├── Asdl.c ├── Asm_Trampoline.S ├── Assemble.c ├── Ast.c ├── Ast_Opt.c ├── Ast_Unparse.c ├── BltinModule.c ├── Bootstrap_Hash.c ├── ByteCodes.c ├── CeVal.c ├── Ceval_Gil.c ├── Ceval_Macros.h ├── Clinic ├── Python-tokenize.c.h ├── _warnings.c.h ├── bltinmodule.c.h ├── context.c.h ├── import.c.h ├── instrumentation.c.h ├── marshal.c.h ├── sysmodule.c.h └── traceback.c.h ├── CodeCS.c ├── Compile.c ├── Condvar.h ├── Context.c ├── Dtoa.c ├── Dup2.c ├── Dynamic_Annotations.c ├── Dynload_Hpux.c ├── Dynload_Shlib.c ├── Dynload_Stub.c ├── Dynload_Win.c ├── Emscripten_Signal.c ├── Errors.c ├── Fileutils.c ├── Flowgraph.c ├── Formatter_Unicode.c ├── Frame.c ├── Frozen.c ├── FrozenMain.c ├── Future.c ├── Game I ├── CMakeLists.txt ├── c_key_event.h ├── c_list.c ├── c_list.h ├── c_rectangle.c ├── c_rectangle.h ├── c_result.h ├── c_vector2.c ├── c_vector2.h ├── c_window.c ├── c_window.h └── main.c ├── Game II ├── CMakeLists.txt ├── colour.cpp ├── colour.h ├── entity.cpp ├── entity.h ├── key_event.h ├── main.cpp ├── rectangle.cpp ├── rectangle.h ├── vector2.cpp ├── vector2.h ├── window.cpp └── window.h ├── Game ├── CMakeLists.txt ├── graphics.asm ├── linked_list.asm ├── main.asm ├── memory.asm └── utils.asm ├── GeTargs.c ├── Generated_Cases.c.h ├── GetArgs.c ├── GetCompiler.c ├── GetCopyRight.c ├── GetCopyright.c ├── GetOpt.c ├── GetPlatForm.c ├── GetVersion.c ├── Get_Compiler.c ├── Get_Opt.c ├── Get_Plat_Form.c ├── Getversion.c ├── Hamt.c ├── HashTable.c ├── ImPort.c ├── ImPortdl.c ├── ImPortdl.h ├── InTrinSics.c ├── InitConfig.c ├── InstruMenTation.c ├── InstruMentation.c ├── Legacy_Tracing.c ├── MakeOpCodeTargets.py ├── MarShal.c ├── ModSupport.c ├── MySnPrintf.c ├── MyStrtoul.c ├── OpCode_MetaData.h ├── OpCode_Targets.h ├── OptiMizer.c ├── PathConfig.c ├── Perf_Trampoline.c ├── PreConfig.c ├── PyArena.c ├── PyCtype.c ├── PyFpc.c ├── PyHash.c ├── PyLifeCycle.c ├── PyMath.c ├── PyState.c ├── PyStrcmp.c ├── PyStrhex.c ├── PyStrtod.c ├── PyTime.c ├── Python-AST.c ├── Python-Tokenize.c ├── PythonRun.c ├── Specialize.c ├── Stdlib_Module_Names.h ├── StrucMember.c ├── Suggestions.c ├── SyMTable.c ├── SySModule.c ├── Thread.c ├── Thread_NT.h ├── Thread_Pthread.h ├── Thread_Pthread_Dtubs.h ├── TraceBack.c └── TraceMalloc.c /Asdl.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "pycore_asdl.h" 3 | 4 | GENERATE_ASDL_SEQ_CONSTRUCTOR(generic, void*); 5 | GENERATE_ASDL_SEQ_CONSTRUCTOR(identifier, PyObject*); 6 | GENERATE_ASDL_SEQ_CONSTRUCTOR(int, int); 7 | -------------------------------------------------------------------------------- /Asm_Trampoline.S: -------------------------------------------------------------------------------- 1 | .text 2 | .globl _Py_trampoline_func_start 3 | # The following assembly is equivalent to: 4 | # PyObject * 5 | # trampoline(PyThreadState *ts, _PyInterpreterFrame *f, 6 | # int throwflag, py_evaluator evaluator) 7 | # { 8 | # return evaluator(ts, f, throwflag); 9 | # } 10 | _Py_trampoline_func_start: 11 | #ifdef __x86_64__ 12 | sub $8, %rsp 13 | call *%rcx 14 | add $8, %rsp 15 | ret 16 | #endif // __x86_64__ 17 | #if defined(__aarch64__) && defined(__AARCH64EL__) && !defined(__ILP32__) 18 | // ARM64 little endian, 64bit ABI 19 | // generate with aarch64-linux-gnu-gcc 12.1 20 | stp x29, x30, [sp, -16]! 21 | mov x29, sp 22 | blr x3 23 | ldp x29, x30, [sp], 16 24 | ret 25 | #endif 26 | .globl _Py_trampoline_func_end 27 | _Py_trampoline_func_end: 28 | .section .note.GNU-stack,"",@progbits 29 | -------------------------------------------------------------------------------- /Clinic/Python-tokenize.c.h: -------------------------------------------------------------------------------- 1 | /*[clinic input] 2 | preserve 3 | [clinic start generated code]*/ 4 | 5 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 6 | # include "pycore_gc.h" // PyGC_Head 7 | # include "pycore_runtime.h" // _Py_ID() 8 | #endif 9 | 10 | 11 | static PyObject * 12 | tokenizeriter_new_impl(PyTypeObject *type, PyObject *readline, 13 | int extra_tokens, const char *encoding); 14 | 15 | static PyObject * 16 | tokenizeriter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 17 | { 18 | PyObject *return_value = NULL; 19 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 20 | 21 | #define NUM_KEYWORDS 2 22 | static struct { 23 | PyGC_Head _this_is_not_used; 24 | PyObject_VAR_HEAD 25 | PyObject *ob_item[NUM_KEYWORDS]; 26 | } _kwtuple = { 27 | .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) 28 | .ob_item = { &_Py_ID(extra_tokens), &_Py_ID(encoding), }, 29 | }; 30 | #undef NUM_KEYWORDS 31 | #define KWTUPLE (&_kwtuple.ob_base.ob_base) 32 | 33 | #else // !Py_BUILD_CORE 34 | # define KWTUPLE NULL 35 | #endif // !Py_BUILD_CORE 36 | 37 | static const char * const _keywords[] = {"", "extra_tokens", "encoding", NULL}; 38 | static _PyArg_Parser _parser = { 39 | .keywords = _keywords, 40 | .fname = "tokenizeriter", 41 | .kwtuple = KWTUPLE, 42 | }; 43 | #undef KWTUPLE 44 | PyObject *argsbuf[3]; 45 | PyObject * const *fastargs; 46 | Py_ssize_t nargs = PyTuple_GET_SIZE(args); 47 | Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 2; 48 | PyObject *readline; 49 | int extra_tokens; 50 | const char *encoding = NULL; 51 | 52 | fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 1, argsbuf); 53 | if (!fastargs) { 54 | goto exit; 55 | } 56 | readline = fastargs[0]; 57 | extra_tokens = PyObject_IsTrue(fastargs[1]); 58 | if (extra_tokens < 0) { 59 | goto exit; 60 | } 61 | if (!noptargs) { 62 | goto skip_optional_kwonly; 63 | } 64 | if (!PyUnicode_Check(fastargs[2])) { 65 | _PyArg_BadArgument("tokenizeriter", "argument 'encoding'", "str", fastargs[2]); 66 | goto exit; 67 | } 68 | Py_ssize_t encoding_length; 69 | encoding = PyUnicode_AsUTF8AndSize(fastargs[2], &encoding_length); 70 | if (encoding == NULL) { 71 | goto exit; 72 | } 73 | if (strlen(encoding) != (size_t)encoding_length) { 74 | PyErr_SetString(PyExc_ValueError, "embedded null character"); 75 | goto exit; 76 | } 77 | skip_optional_kwonly: 78 | return_value = tokenizeriter_new_impl(type, readline, extra_tokens, encoding); 79 | 80 | exit: 81 | return return_value; 82 | } 83 | /*[clinic end generated code: output=48be65a2808bdfa6 input=a9049054013a1b77]*/ 84 | -------------------------------------------------------------------------------- /Clinic/context.c.h: -------------------------------------------------------------------------------- 1 | /*[clinic input] 2 | preserve 3 | [clinic start generated code]*/ 4 | 5 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 6 | # include "pycore_gc.h" // PyGC_Head 7 | # include "pycore_runtime.h" // _Py_ID() 8 | #endif 9 | 10 | 11 | PyDoc_STRVAR(_contextvars_Context_get__doc__, 12 | "get($self, key, default=None, /)\n" 13 | "--\n" 14 | "\n" 15 | "Return the value for `key` if `key` has the value in the context object.\n" 16 | "\n" 17 | "If `key` does not exist, return `default`. If `default` is not given,\n" 18 | "return None."); 19 | 20 | #define _CONTEXTVARS_CONTEXT_GET_METHODDEF \ 21 | {"get", _PyCFunction_CAST(_contextvars_Context_get), METH_FASTCALL, _contextvars_Context_get__doc__}, 22 | 23 | static PyObject * 24 | _contextvars_Context_get_impl(PyContext *self, PyObject *key, 25 | PyObject *default_value); 26 | 27 | static PyObject * 28 | _contextvars_Context_get(PyContext *self, PyObject *const *args, Py_ssize_t nargs) 29 | { 30 | PyObject *return_value = NULL; 31 | PyObject *key; 32 | PyObject *default_value = Py_None; 33 | 34 | if (!_PyArg_CheckPositional("get", nargs, 1, 2)) { 35 | goto exit; 36 | } 37 | key = args[0]; 38 | if (nargs < 2) { 39 | goto skip_optional; 40 | } 41 | default_value = args[1]; 42 | skip_optional: 43 | return_value = _contextvars_Context_get_impl(self, key, default_value); 44 | 45 | exit: 46 | return return_value; 47 | } 48 | 49 | PyDoc_STRVAR(_contextvars_Context_items__doc__, 50 | "items($self, /)\n" 51 | "--\n" 52 | "\n" 53 | "Return all variables and their values in the context object.\n" 54 | "\n" 55 | "The result is returned as a list of 2-tuples (variable, value)."); 56 | 57 | #define _CONTEXTVARS_CONTEXT_ITEMS_METHODDEF \ 58 | {"items", (PyCFunction)_contextvars_Context_items, METH_NOARGS, _contextvars_Context_items__doc__}, 59 | 60 | static PyObject * 61 | _contextvars_Context_items_impl(PyContext *self); 62 | 63 | static PyObject * 64 | _contextvars_Context_items(PyContext *self, PyObject *Py_UNUSED(ignored)) 65 | { 66 | return _contextvars_Context_items_impl(self); 67 | } 68 | 69 | PyDoc_STRVAR(_contextvars_Context_keys__doc__, 70 | "keys($self, /)\n" 71 | "--\n" 72 | "\n" 73 | "Return a list of all variables in the context object."); 74 | 75 | #define _CONTEXTVARS_CONTEXT_KEYS_METHODDEF \ 76 | {"keys", (PyCFunction)_contextvars_Context_keys, METH_NOARGS, _contextvars_Context_keys__doc__}, 77 | 78 | static PyObject * 79 | _contextvars_Context_keys_impl(PyContext *self); 80 | 81 | static PyObject * 82 | _contextvars_Context_keys(PyContext *self, PyObject *Py_UNUSED(ignored)) 83 | { 84 | return _contextvars_Context_keys_impl(self); 85 | } 86 | 87 | PyDoc_STRVAR(_contextvars_Context_values__doc__, 88 | "values($self, /)\n" 89 | "--\n" 90 | "\n" 91 | "Return a list of all variables\' values in the context object."); 92 | 93 | #define _CONTEXTVARS_CONTEXT_VALUES_METHODDEF \ 94 | {"values", (PyCFunction)_contextvars_Context_values, METH_NOARGS, _contextvars_Context_values__doc__}, 95 | 96 | static PyObject * 97 | _contextvars_Context_values_impl(PyContext *self); 98 | 99 | static PyObject * 100 | _contextvars_Context_values(PyContext *self, PyObject *Py_UNUSED(ignored)) 101 | { 102 | return _contextvars_Context_values_impl(self); 103 | } 104 | 105 | PyDoc_STRVAR(_contextvars_Context_copy__doc__, 106 | "copy($self, /)\n" 107 | "--\n" 108 | "\n" 109 | "Return a shallow copy of the context object."); 110 | 111 | #define _CONTEXTVARS_CONTEXT_COPY_METHODDEF \ 112 | {"copy", (PyCFunction)_contextvars_Context_copy, METH_NOARGS, _contextvars_Context_copy__doc__}, 113 | 114 | static PyObject * 115 | _contextvars_Context_copy_impl(PyContext *self); 116 | 117 | static PyObject * 118 | _contextvars_Context_copy(PyContext *self, PyObject *Py_UNUSED(ignored)) 119 | { 120 | return _contextvars_Context_copy_impl(self); 121 | } 122 | 123 | PyDoc_STRVAR(_contextvars_ContextVar_get__doc__, 124 | "get($self, default=, /)\n" 125 | "--\n" 126 | "\n" 127 | "Return a value for the context variable for the current context.\n" 128 | "\n" 129 | "If there is no value for the variable in the current context, the method will:\n" 130 | " * return the value of the default argument of the method, if provided; or\n" 131 | " * return the default value for the context variable, if it was created\n" 132 | " with one; or\n" 133 | " * raise a LookupError."); 134 | 135 | #define _CONTEXTVARS_CONTEXTVAR_GET_METHODDEF \ 136 | {"get", _PyCFunction_CAST(_contextvars_ContextVar_get), METH_FASTCALL, _contextvars_ContextVar_get__doc__}, 137 | 138 | static PyObject * 139 | _contextvars_ContextVar_get_impl(PyContextVar *self, PyObject *default_value); 140 | 141 | static PyObject * 142 | _contextvars_ContextVar_get(PyContextVar *self, PyObject *const *args, Py_ssize_t nargs) 143 | { 144 | PyObject *return_value = NULL; 145 | PyObject *default_value = NULL; 146 | 147 | if (!_PyArg_CheckPositional("get", nargs, 0, 1)) { 148 | goto exit; 149 | } 150 | if (nargs < 1) { 151 | goto skip_optional; 152 | } 153 | default_value = args[0]; 154 | skip_optional: 155 | return_value = _contextvars_ContextVar_get_impl(self, default_value); 156 | 157 | exit: 158 | return return_value; 159 | } 160 | 161 | PyDoc_STRVAR(_contextvars_ContextVar_set__doc__, 162 | "set($self, value, /)\n" 163 | "--\n" 164 | "\n" 165 | "Call to set a new value for the context variable in the current context.\n" 166 | "\n" 167 | "The required value argument is the new value for the context variable.\n" 168 | "\n" 169 | "Returns a Token object that can be used to restore the variable to its previous\n" 170 | "value via the `ContextVar.reset()` method."); 171 | 172 | #define _CONTEXTVARS_CONTEXTVAR_SET_METHODDEF \ 173 | {"set", (PyCFunction)_contextvars_ContextVar_set, METH_O, _contextvars_ContextVar_set__doc__}, 174 | 175 | PyDoc_STRVAR(_contextvars_ContextVar_reset__doc__, 176 | "reset($self, token, /)\n" 177 | "--\n" 178 | "\n" 179 | "Reset the context variable.\n" 180 | "\n" 181 | "The variable is reset to the value it had before the `ContextVar.set()` that\n" 182 | "created the token was used."); 183 | 184 | #define _CONTEXTVARS_CONTEXTVAR_RESET_METHODDEF \ 185 | {"reset", (PyCFunction)_contextvars_ContextVar_reset, METH_O, _contextvars_ContextVar_reset__doc__}, 186 | /*[clinic end generated code: output=0c94d4b919500438 input=a9049054013a1b77]*/ 187 | -------------------------------------------------------------------------------- /Clinic/marshal.c.h: -------------------------------------------------------------------------------- 1 | /*[clinic input] 2 | preserve 3 | [clinic start generated code]*/ 4 | 5 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 6 | # include "pycore_gc.h" // PyGC_Head 7 | # include "pycore_runtime.h" // _Py_ID() 8 | #endif 9 | 10 | 11 | PyDoc_STRVAR(marshal_dump__doc__, 12 | "dump($module, value, file, version=version, /)\n" 13 | "--\n" 14 | "\n" 15 | "Write the value on the open file.\n" 16 | "\n" 17 | " value\n" 18 | " Must be a supported type.\n" 19 | " file\n" 20 | " Must be a writeable binary file.\n" 21 | " version\n" 22 | " Indicates the data format that dump should use.\n" 23 | "\n" 24 | "If the value has (or contains an object that has) an unsupported type, a\n" 25 | "ValueError exception is raised - but garbage data will also be written\n" 26 | "to the file. The object will not be properly read back by load()."); 27 | 28 | #define MARSHAL_DUMP_METHODDEF \ 29 | {"dump", _PyCFunction_CAST(marshal_dump), METH_FASTCALL, marshal_dump__doc__}, 30 | 31 | static PyObject * 32 | marshal_dump_impl(PyObject *module, PyObject *value, PyObject *file, 33 | int version); 34 | 35 | static PyObject * 36 | marshal_dump(PyObject *module, PyObject *const *args, Py_ssize_t nargs) 37 | { 38 | PyObject *return_value = NULL; 39 | PyObject *value; 40 | PyObject *file; 41 | int version = Py_MARSHAL_VERSION; 42 | 43 | if (!_PyArg_CheckPositional("dump", nargs, 2, 3)) { 44 | goto exit; 45 | } 46 | value = args[0]; 47 | file = args[1]; 48 | if (nargs < 3) { 49 | goto skip_optional; 50 | } 51 | version = _PyLong_AsInt(args[2]); 52 | if (version == -1 && PyErr_Occurred()) { 53 | goto exit; 54 | } 55 | skip_optional: 56 | return_value = marshal_dump_impl(module, value, file, version); 57 | 58 | exit: 59 | return return_value; 60 | } 61 | 62 | PyDoc_STRVAR(marshal_load__doc__, 63 | "load($module, file, /)\n" 64 | "--\n" 65 | "\n" 66 | "Read one value from the open file and return it.\n" 67 | "\n" 68 | " file\n" 69 | " Must be readable binary file.\n" 70 | "\n" 71 | "If no valid value is read (e.g. because the data has a different Python\n" 72 | "version\'s incompatible marshal format), raise EOFError, ValueError or\n" 73 | "TypeError.\n" 74 | "\n" 75 | "Note: If an object containing an unsupported type was marshalled with\n" 76 | "dump(), load() will substitute None for the unmarshallable type."); 77 | 78 | #define MARSHAL_LOAD_METHODDEF \ 79 | {"load", (PyCFunction)marshal_load, METH_O, marshal_load__doc__}, 80 | 81 | PyDoc_STRVAR(marshal_dumps__doc__, 82 | "dumps($module, value, version=version, /)\n" 83 | "--\n" 84 | "\n" 85 | "Return the bytes object that would be written to a file by dump(value, file).\n" 86 | "\n" 87 | " value\n" 88 | " Must be a supported type.\n" 89 | " version\n" 90 | " Indicates the data format that dumps should use.\n" 91 | "\n" 92 | "Raise a ValueError exception if value has (or contains an object that has) an\n" 93 | "unsupported type."); 94 | 95 | #define MARSHAL_DUMPS_METHODDEF \ 96 | {"dumps", _PyCFunction_CAST(marshal_dumps), METH_FASTCALL, marshal_dumps__doc__}, 97 | 98 | static PyObject * 99 | marshal_dumps_impl(PyObject *module, PyObject *value, int version); 100 | 101 | static PyObject * 102 | marshal_dumps(PyObject *module, PyObject *const *args, Py_ssize_t nargs) 103 | { 104 | PyObject *return_value = NULL; 105 | PyObject *value; 106 | int version = Py_MARSHAL_VERSION; 107 | 108 | if (!_PyArg_CheckPositional("dumps", nargs, 1, 2)) { 109 | goto exit; 110 | } 111 | value = args[0]; 112 | if (nargs < 2) { 113 | goto skip_optional; 114 | } 115 | version = _PyLong_AsInt(args[1]); 116 | if (version == -1 && PyErr_Occurred()) { 117 | goto exit; 118 | } 119 | skip_optional: 120 | return_value = marshal_dumps_impl(module, value, version); 121 | 122 | exit: 123 | return return_value; 124 | } 125 | 126 | PyDoc_STRVAR(marshal_loads__doc__, 127 | "loads($module, bytes, /)\n" 128 | "--\n" 129 | "\n" 130 | "Convert the bytes-like object to a value.\n" 131 | "\n" 132 | "If no valid value is found, raise EOFError, ValueError or TypeError. Extra\n" 133 | "bytes in the input are ignored."); 134 | 135 | #define MARSHAL_LOADS_METHODDEF \ 136 | {"loads", (PyCFunction)marshal_loads, METH_O, marshal_loads__doc__}, 137 | 138 | static PyObject * 139 | marshal_loads_impl(PyObject *module, Py_buffer *bytes); 140 | 141 | static PyObject * 142 | marshal_loads(PyObject *module, PyObject *arg) 143 | { 144 | PyObject *return_value = NULL; 145 | Py_buffer bytes = {NULL, NULL}; 146 | 147 | if (PyObject_GetBuffer(arg, &bytes, PyBUF_SIMPLE) != 0) { 148 | goto exit; 149 | } 150 | if (!PyBuffer_IsContiguous(&bytes, 'C')) { 151 | _PyArg_BadArgument("loads", "argument", "contiguous buffer", arg); 152 | goto exit; 153 | } 154 | return_value = marshal_loads_impl(module, &bytes); 155 | 156 | exit: 157 | /* Cleanup for bytes */ 158 | if (bytes.obj) { 159 | PyBuffer_Release(&bytes); 160 | } 161 | 162 | return return_value; 163 | } 164 | /*[clinic end generated code: output=12082d61d2942473 input=a9049054013a1b77]*/ 165 | -------------------------------------------------------------------------------- /Clinic/traceback.c.h: -------------------------------------------------------------------------------- 1 | /*[clinic input] 2 | preserve 3 | [clinic start generated code]*/ 4 | 5 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 6 | # include "pycore_gc.h" // PyGC_Head 7 | # include "pycore_runtime.h" // _Py_ID() 8 | #endif 9 | 10 | 11 | PyDoc_STRVAR(tb_new__doc__, 12 | "TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)\n" 13 | "--\n" 14 | "\n" 15 | "Create a new traceback object."); 16 | 17 | static PyObject * 18 | tb_new_impl(PyTypeObject *type, PyObject *tb_next, PyFrameObject *tb_frame, 19 | int tb_lasti, int tb_lineno); 20 | 21 | static PyObject * 22 | tb_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 23 | { 24 | PyObject *return_value = NULL; 25 | #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) 26 | 27 | #define NUM_KEYWORDS 4 28 | static struct { 29 | PyGC_Head _this_is_not_used; 30 | PyObject_VAR_HEAD 31 | PyObject *ob_item[NUM_KEYWORDS]; 32 | } _kwtuple = { 33 | .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) 34 | .ob_item = { &_Py_ID(tb_next), &_Py_ID(tb_frame), &_Py_ID(tb_lasti), &_Py_ID(tb_lineno), }, 35 | }; 36 | #undef NUM_KEYWORDS 37 | #define KWTUPLE (&_kwtuple.ob_base.ob_base) 38 | 39 | #else // !Py_BUILD_CORE 40 | # define KWTUPLE NULL 41 | #endif // !Py_BUILD_CORE 42 | 43 | static const char * const _keywords[] = {"tb_next", "tb_frame", "tb_lasti", "tb_lineno", NULL}; 44 | static _PyArg_Parser _parser = { 45 | .keywords = _keywords, 46 | .fname = "TracebackType", 47 | .kwtuple = KWTUPLE, 48 | }; 49 | #undef KWTUPLE 50 | PyObject *argsbuf[4]; 51 | PyObject * const *fastargs; 52 | Py_ssize_t nargs = PyTuple_GET_SIZE(args); 53 | PyObject *tb_next; 54 | PyFrameObject *tb_frame; 55 | int tb_lasti; 56 | int tb_lineno; 57 | 58 | fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 4, 4, 0, argsbuf); 59 | if (!fastargs) { 60 | goto exit; 61 | } 62 | tb_next = fastargs[0]; 63 | if (!PyObject_TypeCheck(fastargs[1], &PyFrame_Type)) { 64 | _PyArg_BadArgument("TracebackType", "argument 'tb_frame'", (&PyFrame_Type)->tp_name, fastargs[1]); 65 | goto exit; 66 | } 67 | tb_frame = (PyFrameObject *)fastargs[1]; 68 | tb_lasti = _PyLong_AsInt(fastargs[2]); 69 | if (tb_lasti == -1 && PyErr_Occurred()) { 70 | goto exit; 71 | } 72 | tb_lineno = _PyLong_AsInt(fastargs[3]); 73 | if (tb_lineno == -1 && PyErr_Occurred()) { 74 | goto exit; 75 | } 76 | return_value = tb_new_impl(type, tb_next, tb_frame, tb_lasti, tb_lineno); 77 | 78 | exit: 79 | return return_value; 80 | } 81 | /*[clinic end generated code: output=7bc9927e362fdfb7 input=a9049054013a1b77]*/ 82 | -------------------------------------------------------------------------------- /Condvar.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _CONDVAR_IMPL_H_ 4 | #define _CONDVAR_IMPL_H_ 5 | 6 | #include "Python.h" 7 | #include "pycore_condvar.h" 8 | 9 | #ifdef _POSIX_THREADS 10 | /* 11 | * POSIX support 12 | */ 13 | 14 | /* These private functions are implemented in Python/thread_pthread.h */ 15 | int _PyThread_cond_init(PyCOND_T *cond); 16 | void _PyThread_cond_after(long long us, struct timespec *abs); 17 | 18 | /* The following functions return 0 on success, nonzero on error */ 19 | #define PyMUTEX_INIT(mut) pthread_mutex_init((mut), NULL) 20 | #define PyMUTEX_FINI(mut) pthread_mutex_destroy(mut) 21 | #define PyMUTEX_LOCK(mut) pthread_mutex_lock(mut) 22 | #define PyMUTEX_UNLOCK(mut) pthread_mutex_unlock(mut) 23 | 24 | #define PyCOND_INIT(cond) _PyThread_cond_init(cond) 25 | #define PyCOND_FINI(cond) pthread_cond_destroy(cond) 26 | #define PyCOND_SIGNAL(cond) pthread_cond_signal(cond) 27 | #define PyCOND_BROADCAST(cond) pthread_cond_broadcast(cond) 28 | #define PyCOND_WAIT(cond, mut) pthread_cond_wait((cond), (mut)) 29 | 30 | /* return 0 for success, 1 on timeout, -1 on error */ 31 | Py_LOCAL_INLINE(int) 32 | PyCOND_TIMEDWAIT(PyCOND_T *cond, PyMUTEX_T *mut, long long us) 33 | { 34 | struct timespec abs_timeout; 35 | _PyThread_cond_after(us, &abs_timeout); 36 | int ret = pthread_cond_timedwait(cond, mut, &abs_timeout); 37 | if (ret == ETIMEDOUT) { 38 | return 1; 39 | } 40 | if (ret) { 41 | return -1; 42 | } 43 | return 0; 44 | } 45 | 46 | #elif defined(NT_THREADS) 47 | /* 48 | * Windows (XP, 2003 server and later, as well as (hopefully) CE) support 49 | * 50 | * Emulated condition variables ones that work with XP and later, plus 51 | * example native support on VISTA and onwards. 52 | */ 53 | 54 | #if _PY_EMULATED_WIN_CV 55 | 56 | /* The mutex is a CriticalSection object and 57 | The condition variables is emulated with the help of a semaphore. 58 | 59 | This implementation still has the problem that the threads woken 60 | with a "signal" aren't necessarily those that are already 61 | waiting. It corresponds to listing 2 in: 62 | http://birrell.org/andrew/papers/ImplementingCVs.pdf 63 | 64 | Generic emulations of the pthread_cond_* API using 65 | earlier Win32 functions can be found on the web. 66 | The following read can be give background information to these issues, 67 | but the implementations are all broken in some way. 68 | http://www.cse.wustl.edu/~schmidt/win32-cv-1.html 69 | */ 70 | 71 | Py_LOCAL_INLINE(int) 72 | PyMUTEX_INIT(PyMUTEX_T *cs) 73 | { 74 | InitializeCriticalSection(cs); 75 | return 0; 76 | } 77 | 78 | Py_LOCAL_INLINE(int) 79 | PyMUTEX_FINI(PyMUTEX_T *cs) 80 | { 81 | DeleteCriticalSection(cs); 82 | return 0; 83 | } 84 | 85 | Py_LOCAL_INLINE(int) 86 | PyMUTEX_LOCK(PyMUTEX_T *cs) 87 | { 88 | EnterCriticalSection(cs); 89 | return 0; 90 | } 91 | 92 | Py_LOCAL_INLINE(int) 93 | PyMUTEX_UNLOCK(PyMUTEX_T *cs) 94 | { 95 | LeaveCriticalSection(cs); 96 | return 0; 97 | } 98 | 99 | 100 | Py_LOCAL_INLINE(int) 101 | PyCOND_INIT(PyCOND_T *cv) 102 | { 103 | /* A semaphore with a "large" max value, The positive value 104 | * is only needed to catch those "lost wakeup" events and 105 | * race conditions when a timed wait elapses. 106 | */ 107 | cv->sem = CreateSemaphore(NULL, 0, 100000, NULL); 108 | if (cv->sem==NULL) 109 | return -1; 110 | cv->waiting = 0; 111 | return 0; 112 | } 113 | 114 | Py_LOCAL_INLINE(int) 115 | PyCOND_FINI(PyCOND_T *cv) 116 | { 117 | return CloseHandle(cv->sem) ? 0 : -1; 118 | } 119 | 120 | /* this implementation can detect a timeout. Returns 1 on timeout, 121 | * 0 otherwise (and -1 on error) 122 | */ 123 | Py_LOCAL_INLINE(int) 124 | _PyCOND_WAIT_MS(PyCOND_T *cv, PyMUTEX_T *cs, DWORD ms) 125 | { 126 | DWORD wait; 127 | cv->waiting++; 128 | PyMUTEX_UNLOCK(cs); 129 | /* "lost wakeup bug" would occur if the caller were interrupted here, 130 | * but we are safe because we are using a semaphore which has an internal 131 | * count. 132 | */ 133 | wait = WaitForSingleObjectEx(cv->sem, ms, FALSE); 134 | PyMUTEX_LOCK(cs); 135 | if (wait != WAIT_OBJECT_0) 136 | --cv->waiting; 137 | /* Here we have a benign race condition with PyCOND_SIGNAL. 138 | * When failure occurs or timeout, it is possible that 139 | * PyCOND_SIGNAL also decrements this value 140 | * and signals releases the mutex. This is benign because it 141 | * just means an extra spurious wakeup for a waiting thread. 142 | * ('waiting' corresponds to the semaphore's "negative" count and 143 | * we may end up with e.g. (waiting == -1 && sem.count == 1). When 144 | * a new thread comes along, it will pass right through, having 145 | * adjusted it to (waiting == 0 && sem.count == 0). 146 | */ 147 | 148 | if (wait == WAIT_FAILED) 149 | return -1; 150 | /* return 0 on success, 1 on timeout */ 151 | return wait != WAIT_OBJECT_0; 152 | } 153 | 154 | Py_LOCAL_INLINE(int) 155 | PyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) 156 | { 157 | int result = _PyCOND_WAIT_MS(cv, cs, INFINITE); 158 | return result >= 0 ? 0 : result; 159 | } 160 | 161 | Py_LOCAL_INLINE(int) 162 | PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) 163 | { 164 | return _PyCOND_WAIT_MS(cv, cs, (DWORD)(us/1000)); 165 | } 166 | 167 | Py_LOCAL_INLINE(int) 168 | PyCOND_SIGNAL(PyCOND_T *cv) 169 | { 170 | /* this test allows PyCOND_SIGNAL to be a no-op unless required 171 | * to wake someone up, thus preventing an unbounded increase of 172 | * the semaphore's internal counter. 173 | */ 174 | if (cv->waiting > 0) { 175 | /* notifying thread decreases the cv->waiting count so that 176 | * a delay between notify and actual wakeup of the target thread 177 | * doesn't cause a number of extra ReleaseSemaphore calls. 178 | */ 179 | cv->waiting--; 180 | return ReleaseSemaphore(cv->sem, 1, NULL) ? 0 : -1; 181 | } 182 | return 0; 183 | } 184 | 185 | Py_LOCAL_INLINE(int) 186 | PyCOND_BROADCAST(PyCOND_T *cv) 187 | { 188 | int waiting = cv->waiting; 189 | if (waiting > 0) { 190 | cv->waiting = 0; 191 | return ReleaseSemaphore(cv->sem, waiting, NULL) ? 0 : -1; 192 | } 193 | return 0; 194 | } 195 | 196 | #else /* !_PY_EMULATED_WIN_CV */ 197 | 198 | Py_LOCAL_INLINE(int) 199 | PyMUTEX_INIT(PyMUTEX_T *cs) 200 | { 201 | InitializeSRWLock(cs); 202 | return 0; 203 | } 204 | 205 | Py_LOCAL_INLINE(int) 206 | PyMUTEX_FINI(PyMUTEX_T *cs) 207 | { 208 | return 0; 209 | } 210 | 211 | Py_LOCAL_INLINE(int) 212 | PyMUTEX_LOCK(PyMUTEX_T *cs) 213 | { 214 | AcquireSRWLockExclusive(cs); 215 | return 0; 216 | } 217 | 218 | Py_LOCAL_INLINE(int) 219 | PyMUTEX_UNLOCK(PyMUTEX_T *cs) 220 | { 221 | ReleaseSRWLockExclusive(cs); 222 | return 0; 223 | } 224 | 225 | 226 | Py_LOCAL_INLINE(int) 227 | PyCOND_INIT(PyCOND_T *cv) 228 | { 229 | InitializeConditionVariable(cv); 230 | return 0; 231 | } 232 | Py_LOCAL_INLINE(int) 233 | PyCOND_FINI(PyCOND_T *cv) 234 | { 235 | return 0; 236 | } 237 | 238 | Py_LOCAL_INLINE(int) 239 | PyCOND_WAIT(PyCOND_T *cv, PyMUTEX_T *cs) 240 | { 241 | return SleepConditionVariableSRW(cv, cs, INFINITE, 0) ? 0 : -1; 242 | } 243 | 244 | /* This implementation makes no distinction about timeouts. Signal 245 | * 2 to indicate that we don't know. 246 | */ 247 | Py_LOCAL_INLINE(int) 248 | PyCOND_TIMEDWAIT(PyCOND_T *cv, PyMUTEX_T *cs, long long us) 249 | { 250 | return SleepConditionVariableSRW(cv, cs, (DWORD)(us/1000), 0) ? 2 : -1; 251 | } 252 | 253 | Py_LOCAL_INLINE(int) 254 | PyCOND_SIGNAL(PyCOND_T *cv) 255 | { 256 | WakeConditionVariable(cv); 257 | return 0; 258 | } 259 | 260 | Py_LOCAL_INLINE(int) 261 | PyCOND_BROADCAST(PyCOND_T *cv) 262 | { 263 | WakeAllConditionVariable(cv); 264 | return 0; 265 | } 266 | 267 | 268 | #endif /* _PY_EMULATED_WIN_CV */ 269 | 270 | #endif /* _POSIX_THREADS, NT_THREADS */ 271 | 272 | #endif /* _CONDVAR_IMPL_H_ */ 273 | -------------------------------------------------------------------------------- /Dup2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define BADEXIT -1 6 | 7 | int 8 | dup2(int fd1, int fd2) 9 | { 10 | if (fd1 != fd2) { 11 | #ifdef F_DUPFD 12 | if (fcntl(fd1, F_GETFL) < 0) 13 | return BADEXIT; 14 | if (fcntl(fd2, F_GETFL) >= 0) 15 | close(fd2); 16 | if (fcntl(fd1, F_DUPFD, fd2) < 0) 17 | return BADEXIT; 18 | #else 19 | errno = ENOTSUP; 20 | return BADEXIT; 21 | #endif 22 | } 23 | return fd2; 24 | } 25 | -------------------------------------------------------------------------------- /Dynamic_Annotations.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifdef _MSC_VER 4 | # include 5 | #endif 6 | 7 | #ifdef __cplusplus 8 | # error "This file should be built as pure C to avoid name mangling" 9 | #endif 10 | 11 | #include 12 | #include 13 | 14 | #include "dynamic_annotations.h" 15 | 16 | /* Each function is empty and called (via a macro) only in debug mode. 17 | The arguments are captured by dynamic tools at runtime. */ 18 | 19 | #if DYNAMIC_ANNOTATIONS_ENABLED == 1 20 | 21 | void AnnotateRWLockCreate(const char *file, int line, 22 | const volatile void *lock){} 23 | void AnnotateRWLockDestroy(const char *file, int line, 24 | const volatile void *lock){} 25 | void AnnotateRWLockAcquired(const char *file, int line, 26 | const volatile void *lock, long is_w){} 27 | void AnnotateRWLockReleased(const char *file, int line, 28 | const volatile void *lock, long is_w){} 29 | void AnnotateBarrierInit(const char *file, int line, 30 | const volatile void *barrier, long count, 31 | long reinitialization_allowed) {} 32 | void AnnotateBarrierWaitBefore(const char *file, int line, 33 | const volatile void *barrier) {} 34 | void AnnotateBarrierWaitAfter(const char *file, int line, 35 | const volatile void *barrier) {} 36 | void AnnotateBarrierDestroy(const char *file, int line, 37 | const volatile void *barrier) {} 38 | 39 | void AnnotateCondVarWait(const char *file, int line, 40 | const volatile void *cv, 41 | const volatile void *lock){} 42 | void AnnotateCondVarSignal(const char *file, int line, 43 | const volatile void *cv){} 44 | void AnnotateCondVarSignalAll(const char *file, int line, 45 | const volatile void *cv){} 46 | void AnnotatePublishMemoryRange(const char *file, int line, 47 | const volatile void *address, 48 | long size){} 49 | void AnnotateUnpublishMemoryRange(const char *file, int line, 50 | const volatile void *address, 51 | long size){} 52 | void AnnotatePCQCreate(const char *file, int line, 53 | const volatile void *pcq){} 54 | void AnnotatePCQDestroy(const char *file, int line, 55 | const volatile void *pcq){} 56 | void AnnotatePCQPut(const char *file, int line, 57 | const volatile void *pcq){} 58 | void AnnotatePCQGet(const char *file, int line, 59 | const volatile void *pcq){} 60 | void AnnotateNewMemory(const char *file, int line, 61 | const volatile void *mem, 62 | long size){} 63 | void AnnotateExpectRace(const char *file, int line, 64 | const volatile void *mem, 65 | const char *description){} 66 | void AnnotateBenignRace(const char *file, int line, 67 | const volatile void *mem, 68 | const char *description){} 69 | void AnnotateBenignRaceSized(const char *file, int line, 70 | const volatile void *mem, 71 | long size, 72 | const char *description) {} 73 | void AnnotateMutexIsUsedAsCondVar(const char *file, int line, 74 | const volatile void *mu){} 75 | void AnnotateTraceMemory(const char *file, int line, 76 | const volatile void *arg){} 77 | void AnnotateThreadName(const char *file, int line, 78 | const char *name){} 79 | void AnnotateIgnoreReadsBegin(const char *file, int line){} 80 | void AnnotateIgnoreReadsEnd(const char *file, int line){} 81 | void AnnotateIgnoreWritesBegin(const char *file, int line){} 82 | void AnnotateIgnoreWritesEnd(const char *file, int line){} 83 | void AnnotateIgnoreSyncBegin(const char *file, int line){} 84 | void AnnotateIgnoreSyncEnd(const char *file, int line){} 85 | void AnnotateEnableRaceDetection(const char *file, int line, int enable){} 86 | void AnnotateNoOp(const char *file, int line, 87 | const volatile void *arg){} 88 | void AnnotateFlushState(const char *file, int line){} 89 | 90 | static int GetRunningOnValgrind(void) { 91 | #ifdef RUNNING_ON_VALGRIND 92 | if (RUNNING_ON_VALGRIND) return 1; 93 | #endif 94 | 95 | #ifndef _MSC_VER 96 | const char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); 97 | if (running_on_valgrind_str) { 98 | return strcmp(running_on_valgrind_str, "0") != 0; 99 | } 100 | #else 101 | /* Visual Studio issues warnings if we use getenv, 102 | * so we use GetEnvironmentVariableA instead. 103 | */ 104 | char value[100] = "1"; 105 | int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND", 106 | value, sizeof(value)); 107 | /* value will remain "1" if res == 0 or res >= sizeof(value). The latter 108 | * can happen only if the given value is long, in this case it can't be "0". 109 | */ 110 | if (res > 0 && !strcmp(value, "0")) 111 | return 1; 112 | #endif 113 | return 0; 114 | } 115 | 116 | /* See the comments in dynamic_annotations.h */ 117 | int RunningOnValgrind(void) { 118 | static volatile int running_on_valgrind = -1; 119 | /* C doesn't have thread-safe initialization of statics, and we 120 | don't want to depend on pthread_once here, so hack it. */ 121 | int local_running_on_valgrind = running_on_valgrind; 122 | if (local_running_on_valgrind == -1) 123 | running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind(); 124 | return local_running_on_valgrind; 125 | } 126 | 127 | #endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */ 128 | -------------------------------------------------------------------------------- /Dynload_Hpux.c: -------------------------------------------------------------------------------- 1 | 2 | /* Support for dynamic loading of extension modules */ 3 | 4 | #include "dl.h" 5 | #include 6 | 7 | #include "Python.h" 8 | #include "importdl.h" 9 | 10 | #if defined(__hp9000s300) 11 | #define FUNCNAME_PATTERN "_%.20s_%.200s" 12 | #else 13 | #define FUNCNAME_PATTERN "%.20s_%.200s" 14 | #endif 15 | 16 | const char *_PyImport_DynLoadFiletab[] = {SHLIB_EXT, ".sl", NULL}; 17 | 18 | dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, 19 | const char *shortname, 20 | const char *pathname, FILE *fp) 21 | { 22 | int flags = BIND_FIRST | BIND_DEFERRED; 23 | int verbose = _Py_GetConfig()->verbose; 24 | if (verbose) { 25 | flags = BIND_FIRST | BIND_IMMEDIATE | 26 | BIND_NONFATAL | BIND_VERBOSE; 27 | printf("shl_load %s\n",pathname); 28 | } 29 | 30 | shl_t lib = shl_load(pathname, flags, 0); 31 | /* XXX Chuck Blake once wrote that 0 should be BIND_NOSTART? */ 32 | if (lib == NULL) { 33 | if (verbose) { 34 | perror(pathname); 35 | } 36 | char buf[256]; 37 | PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s", 38 | pathname); 39 | PyObject *buf_ob = PyUnicode_DecodeFSDefault(buf); 40 | if (buf_ob == NULL) 41 | return NULL; 42 | PyObject *shortname_ob = PyUnicode_FromString(shortname); 43 | if (shortname_ob == NULL) { 44 | Py_DECREF(buf_ob); 45 | return NULL; 46 | } 47 | PyObject *pathname_ob = PyUnicode_DecodeFSDefault(pathname); 48 | if (pathname_ob == NULL) { 49 | Py_DECREF(buf_ob); 50 | Py_DECREF(shortname_ob); 51 | return NULL; 52 | } 53 | PyErr_SetImportError(buf_ob, shortname_ob, pathname_ob); 54 | Py_DECREF(buf_ob); 55 | Py_DECREF(shortname_ob); 56 | Py_DECREF(pathname_ob); 57 | return NULL; 58 | } 59 | 60 | char funcname[258]; 61 | PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN, 62 | prefix, shortname); 63 | if (verbose) { 64 | printf("shl_findsym %s\n", funcname); 65 | } 66 | 67 | dl_funcptr p; 68 | if (shl_findsym(&lib, funcname, TYPE_UNDEFINED, (void *) &p) == -1) { 69 | shl_unload(lib); 70 | p = NULL; 71 | } 72 | if (p == NULL && verbose) { 73 | perror(funcname); 74 | } 75 | return p; 76 | } 77 | -------------------------------------------------------------------------------- /Dynload_Shlib.c: -------------------------------------------------------------------------------- 1 | 2 | /* Support for dynamic loading of extension modules */ 3 | 4 | #include "Python.h" 5 | #include "pycore_interp.h" // _PyInterpreterState.dlopenflags 6 | #include "pycore_pystate.h" // _PyInterpreterState_GET() 7 | #include "importdl.h" 8 | 9 | #include 10 | #include 11 | 12 | #if defined(__NetBSD__) 13 | #include 14 | #if (NetBSD < 199712) 15 | #include 16 | #include 17 | #define dlerror() "error in dynamic linking" 18 | #endif 19 | #endif /* NetBSD */ 20 | 21 | #ifdef HAVE_DLFCN_H 22 | #include 23 | #endif 24 | 25 | #if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__) 26 | #define LEAD_UNDERSCORE "_" 27 | #else 28 | #define LEAD_UNDERSCORE "" 29 | #endif 30 | 31 | /* The .so extension module ABI tag, supplied by the Makefile via 32 | Makefile.pre.in and configure. This is used to discriminate between 33 | incompatible .so files so that extensions for different Python builds can 34 | live in the same directory. E.g. foomodule.cpython-32.so 35 | */ 36 | 37 | const char *_PyImport_DynLoadFiletab[] = { 38 | #ifdef __CYGWIN__ 39 | ".dll", 40 | #else /* !__CYGWIN__ */ 41 | "." SOABI ".so", 42 | #ifdef ALT_SOABI 43 | "." ALT_SOABI ".so", 44 | #endif 45 | ".abi" PYTHON_ABI_STRING ".so", 46 | ".so", 47 | #endif /* __CYGWIN__ */ 48 | NULL, 49 | }; 50 | 51 | 52 | dl_funcptr 53 | _PyImport_FindSharedFuncptr(const char *prefix, 54 | const char *shortname, 55 | const char *pathname, FILE *fp) 56 | { 57 | dl_funcptr p; 58 | void *handle; 59 | char funcname[258]; 60 | char pathbuf[260]; 61 | int dlopenflags=0; 62 | 63 | if (strchr(pathname, '/') == NULL) { 64 | /* Prefix bare filename with "./" */ 65 | PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname); 66 | pathname = pathbuf; 67 | } 68 | 69 | PyOS_snprintf(funcname, sizeof(funcname), 70 | LEAD_UNDERSCORE "%.20s_%.200s", prefix, shortname); 71 | 72 | if (fp != NULL) { 73 | struct _Py_stat_struct status; 74 | if (_Py_fstat(fileno(fp), &status) == -1) 75 | return NULL; 76 | } 77 | 78 | dlopenflags = _PyImport_GetDLOpenFlags(_PyInterpreterState_GET()); 79 | 80 | handle = dlopen(pathname, dlopenflags); 81 | 82 | if (handle == NULL) { 83 | PyObject *mod_name; 84 | PyObject *path; 85 | PyObject *error_ob; 86 | const char *error = dlerror(); 87 | if (error == NULL) 88 | error = "unknown dlopen() error"; 89 | error_ob = PyUnicode_DecodeLocale(error, "surrogateescape"); 90 | if (error_ob == NULL) 91 | return NULL; 92 | mod_name = PyUnicode_FromString(shortname); 93 | if (mod_name == NULL) { 94 | Py_DECREF(error_ob); 95 | return NULL; 96 | } 97 | path = PyUnicode_DecodeFSDefault(pathname); 98 | if (path == NULL) { 99 | Py_DECREF(error_ob); 100 | Py_DECREF(mod_name); 101 | return NULL; 102 | } 103 | PyErr_SetImportError(error_ob, mod_name, path); 104 | Py_DECREF(error_ob); 105 | Py_DECREF(mod_name); 106 | Py_DECREF(path); 107 | return NULL; 108 | } 109 | p = (dl_funcptr) dlsym(handle, funcname); 110 | return p; 111 | } 112 | -------------------------------------------------------------------------------- /Dynload_Stub.c: -------------------------------------------------------------------------------- 1 | 2 | /* This module provides the necessary stubs for when dynamic loading is 3 | not present. */ 4 | 5 | #include "Python.h" 6 | #include "importdl.h" 7 | 8 | 9 | const char *_PyImport_DynLoadFiletab[] = {NULL}; 10 | -------------------------------------------------------------------------------- /Emscripten_Signal.c: -------------------------------------------------------------------------------- 1 | // To enable signal handling, the embedder should: 2 | // 1. set Module.Py_EmscriptenSignalBuffer = some_shared_array_buffer; 3 | // 2. set the Py_EMSCRIPTEN_SIGNAL_HANDLING flag to 1 as follows: 4 | // Module.HEAP8[Module._Py_EMSCRIPTEN_SIGNAL_HANDLING] = 1 5 | // 6 | // The address &Py_EMSCRIPTEN_SIGNAL_HANDLING is exported as 7 | // Module._Py_EMSCRIPTEN_SIGNAL_HANDLING. 8 | #include 9 | #include "Python.h" 10 | 11 | EM_JS(int, _Py_CheckEmscriptenSignals_Helper, (void), { 12 | if (!Module.Py_EmscriptenSignalBuffer) { 13 | return 0; 14 | } 15 | try { 16 | let result = Module.Py_EmscriptenSignalBuffer[0]; 17 | Module.Py_EmscriptenSignalBuffer[0] = 0; 18 | return result; 19 | } catch(e) { 20 | #if !defined(NDEBUG) 21 | console.warn("Error occurred while trying to read signal buffer:", e); 22 | #endif 23 | return 0; 24 | } 25 | }); 26 | 27 | EMSCRIPTEN_KEEPALIVE int Py_EMSCRIPTEN_SIGNAL_HANDLING = 0; 28 | 29 | void 30 | _Py_CheckEmscriptenSignals(void) 31 | { 32 | if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) { 33 | return; 34 | } 35 | int signal = _Py_CheckEmscriptenSignals_Helper(); 36 | if (signal) { 37 | PyErr_SetInterruptEx(signal); 38 | } 39 | } 40 | 41 | 42 | #define PY_EMSCRIPTEN_SIGNAL_INTERVAL 50 43 | static int emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL; 44 | 45 | void 46 | _Py_CheckEmscriptenSignalsPeriodically(void) 47 | { 48 | if (!Py_EMSCRIPTEN_SIGNAL_HANDLING) { 49 | return; 50 | } 51 | emscripten_signal_clock--; 52 | if (emscripten_signal_clock == 0) { 53 | emscripten_signal_clock = PY_EMSCRIPTEN_SIGNAL_INTERVAL; 54 | _Py_CheckEmscriptenSignals(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Frame.c: -------------------------------------------------------------------------------- 1 | 2 | #define _PY_INTERPRETER 3 | 4 | #include "Python.h" 5 | #include "frameobject.h" 6 | #include "pycore_code.h" // stats 7 | #include "pycore_frame.h" 8 | #include "pycore_object.h" // _PyObject_GC_UNTRACK() 9 | #include "opcode.h" 10 | 11 | int 12 | _PyFrame_Traverse(_PyInterpreterFrame *frame, visitproc visit, void *arg) 13 | { 14 | Py_VISIT(frame->frame_obj); 15 | Py_VISIT(frame->f_locals); 16 | Py_VISIT(frame->f_funcobj); 17 | Py_VISIT(frame->f_code); 18 | /* locals */ 19 | PyObject **locals = _PyFrame_GetLocalsArray(frame); 20 | int i = 0; 21 | /* locals and stack */ 22 | for (; i stacktop; i++) { 23 | Py_VISIT(locals[i]); 24 | } 25 | return 0; 26 | } 27 | 28 | PyFrameObject * 29 | _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) 30 | { 31 | assert(frame->frame_obj == NULL); 32 | PyObject *exc = PyErr_GetRaisedException(); 33 | 34 | PyFrameObject *f = _PyFrame_New_NoTrack(frame->f_code); 35 | if (f == NULL) { 36 | Py_XDECREF(exc); 37 | return NULL; 38 | } 39 | PyErr_SetRaisedException(exc); 40 | if (frame->frame_obj) { 41 | // GH-97002: How did we get into this horrible situation? Most likely, 42 | // allocating f triggered a GC collection, which ran some code that 43 | // *also* created the same frame... while we were in the middle of 44 | // creating it! See test_sneaky_frame_object in test_frame.py for a 45 | // concrete example. 46 | // 47 | // Regardless, just throw f away and use that frame instead, since it's 48 | // already been exposed to user code. It's actually a bit tricky to do 49 | // this, since we aren't backed by a real _PyInterpreterFrame anymore. 50 | // Just pretend that we have an owned, cleared frame so frame_dealloc 51 | // doesn't make the situation worse: 52 | f->f_frame = (_PyInterpreterFrame *)f->_f_frame_data; 53 | f->f_frame->owner = FRAME_CLEARED; 54 | f->f_frame->frame_obj = f; 55 | Py_DECREF(f); 56 | return frame->frame_obj; 57 | } 58 | assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); 59 | assert(frame->owner != FRAME_CLEARED); 60 | f->f_frame = frame; 61 | frame->frame_obj = f; 62 | return f; 63 | } 64 | 65 | void 66 | _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) 67 | { 68 | assert(src->stacktop >= src->f_code->co_nlocalsplus); 69 | Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; 70 | memcpy(dest, src, size); 71 | // Don't leave a dangling pointer to the old frame when creating generators 72 | // and coroutines: 73 | dest->previous = NULL; 74 | } 75 | 76 | 77 | static void 78 | take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) 79 | { 80 | assert(frame->owner != FRAME_OWNED_BY_CSTACK); 81 | assert(frame->owner != FRAME_OWNED_BY_FRAME_OBJECT); 82 | assert(frame->owner != FRAME_CLEARED); 83 | Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; 84 | Py_INCREF(frame->f_code); 85 | memcpy((_PyInterpreterFrame *)f->_f_frame_data, frame, size); 86 | frame = (_PyInterpreterFrame *)f->_f_frame_data; 87 | f->f_frame = frame; 88 | frame->owner = FRAME_OWNED_BY_FRAME_OBJECT; 89 | if (_PyFrame_IsIncomplete(frame)) { 90 | // This may be a newly-created generator or coroutine frame. Since it's 91 | // dead anyways, just pretend that the first RESUME ran: 92 | PyCodeObject *code = frame->f_code; 93 | frame->prev_instr = _PyCode_CODE(code) + code->_co_firsttraceable; 94 | } 95 | assert(!_PyFrame_IsIncomplete(frame)); 96 | assert(f->f_back == NULL); 97 | _PyInterpreterFrame *prev = _PyFrame_GetFirstComplete(frame->previous); 98 | frame->previous = NULL; 99 | if (prev) { 100 | assert(prev->owner != FRAME_OWNED_BY_CSTACK); 101 | /* Link PyFrameObjects.f_back and remove link through _PyInterpreterFrame.previous */ 102 | PyFrameObject *back = _PyFrame_GetFrameObject(prev); 103 | if (back == NULL) { 104 | /* Memory error here. */ 105 | assert(PyErr_ExceptionMatches(PyExc_MemoryError)); 106 | /* Nothing we can do about it */ 107 | PyErr_Clear(); 108 | } 109 | else { 110 | f->f_back = (PyFrameObject *)Py_NewRef(back); 111 | } 112 | } 113 | if (!_PyObject_GC_IS_TRACKED((PyObject *)f)) { 114 | _PyObject_GC_TRACK((PyObject *)f); 115 | } 116 | } 117 | 118 | void 119 | _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) 120 | { 121 | /* It is the responsibility of the owning generator/coroutine 122 | * to have cleared the enclosing generator, if any. */ 123 | assert(frame->owner != FRAME_OWNED_BY_GENERATOR || 124 | _PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED); 125 | // GH-99729: Clearing this frame can expose the stack (via finalizers). It's 126 | // crucial that this frame has been unlinked, and is no longer visible: 127 | assert(_PyThreadState_GET()->cframe->current_frame != frame); 128 | if (frame->frame_obj) { 129 | PyFrameObject *f = frame->frame_obj; 130 | frame->frame_obj = NULL; 131 | if (Py_REFCNT(f) > 1) { 132 | take_ownership(f, frame); 133 | Py_DECREF(f); 134 | return; 135 | } 136 | Py_DECREF(f); 137 | } 138 | assert(frame->stacktop >= 0); 139 | for (int i = 0; i < frame->stacktop; i++) { 140 | Py_XDECREF(frame->localsplus[i]); 141 | } 142 | Py_XDECREF(frame->frame_obj); 143 | Py_XDECREF(frame->f_locals); 144 | Py_DECREF(frame->f_funcobj); 145 | } 146 | 147 | /* Unstable API functions */ 148 | 149 | PyObject * 150 | PyUnstable_InterpreterFrame_GetCode(struct _PyInterpreterFrame *frame) 151 | { 152 | PyObject *code = (PyObject *)frame->f_code; 153 | Py_INCREF(code); 154 | return code; 155 | } 156 | 157 | int 158 | PyUnstable_InterpreterFrame_GetLasti(struct _PyInterpreterFrame *frame) 159 | { 160 | return _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); 161 | } 162 | 163 | int 164 | PyUnstable_InterpreterFrame_GetLine(_PyInterpreterFrame *frame) 165 | { 166 | int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); 167 | return PyCode_Addr2Line(frame->f_code, addr); 168 | } 169 | -------------------------------------------------------------------------------- /FrozenMain.c: -------------------------------------------------------------------------------- 1 | /* Python interpreter main program for frozen scripts */ 2 | 3 | #include "Python.h" 4 | #include "pycore_runtime.h" // _PyRuntime_Initialize() 5 | #include 6 | 7 | #ifdef MS_WINDOWS 8 | extern void PyWinFreeze_ExeInit(void); 9 | extern void PyWinFreeze_ExeTerm(void); 10 | extern int PyInitFrozenExtensions(void); 11 | #endif 12 | 13 | /* Main program */ 14 | 15 | int 16 | Py_FrozenMain(int argc, char **argv) 17 | { 18 | PyStatus status = _PyRuntime_Initialize(); 19 | if (PyStatus_Exception(status)) { 20 | Py_ExitStatusException(status); 21 | } 22 | 23 | PyConfig config; 24 | PyConfig_InitPythonConfig(&config); 25 | // Suppress errors from getpath.c 26 | config.pathconfig_warnings = 0; 27 | // Don't parse command line options like -E 28 | config.parse_argv = 0; 29 | 30 | status = PyConfig_SetBytesArgv(&config, argc, argv); 31 | if (PyStatus_Exception(status)) { 32 | PyConfig_Clear(&config); 33 | Py_ExitStatusException(status); 34 | } 35 | 36 | const char *p; 37 | int inspect = 0; 38 | if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') { 39 | inspect = 1; 40 | } 41 | 42 | #ifdef MS_WINDOWS 43 | PyInitFrozenExtensions(); 44 | #endif /* MS_WINDOWS */ 45 | 46 | status = Py_InitializeFromConfig(&config); 47 | PyConfig_Clear(&config); 48 | if (PyStatus_Exception(status)) { 49 | Py_ExitStatusException(status); 50 | } 51 | 52 | #ifdef MS_WINDOWS 53 | PyWinFreeze_ExeInit(); 54 | #endif 55 | 56 | if (_Py_GetConfig()->verbose) { 57 | fprintf(stderr, "Python %s\n%s\n", 58 | Py_GetVersion(), Py_GetCopyright()); 59 | } 60 | 61 | int sts = 1; 62 | int n = PyImport_ImportFrozenModule("__main__"); 63 | if (n == 0) { 64 | Py_FatalError("the __main__ module is not frozen"); 65 | } 66 | if (n < 0) { 67 | PyErr_Print(); 68 | sts = 1; 69 | } 70 | else { 71 | sts = 0; 72 | } 73 | 74 | if (inspect && isatty((int)fileno(stdin))) { 75 | sts = PyRun_AnyFile(stdin, "") != 0; 76 | } 77 | 78 | #ifdef MS_WINDOWS 79 | PyWinFreeze_ExeTerm(); 80 | #endif 81 | if (Py_FinalizeEx() < 0) { 82 | sts = 120; 83 | } 84 | return sts; 85 | } 86 | -------------------------------------------------------------------------------- /Future.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "pycore_ast.h" // _PyAST_GetDocString() 3 | 4 | #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" 5 | 6 | static int 7 | future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename) 8 | { 9 | int i; 10 | 11 | assert(s->kind == ImportFrom_kind); 12 | 13 | asdl_alias_seq *names = s->v.ImportFrom.names; 14 | for (i = 0; i < asdl_seq_LEN(names); i++) { 15 | alias_ty name = (alias_ty)asdl_seq_GET(names, i); 16 | const char *feature = PyUnicode_AsUTF8(name->name); 17 | if (!feature) 18 | return 0; 19 | if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { 20 | continue; 21 | } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { 22 | continue; 23 | } else if (strcmp(feature, FUTURE_DIVISION) == 0) { 24 | continue; 25 | } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { 26 | continue; 27 | } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { 28 | continue; 29 | } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) { 30 | continue; 31 | } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) { 32 | continue; 33 | } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) { 34 | ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL; 35 | } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) { 36 | continue; 37 | } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) { 38 | ff->ff_features |= CO_FUTURE_ANNOTATIONS; 39 | } else if (strcmp(feature, "braces") == 0) { 40 | PyErr_SetString(PyExc_SyntaxError, 41 | "not a chance"); 42 | PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); 43 | return 0; 44 | } else { 45 | PyErr_Format(PyExc_SyntaxError, 46 | UNDEFINED_FUTURE_FEATURE, feature); 47 | PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1); 48 | return 0; 49 | } 50 | } 51 | return 1; 52 | } 53 | 54 | static int 55 | future_parse(PyFutureFeatures *ff, mod_ty mod, PyObject *filename) 56 | { 57 | if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) { 58 | return 1; 59 | } 60 | 61 | Py_ssize_t n = asdl_seq_LEN(mod->v.Module.body); 62 | if (n == 0) { 63 | return 1; 64 | } 65 | 66 | Py_ssize_t i = 0; 67 | if (_PyAST_GetDocString(mod->v.Module.body) != NULL) { 68 | i++; 69 | } 70 | 71 | for (; i < n; i++) { 72 | stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); 73 | 74 | /* The only things that can precede a future statement 75 | * are another future statement and a doc string. 76 | */ 77 | 78 | if (s->kind == ImportFrom_kind) { 79 | identifier modname = s->v.ImportFrom.module; 80 | if (modname && 81 | _PyUnicode_EqualToASCIIString(modname, "__future__")) { 82 | if (!future_check_features(ff, s, filename)) { 83 | return 0; 84 | } 85 | ff->ff_location = SRC_LOCATION_FROM_AST(s); 86 | } 87 | else { 88 | return 1; 89 | } 90 | } 91 | else { 92 | return 1; 93 | } 94 | } 95 | return 1; 96 | } 97 | 98 | 99 | int 100 | _PyFuture_FromAST(mod_ty mod, PyObject *filename, PyFutureFeatures *ff) 101 | { 102 | ff->ff_features = 0; 103 | ff->ff_location = (_PyCompilerSrcLocation){-1, -1, -1, -1}; 104 | 105 | if (!future_parse(ff, mod, filename)) { 106 | return 0; 107 | } 108 | return 1; 109 | } 110 | -------------------------------------------------------------------------------- /Game I/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(c_game 2 | c_list.c 3 | c_rectangle.c 4 | c_vector2.c 5 | c_window.c 6 | main.c 7 | ) 8 | 9 | target_link_directories(c_game PRIVATE ${sdl_BINARY_DIR}) 10 | target_include_directories(c_game PRIVATE ${sdl_SOURCE_DIR}/include) 11 | 12 | target_link_libraries(c_game SDL2::SDL2-static) 13 | -------------------------------------------------------------------------------- /Game I/c_key_event.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | /** 10 | * Enumeration of possible key states. 11 | */ 12 | typedef enum C_KeyState 13 | { 14 | C_KEYSTATE_DOWN, 15 | C_KEYSTATE_UP 16 | } C_KeyState; 17 | 18 | /** 19 | * Enumeration of possible input keys (maybe incomplete). 20 | */ 21 | typedef enum C_Key 22 | { 23 | C_KEY_ESCAPE, 24 | C_KEY_LEFT, 25 | C_KEY_RIGHT, 26 | } C_Key; 27 | 28 | /** 29 | * Struct encapsulating the data for a key press event. 30 | */ 31 | typedef struct C_KeyEvent 32 | { 33 | C_KeyState key_state; 34 | C_Key key; 35 | } C_KeyEvent; 36 | -------------------------------------------------------------------------------- /Game I/c_list.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "c_list.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "c_result.h" 13 | 14 | /** 15 | * Internal node struct. Stores value, next node and dtor function for value. 16 | */ 17 | typedef struct Node 18 | { 19 | void *value; 20 | struct Node *next; 21 | void (*dtor)(void *); 22 | } Node; 23 | 24 | /** 25 | * Internal list struct. Stores a head sentinel node. 26 | */ 27 | typedef struct C_List 28 | { 29 | Node *head; 30 | } C_List; 31 | 32 | /** 33 | * Internal iterator struct. Stores the node it is referencing. 34 | */ 35 | typedef struct C_ListIter 36 | { 37 | Node *node; 38 | } C_ListIter; 39 | 40 | C_Result c_list_create(C_List **list) 41 | { 42 | assert(list != NULL); 43 | 44 | C_Result result = C_SUCCESS; 45 | 46 | // allocate the list 47 | C_List *new_list = (C_List *)calloc(sizeof(C_List), 1u); 48 | if (new_list == NULL) 49 | { 50 | result = C_FAILED_TO_ALLOCATE_LIST; 51 | goto fail; 52 | } 53 | 54 | // allocate the head node 55 | new_list->head = (Node *)calloc(sizeof(Node), 1u); 56 | if (new_list->head == NULL) 57 | { 58 | result = C_FAILED_TO_ALLOCATE_NODE; 59 | goto fail; 60 | } 61 | 62 | // assign the list to the user supplied pointer 63 | *list = new_list; 64 | 65 | return result; 66 | 67 | fail: 68 | // clean up and return error code 69 | c_list_destroy(new_list); 70 | return result; 71 | } 72 | 73 | void c_list_destroy(C_List *list) 74 | { 75 | if (list == NULL) 76 | { 77 | return; 78 | } 79 | 80 | Node *cursor = list->head; 81 | 82 | // walk through the linked list 83 | do 84 | { 85 | Node *next = cursor->next; 86 | 87 | // if we have a dtor the call it 88 | if (cursor->dtor != NULL) 89 | { 90 | cursor->dtor(cursor->value); 91 | } 92 | 93 | // clean up the node and advance 94 | free(cursor); 95 | cursor = next; 96 | } while (cursor != NULL); 97 | 98 | free(list); 99 | } 100 | 101 | C_Result c_list_push_back(C_List *list, void *value) 102 | { 103 | return c_list_push_back_dtor(list, value, NULL); 104 | } 105 | 106 | C_Result c_list_push_back_dtor(C_List *list, void *value, void (*dtor)(void *)) 107 | { 108 | assert(list != NULL); 109 | 110 | C_Result result = C_SUCCESS; 111 | 112 | // walk the list looking for rhe last node 113 | Node *cursor = list->head; 114 | while (cursor->next != NULL) 115 | { 116 | cursor = cursor->next; 117 | } 118 | 119 | // allocate a new node 120 | Node *new_node = (Node *)calloc(sizeof(Node), 1u); 121 | if (new_node == NULL) 122 | { 123 | result = C_FAILED_TO_ALLOCATE_NODE; 124 | goto end; 125 | } 126 | 127 | // store the supplied data abd wire up the node to the end 128 | new_node->value = value; 129 | new_node->dtor = dtor; 130 | cursor->next = new_node; 131 | 132 | end: 133 | return result; 134 | } 135 | 136 | void c_list_remove(C_List *list, const C_ListIter *iter) 137 | { 138 | assert(list != NULL); 139 | assert(iter != NULL); 140 | 141 | // walk the list looking for the node 142 | Node *cursor = list->head; 143 | while ((cursor->next != NULL) && (cursor->next != iter->node)) 144 | { 145 | cursor = cursor->next; 146 | } 147 | 148 | // if we didn't reach the end of the list then we found the node 149 | if (cursor->next != NULL) 150 | { 151 | Node *to_remove = cursor->next; 152 | Node *next = to_remove->next; 153 | 154 | // if we have a dtor the call it 155 | if (to_remove->dtor != NULL) 156 | { 157 | to_remove->dtor(to_remove->value); 158 | } 159 | 160 | // free the node and remove it from the list 161 | free(to_remove); 162 | cursor->next = next; 163 | } 164 | } 165 | 166 | C_Result c_list_iterator_create(const C_List *list, C_ListIter **iter) 167 | { 168 | assert(list != NULL); 169 | assert(iter != NULL); 170 | 171 | C_Result result = C_SUCCESS; 172 | 173 | // allocate the iterator 174 | C_ListIter *new_iter = (C_ListIter *)calloc(sizeof(C_ListIter), 1u); 175 | if (new_iter == NULL) 176 | { 177 | result = C_FAILED_TO_ALLOCATE_ITERATOR; 178 | goto end; 179 | } 180 | 181 | c_list_iterator_reset(list, &new_iter); 182 | 183 | // assign the iterator to the user supplied pointer 184 | *iter = new_iter; 185 | 186 | end: 187 | return result; 188 | } 189 | 190 | void c_list_iterator_destroy(C_ListIter *iter) 191 | { 192 | free(iter); 193 | } 194 | 195 | void c_list_iterator_advance(C_ListIter **iter) 196 | { 197 | assert(*iter != NULL); 198 | 199 | (*iter)->node = (*iter)->node->next; 200 | } 201 | 202 | void c_list_iterator_reset(const C_List *list, C_ListIter **iter) 203 | { 204 | assert(*iter != NULL); 205 | 206 | (*iter)->node = list->head->next; 207 | } 208 | 209 | bool c_list_iterator_at_end(C_ListIter *iter) 210 | { 211 | assert(iter != NULL); 212 | 213 | return iter->node == NULL; 214 | } 215 | 216 | void *c_list_iterator_value(const C_ListIter *iter) 217 | { 218 | assert(iter != NULL); 219 | 220 | return iter->node->value; 221 | } 222 | -------------------------------------------------------------------------------- /Game I/c_list.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "c_result.h" 12 | 13 | /** 14 | * Simple linked list data structure which can store void*. 15 | */ 16 | 17 | /** 18 | * Handle to internal list data. 19 | */ 20 | typedef struct C_List C_List; 21 | 22 | /** 23 | * Handle to internal list iterator data. 24 | */ 25 | typedef struct C_ListIter C_ListIter; 26 | 27 | /** 28 | * Create a new list. 29 | * 30 | * @param list 31 | * Out parameter for created list. 32 | * 33 | * @returns 34 | * C_SUCCESS on success 35 | * Another Result type on error 36 | */ 37 | C_Result c_list_create(C_List **list); 38 | 39 | /** 40 | * Destroy a list. 41 | * 42 | * Will call dtor function for each node (if supplied). 43 | * 44 | * @param list 45 | * List to destroy. 46 | */ 47 | void c_list_destroy(C_List *list); 48 | 49 | /** 50 | * Push a new value to the end of the list. 51 | * 52 | * @param list 53 | * List to add to. 54 | * 55 | * @param value 56 | * Value to add. 57 | * 58 | * @returns 59 | * C_SUCCESS on success 60 | * Another Result type on error 61 | */ 62 | C_Result c_list_push_back(C_List *list, void *value); 63 | 64 | /** 65 | * Push a new value to the end of the list, with a dtor function which will get called when the node is removed or the 66 | * list is destroyed. 67 | * 68 | * @param list 69 | * List to add to. 70 | * 71 | * @param value 72 | * Value to add. 73 | * 74 | * @param dtor 75 | * Function to call to cleanup value. 76 | * 77 | * @returns 78 | * C_SUCCESS on success 79 | * Another Result type on error 80 | */ 81 | C_Result c_list_push_back_dtor(C_List *list, void *value, void (*dtor)(void *)); 82 | 83 | /** 84 | * Remove the node referenced by an iterator from a list. 85 | * 86 | * @param list 87 | * List to remove node from. 88 | * 89 | * @param iter 90 | * Iterator to node to remove. 91 | */ 92 | void c_list_remove(C_List *list, const C_ListIter *iter); 93 | 94 | /** 95 | * Create a new iterator to the first node. 96 | * 97 | * Note this will be NULL if the list is empty. 98 | * 99 | * @param list 100 | * List to create iterator in. 101 | * 102 | * @param iter 103 | * Out parameter for created iterator. 104 | * 105 | * @returns 106 | * C_SUCCESS on success 107 | * Another Result type on error 108 | */ 109 | C_Result c_list_iterator_create(const C_List *list, C_ListIter **iter); 110 | 111 | /** 112 | * Destroy an iterator. 113 | * 114 | * @param iter 115 | * Iterator to destroy. 116 | */ 117 | void c_list_iterator_destroy(C_ListIter *iter); 118 | 119 | /** 120 | * Advance an iterator to the next node. 121 | * 122 | * @param iter 123 | * Out parameter for advanced iterator. 124 | */ 125 | void c_list_iterator_advance(C_ListIter **iter); 126 | 127 | /** 128 | * Reset an iterator back to the start of the list. 129 | * 130 | * @param list 131 | * List to reset iterator in. 132 | * 133 | * @param iter 134 | * Out paramater for reset iterator. 135 | */ 136 | void c_list_iterator_reset(const C_List *list, C_ListIter **iter); 137 | 138 | /** 139 | * Check if an iterator is one past the end of the list. 140 | * 141 | * @param iter 142 | * Iterator to check. 143 | * 144 | * @returns 145 | * True if iterator is one past the end of the list, otherwise false. 146 | */ 147 | bool c_list_iterator_at_end(C_ListIter *iter); 148 | 149 | /** 150 | * Get the value the iterator is referencing. 151 | * 152 | * @param iter 153 | * Iterator to get value of. 154 | * 155 | * @returns 156 | * Value at iterator. 157 | */ 158 | void *c_list_iterator_value(const C_ListIter *iter); 159 | -------------------------------------------------------------------------------- /Game I/c_rectangle.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "c_rectangle.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "c_vector2.h" 13 | 14 | C_Rectangle c_rectangle_create(const C_Vector2 *position, float width, float height) 15 | { 16 | return c_rectangle_create_xy(position->x, position->y, width, height); 17 | } 18 | 19 | C_Rectangle c_rectangle_create_xy(float x, float y, float width, float height) 20 | { 21 | C_Rectangle rect = {.position = {.x = x, .y = y}, .width = width, .height = height}; 22 | return rect; 23 | } 24 | 25 | void c_rectangle_translate(C_Rectangle *rectangle, const C_Vector2 *translation) 26 | { 27 | c_vector2_add(&rectangle->position, translation); 28 | } 29 | 30 | void c_rectangle_translate_xy(C_Rectangle *rectangle, float x, float y) 31 | { 32 | c_vector2_add_xy(&rectangle->position, x, y); 33 | } 34 | 35 | void c_rectangle_set_position(C_Rectangle *rectangle, const C_Vector2 *position) 36 | { 37 | rectangle->position = *position; 38 | } 39 | 40 | void c_rectangle_set_position_xy(C_Rectangle *rectangle, float x, float y) 41 | { 42 | rectangle->position.x = x; 43 | rectangle->position.y = y; 44 | } 45 | 46 | void c_rectangle_print(const C_Rectangle *rectangle) 47 | { 48 | printf( 49 | "{ x: %f, y: %f, w: %f, h: %f }\n", 50 | rectangle->position.x, 51 | rectangle->position.y, 52 | rectangle->width, 53 | rectangle->height); 54 | } 55 | -------------------------------------------------------------------------------- /Game I/c_rectangle.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include "c_vector2.h" 10 | 11 | /** 12 | * A Rectangle represents an axis aligned box defined by the coordinates of its upper left corner as well as width and 13 | * height. 14 | */ 15 | 16 | /** 17 | * Struct for rectangle data. Deliberately public. 18 | */ 19 | typedef struct C_Rectangle 20 | { 21 | C_Vector2 position; 22 | float width; 23 | float height; 24 | } C_Rectangle; 25 | 26 | /** 27 | * Create a new Rectangle. 28 | * 29 | * @param position 30 | * Position of rectangle (upper left corner). 31 | * 32 | * @param width 33 | * Width of rectangle. 34 | * 35 | * @param height 36 | * Height of rectangle. 37 | * 38 | * @returns 39 | * Rectangle constructed with supplied values. 40 | */ 41 | C_Rectangle c_rectangle_create(const C_Vector2 *position, float width, float height); 42 | 43 | /** 44 | * Create a new Rectangle. 45 | * 46 | * @param x 47 | * X coordinate of position (upper left corner). 48 | * 49 | * @param y 50 | * Y coordinate of position (upper left corner). 51 | * 52 | * @param width 53 | * Width of rectangle. 54 | * 55 | * @param height 56 | * Height of rectangle. 57 | * 58 | * @returns 59 | * Rectangle constructed with supplied values. 60 | */ 61 | C_Rectangle c_rectangle_create_xy(float x, float y, float width, float height); 62 | 63 | /** 64 | * Translate the position of a rectangle. 65 | * 66 | * @param rectangle 67 | * Rectangle to translate. 68 | * 69 | * @param translation 70 | * Translation amount. 71 | */ 72 | void c_rectangle_translate(C_Rectangle *rectangle, const C_Vector2 *translation); 73 | 74 | /** 75 | * Translate the position of a rectangle. 76 | * 77 | * @param rectangle 78 | * Rectangle to translate. 79 | * 80 | * @param x 81 | * Amount to move along x axis. 82 | * 83 | * @param y 84 | * Amount to move along y axis. 85 | */ 86 | void c_rectangle_translate_xy(C_Rectangle *rectangle, float x, float y); 87 | 88 | /** 89 | * Set the position of a rectangle. 90 | * 91 | * @param rectangle 92 | * Rectangle to set position of. 93 | * 94 | * @param position 95 | * New rectangle position. 96 | */ 97 | void c_rectangle_set_position(C_Rectangle *rectangle, const C_Vector2 *position); 98 | 99 | /** 100 | * Set the position of a rectangle. 101 | * 102 | * @param rectangle 103 | * Rectangle to set position of. 104 | * 105 | * @param x 106 | * X coordinate of new position. 107 | * 108 | * @param y 109 | * Y coordinate of new position. 110 | */ 111 | void c_rectangle_set_position_xy(C_Rectangle *rectangle, float x, float y); 112 | 113 | /** 114 | * Print rectangle to stdout. 115 | * 116 | * @param rectangle 117 | * Rectangle to print. 118 | */ 119 | void c_rectangle_print(const C_Rectangle *rectangle); 120 | -------------------------------------------------------------------------------- /Game I/c_result.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | /** 10 | * Enumeration of all possible return codes. 11 | */ 12 | typedef enum C_Result 13 | { 14 | C_SUCCESS, 15 | 16 | C_NO_MORE_EVENTS, 17 | 18 | C_SDL_INIT_FAILED, 19 | 20 | C_FAILED_TO_ALLOCATE_WINDOW, 21 | C_FAILED_TO_CREATE_WINDOW, 22 | C_FAILED_TO_GET_SURFACE, 23 | C_FAILED_TO_FILL_RECT, 24 | C_FAILED_TO_UPDATE_SURFACE, 25 | C_FAILED_TO_CREATE_RENDERER, 26 | 27 | C_FAILED_TO_MAP_KEY, 28 | 29 | C_FAILED_TO_CLEAR_RENDERER, 30 | C_FAILED_TO_SET_RENDER_COLOUR, 31 | C_FAILED_TO_DRAW_FILLED_RECT, 32 | 33 | C_FAILED_TO_ALLOCATE_LIST, 34 | C_FAILED_TO_ALLOCATE_NODE, 35 | C_FAILED_TO_ALLOCATE_ITERATOR, 36 | } C_Result; 37 | -------------------------------------------------------------------------------- /Game I/c_vector2.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "c_vector2.h" 8 | 9 | #include 10 | #include 11 | 12 | C_Vector2 c_vector2_create() 13 | { 14 | return c_vector2_create_xy(0.0f, 0.0f); 15 | } 16 | 17 | C_Vector2 c_vector2_create_xy(float x, float y) 18 | { 19 | C_Vector2 vec = {.x = x, .y = y}; 20 | return vec; 21 | } 22 | 23 | void c_vector2_add(C_Vector2 *vec1, const C_Vector2 *vec2) 24 | { 25 | assert(vec1 != NULL); 26 | assert(vec2 != NULL); 27 | 28 | vec1->x += vec2->x; 29 | vec1->y += vec2->y; 30 | } 31 | 32 | void c_vector2_add_xy(C_Vector2 *vec, float x, float y) 33 | { 34 | assert(vec != NULL); 35 | 36 | vec->x += x; 37 | vec->y += y; 38 | } 39 | 40 | void c_vector2_print(const C_Vector2 *vec) 41 | { 42 | assert(vec != NULL); 43 | 44 | printf("{ x: %f, y: %f }\n", vec->x, vec->y); 45 | } 46 | -------------------------------------------------------------------------------- /Game I/c_vector2.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | /** 10 | * A Vector2 represents a two component (x and y) vector. 11 | */ 12 | 13 | /** 14 | * Struct for vector data. Deliberately public. 15 | */ 16 | typedef struct C_Vector2 17 | { 18 | float x; 19 | float y; 20 | } C_Vector2; 21 | 22 | /** 23 | * Create a new Vector2 with both components 0.0. 24 | * 25 | * @returns 26 | * Vector2 with x and y set to 0.0. 27 | */ 28 | C_Vector2 c_vector2_create(); 29 | 30 | /** 31 | * Create a new Vector2 with supplied component values. 32 | * 33 | * @param x 34 | * X component. 35 | * 36 | * @param y 37 | * Y component. 38 | * 39 | * @returns 40 | * Vector2 with x and y set to supplied values. 41 | */ 42 | C_Vector2 c_vector2_create_xy(float x, float y); 43 | 44 | /** 45 | * Add one vector to another. 46 | * 47 | * @param vec1 48 | * The source vector, this will be modified. 49 | * 50 | * @param vec2 51 | * The vector to add to vec1. 52 | */ 53 | void c_vector2_add(C_Vector2 *vec1, const C_Vector2 *vec2); 54 | 55 | /** 56 | * Add values to a vector. 57 | * 58 | * @param vec 59 | * The source vector, this will be modified. 60 | * 61 | * @param x 62 | * Value to add to x component. 63 | * 64 | * @param y 65 | * Value to add to y component. 66 | */ 67 | void c_vector2_add_xy(C_Vector2 *vec, float x, float y); 68 | 69 | /** 70 | * Print vector to stdout. 71 | * 72 | * @param vec 73 | * The vector to print. 74 | */ 75 | void c_vector2_print(const C_Vector2 *vec); 76 | -------------------------------------------------------------------------------- /Game I/c_window.c: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "c_window.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "SDL.h" 15 | 16 | #include "c_key_event.h" 17 | #include "c_result.h" 18 | 19 | typedef struct C_Window 20 | { 21 | SDL_Window *window; 22 | SDL_Renderer *renderer; 23 | } C_Window; 24 | 25 | static C_Result map_sdl_key(C_Key *key, SDL_Keycode sdl_code) 26 | { 27 | switch (sdl_code) 28 | { 29 | case SDLK_ESCAPE: *key = C_KEY_ESCAPE; return C_SUCCESS; 30 | case SDLK_LEFT: *key = C_KEY_LEFT; return C_SUCCESS; 31 | case SDLK_RIGHT: *key = C_KEY_RIGHT; return C_SUCCESS; 32 | default: return C_NO_MORE_EVENTS; 33 | } 34 | } 35 | 36 | C_Result c_window_create(C_Window **window) 37 | { 38 | C_Result res = C_SUCCESS; 39 | 40 | // perform the initial SDL initialisation 41 | if (SDL_Init(SDL_INIT_VIDEO) != 0) 42 | { 43 | res = C_SDL_INIT_FAILED; 44 | goto fail; 45 | } 46 | 47 | // allocate space for the window object 48 | C_Window *new_window = (C_Window *)calloc(1u, sizeof(C_Window)); 49 | if (new_window == NULL) 50 | { 51 | res = C_FAILED_TO_ALLOCATE_WINDOW; 52 | goto fail; 53 | } 54 | 55 | // create an SDL window 56 | new_window->window = 57 | SDL_CreateWindow("c_game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 800, SDL_WINDOW_SHOWN); 58 | if (new_window->window == NULL) 59 | { 60 | res = C_FAILED_TO_CREATE_WINDOW; 61 | goto fail; 62 | } 63 | 64 | // create an SDL renderer 65 | new_window->renderer = SDL_CreateRenderer(new_window->window, -1, 0); 66 | if (new_window->renderer == NULL) 67 | { 68 | res = C_FAILED_TO_CREATE_RENDERER; 69 | goto fail; 70 | } 71 | 72 | // assign the window to the user supplied pointer 73 | *window = new_window; 74 | return res; 75 | 76 | fail: 77 | // clean up and return error code 78 | c_window_destroy(new_window); 79 | return res; 80 | } 81 | 82 | void c_window_destroy(C_Window *window) 83 | { 84 | if (window == NULL) 85 | { 86 | return; 87 | } 88 | 89 | if (window->window != NULL) 90 | { 91 | SDL_DestroyWindow(window->window); 92 | } 93 | 94 | free(window); 95 | 96 | SDL_Quit(); 97 | } 98 | 99 | C_Result c_window_get_event(const C_Window *window, C_KeyEvent *event) 100 | { 101 | assert(window != NULL); 102 | assert(event != NULL); 103 | 104 | C_Result result = C_NO_MORE_EVENTS; 105 | 106 | // try and get an SDL event 107 | SDL_Event sdl_event; 108 | if (SDL_PollEvent(&sdl_event) != 0u) 109 | { 110 | bool try_map_key = false; 111 | 112 | if (sdl_event.type == SDL_KEYDOWN) 113 | { 114 | event->key_state = C_KEYSTATE_DOWN; 115 | try_map_key = true; 116 | } 117 | else if (sdl_event.type == SDL_KEYUP) 118 | { 119 | event->key_state = C_KEYSTATE_UP; 120 | try_map_key = true; 121 | } 122 | 123 | if (try_map_key) 124 | { 125 | // if we get here then we know we had a key event (either press or release), so convert the SDL key code 126 | // to our internal representation 127 | result = map_sdl_key(&event->key, sdl_event.key.keysym.sym); 128 | } 129 | } 130 | 131 | return result; 132 | } 133 | 134 | C_Result c_window_pre_render(const C_Window *window) 135 | { 136 | C_Result result = C_SUCCESS; 137 | 138 | // clear the window to black 139 | 140 | if (SDL_SetRenderDrawColor(window->renderer, 0x0, 0x0, 0x0, 0x0) != 0) 141 | { 142 | result = C_FAILED_TO_SET_RENDER_COLOUR; 143 | goto end; 144 | } 145 | 146 | if (SDL_RenderClear(window->renderer) != 0) 147 | { 148 | result = C_FAILED_TO_CLEAR_RENDERER; 149 | goto end; 150 | } 151 | 152 | end: 153 | return result; 154 | } 155 | 156 | void c_window_post_render(const C_Window *window) 157 | { 158 | return SDL_RenderPresent(window->renderer); 159 | } 160 | 161 | C_Result c_window_draw_rectangle(const C_Window *window, const C_Rectangle *rectangle, uint8_t r, uint8_t g, uint8_t b) 162 | { 163 | C_Result result = C_SUCCESS; 164 | 165 | // convert our internal rect to an SDL rect 166 | SDL_Rect sdl_rect = { 167 | .x = rectangle->position.x, .y = rectangle->position.y, .w = rectangle->width, .h = rectangle->height}; 168 | 169 | // set the draw colour 170 | if (SDL_SetRenderDrawColor(window->renderer, r, g, b, 0xff) != 0) 171 | { 172 | result = C_FAILED_TO_SET_RENDER_COLOUR; 173 | goto end; 174 | } 175 | 176 | // draw! 177 | if (SDL_RenderFillRect(window->renderer, &sdl_rect) != 0) 178 | { 179 | result = C_FAILED_TO_DRAW_FILLED_RECT; 180 | goto end; 181 | } 182 | 183 | end: 184 | return result; 185 | } 186 | -------------------------------------------------------------------------------- /Game I/c_window.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "c_key_event.h" 12 | #include "c_rectangle.h" 13 | #include "c_result.h" 14 | 15 | /** 16 | * Window is responsible fro creating and destroying a platform window as well as rendering to it and getting event. 17 | */ 18 | 19 | /** 20 | * Handle to internal window data. 21 | */ 22 | typedef struct C_Window C_Window; 23 | 24 | /** 25 | * Create a new platform window. 26 | * 27 | * Note this library only supports creating one window, any calls to this function after the first successful call are 28 | * undefined. 29 | * 30 | * @param window 31 | * Out paramater for created window object. 32 | * 33 | * @returns 34 | * C_SUCCESS on success 35 | * Another Result type on error 36 | */ 37 | C_Result c_window_create(C_Window **window); 38 | 39 | /** 40 | * Destroy a window. 41 | * 42 | * @param window 43 | * The window to destroy. 44 | */ 45 | void c_window_destroy(C_Window *window); 46 | 47 | /** 48 | * Get an event if one is available. 49 | * 50 | * @param window 51 | * Window to get events for. 52 | * 53 | * @param event 54 | * Out paramater to write event data to. 55 | * 56 | * @returns 57 | * C_SUCCESS on success 58 | * C_NO_MORE_EVENTS if there was no event to get 59 | * Another Result type on error 60 | */ 61 | C_Result c_window_get_event(const C_Window *window, C_KeyEvent *event); 62 | 63 | /** 64 | * Perform an pre-render tasks. 65 | * 66 | * @param window 67 | * Window to render to. 68 | * 69 | * @returns 70 | * C_SUCCESS on success 71 | * Another Result type on error 72 | */ 73 | C_Result c_window_pre_render(const C_Window *window); 74 | 75 | /** 76 | * Perform an post-render tasks. 77 | * 78 | * @param window 79 | * Window to render to. 80 | */ 81 | void c_window_post_render(const C_Window *window); 82 | 83 | /** 84 | * Draw a rectangle to the screen. 85 | * 86 | * This *must* be called after c_window_pre_render and before c_window_post_render for any given frame. 87 | * 88 | * @param window 89 | * The window to render to. 90 | * 91 | * @param rectangle 92 | * The rectangle to draw. 93 | * 94 | * @param r 95 | * The red component of the rectangle colour. 96 | * 97 | * @param g 98 | * The green component of the rectangle colour. 99 | * 100 | * @param b 101 | * The blue component of the rectangle colour. 102 | * 103 | * @returns 104 | * C_SUCCESS on success 105 | * Another Result type on error 106 | */ 107 | C_Result c_window_draw_rectangle(const C_Window *window, const C_Rectangle *rectangle, uint8_t r, uint8_t g, uint8_t b); 108 | -------------------------------------------------------------------------------- /Game II/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(cpp_game 2 | colour.cpp 3 | entity.cpp 4 | main.cpp 5 | rectangle.cpp 6 | vector2.cpp 7 | window.cpp 8 | ) 9 | 10 | target_link_directories(cpp_game PRIVATE ${sdl_BINARY_DIR}) 11 | target_include_directories(cpp_game PRIVATE ${sdl_SOURCE_DIR}/include) 12 | target_compile_features(cpp_game PRIVATE cxx_std_20) 13 | 14 | target_link_libraries(cpp_game SDL2::SDL2-static) 15 | -------------------------------------------------------------------------------- /Game II/colour.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "colour.h" 8 | 9 | #include 10 | #include 11 | 12 | namespace cpp 13 | { 14 | 15 | Colour::Colour() 16 | : Colour(0xffffff) 17 | { 18 | } 19 | 20 | Colour::Colour(std::uint8_t r, std::uint8_t g, std::uint8_t b) 21 | : r(r) 22 | , g(g) 23 | , b(b) 24 | { 25 | } 26 | 27 | Colour::Colour(std::uint32_t colour) 28 | : Colour((colour >> 16) & 0xff, (colour >> 7) & 0xff, colour & 0xff) 29 | { 30 | } 31 | 32 | bool operator==(const Colour &c1, const Colour &c2) 33 | { 34 | return (c1.r == c2.r) && (c1.g == c2.g) && (c1.b == c2.b); 35 | } 36 | 37 | bool operator!=(const Colour &c1, const Colour &c2) 38 | { 39 | return !(c1 == c2); 40 | } 41 | 42 | std::ostream &operator<<(std::ostream &os, const Colour &c) 43 | { 44 | os << "{ r: " << c.r << ", g: " << c.g << ", b: " << c.b << " }"; 45 | return os; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Game II/colour.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace cpp 13 | { 14 | 15 | /** 16 | * A Colour represents an RGB component (where each component is 8 bits). 17 | */ 18 | class Colour 19 | { 20 | public: 21 | /** 22 | * Construct a new white colour. 23 | */ 24 | Colour(); 25 | 26 | /** 27 | * Construct a new colour from r, g and b components. 28 | * 29 | * @param r 30 | * Red component. 31 | * 32 | * @param g 33 | * Green component. 34 | * 35 | * @param b 36 | * Blue component. 37 | */ 38 | Colour(std::uint8_t r, std::uint8_t g, std::uint8_t b); 39 | 40 | /** 41 | * Construct a new colour from a hex colour number. The expected format of the number is 0xRRGGBB. 42 | * 43 | * @param colour 44 | * Colour value (0xRRGGBB). 45 | */ 46 | Colour(std::uint32_t colour); 47 | 48 | /** 49 | * Stream operator. 50 | * 51 | * @param os 52 | * Stream to write to. 53 | * 54 | * @param c 55 | * Colour to write to stream. 56 | * 57 | * @returns 58 | * Reference to supplied stream. 59 | */ 60 | friend std::ostream &operator<<(std::ostream &os, const Colour &c); 61 | 62 | /** Red component. */ 63 | std::uint8_t r; 64 | 65 | /** Green component. */ 66 | std::uint8_t g; 67 | 68 | /** Blue component. */ 69 | std::uint8_t b; 70 | }; 71 | 72 | /** 73 | * Check if two colours are equal. 74 | * 75 | * @param c1 76 | * First colour to check. 77 | * 78 | * @param c2 79 | * Second colour to check. 80 | * 81 | * @returns 82 | * True if both colours are equal, otherwise false. 83 | */ 84 | bool operator==(const Colour &c1, const Colour &c2); 85 | 86 | /** 87 | * Check if two colours are not equal. 88 | * 89 | * @param c1 90 | * First colour to check. 91 | * 92 | * @param c2 93 | * Second colour to check. 94 | * 95 | * @returns 96 | * True if both colours are not equal, otherwise false. 97 | */ 98 | bool operator!=(const Colour &c1, const Colour &c2); 99 | 100 | // see docs on class definition 101 | std::ostream &operator<<(std::ostream &os, const Colour &c); 102 | 103 | } 104 | -------------------------------------------------------------------------------- /Game II/entity.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "entity.h" 8 | 9 | #include 10 | 11 | #include "colour.h" 12 | #include "rectangle.h" 13 | #include "vector2.h" 14 | 15 | namespace cpp 16 | { 17 | 18 | Entity::Entity(const Rectangle &rectangle, const Colour &colour) 19 | : rectangle_(rectangle) 20 | , colour_(colour) 21 | { 22 | } 23 | 24 | Rectangle Entity::rectangle() const 25 | { 26 | return rectangle_; 27 | } 28 | 29 | Colour Entity::colour() const 30 | { 31 | return colour_; 32 | } 33 | 34 | void Entity::translate(const Vector2 &translation) 35 | { 36 | rectangle_.translate(translation); 37 | } 38 | 39 | bool Entity::intersects(const Entity &e) const 40 | { 41 | return rectangle_.intersects(e.rectangle_); 42 | } 43 | 44 | bool operator==(const Entity &e1, const Entity &e2) 45 | { 46 | return (e1.colour() == e2.colour()) && (e1.rectangle() == e2.rectangle()); 47 | } 48 | 49 | bool operator!=(const Entity &e1, const Entity &e2) 50 | { 51 | return !(e1 == e2); 52 | } 53 | 54 | std::ostream &operator<<(std::ostream &os, const Entity &e) 55 | { 56 | os << "{ " << e.colour() << ", " << e.rectangle() << " }"; 57 | return os; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Game II/entity.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include "colour.h" 10 | #include "rectangle.h" 11 | #include "vector2.h" 12 | 13 | namespace cpp 14 | { 15 | 16 | /** 17 | * An Entity represents a renderable rectangle. 18 | */ 19 | class Entity 20 | { 21 | public: 22 | /** 23 | * Construct a new entity. 24 | * 25 | * @param rectangle 26 | * Rectangle representing the area to draw. 27 | * 28 | * @param colour 29 | * The colour to render the entity. 30 | */ 31 | Entity(const Rectangle &rectangle, const Colour &colour); 32 | 33 | /** 34 | * Get the entities rectangle. 35 | * 36 | * @returns 37 | * Entity rectangle. 38 | */ 39 | Rectangle rectangle() const; 40 | 41 | /** 42 | * Get the entities colour. 43 | * 44 | * @returns 45 | * Entity colour. 46 | */ 47 | Colour colour() const; 48 | 49 | /** 50 | * Translate the entity. 51 | * 52 | * @param translation 53 | * Translation amount. 54 | */ 55 | void translate(const Vector2 &translation); 56 | 57 | /** 58 | * Check if another entity intersects this. 59 | * 60 | * @param e 61 | * Entity to check for intersection. 62 | * 63 | * @returns 64 | * True if supplied entity intersects this, otherwise false. 65 | */ 66 | bool intersects(const Entity &e) const; 67 | 68 | /** 69 | * Stream operator. 70 | * 71 | * @param os 72 | * Stream to write to. 73 | * 74 | * @param e 75 | * Entity to write to stream. 76 | * 77 | * @returns 78 | * Reference to supplied stream. 79 | */ 80 | friend std::ostream &operator<<(std::ostream &os, const Entity &e); 81 | 82 | private: 83 | /** Drawable area. */ 84 | Rectangle rectangle_; 85 | 86 | /** Draw colour. */ 87 | Colour colour_; 88 | }; 89 | 90 | /** 91 | * Check if two entities are equal. 92 | * 93 | * @param e1 94 | * First entity to check. 95 | * 96 | * @param e2 97 | * Second entity to check. 98 | * 99 | * @returns 100 | * True if both entities are equal, otherwise false. 101 | */ 102 | bool operator==(const Entity &e1, const Entity &e2); 103 | 104 | /** 105 | * Check if two entities are equal. 106 | * 107 | * @param e1 108 | * First entity to check. 109 | * 110 | * @param e2 111 | * Second entity to check. 112 | * 113 | * @returns 114 | * True if both entities are equal, otherwise false. 115 | */ 116 | bool operator!=(const Entity &e1, const Entity &e2); 117 | 118 | // see docs on class definition 119 | std::ostream &operator<<(std::ostream &os, const Entity &e); 120 | 121 | } 122 | -------------------------------------------------------------------------------- /Game II/key_event.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | namespace cpp 10 | { 11 | 12 | /** 13 | * Enumeration of possible key states. 14 | */ 15 | enum class KeyState 16 | { 17 | DOWN, 18 | UP 19 | }; 20 | 21 | /** 22 | * Enumeration of possible input keys (maybe incomplete). 23 | */ 24 | enum class Key 25 | { 26 | ESCAPE, 27 | LEFT, 28 | RIGHT, 29 | }; 30 | 31 | /** 32 | * Struct encapsulating the data for a key press event. 33 | */ 34 | struct KeyEvent 35 | { 36 | KeyState key_state; 37 | Key key; 38 | }; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Game II/main.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include 8 | #include 9 | 10 | #include "colour.h" 11 | #include "entity.h" 12 | #include "key_event.h" 13 | #include "rectangle.h" 14 | #include "vector2.h" 15 | #include "window.h" 16 | 17 | namespace 18 | { 19 | 20 | /** 21 | * Helper function to create a row of 10 bricks. 22 | * 23 | * @param entities 24 | * Collection to add new entities to. 25 | * 26 | * @param y 27 | * Y coordinate of row. 28 | * 29 | * @param colour 30 | * Colour of bricks. 31 | */ 32 | void create_brick_row(std::vector &entities, float y, const cpp::Colour &colour) 33 | { 34 | auto x = 20.0f; 35 | 36 | for (auto i = 0u; i < 10u; ++i) 37 | { 38 | entities.push_back({{{x, y}, 58.0f, 20.0f}, colour}); 39 | x += 78.0f; 40 | } 41 | } 42 | 43 | /** 44 | * Helper function to check for and resolve collisions between the ball and other entities. 45 | * 46 | * @param ball 47 | * Ball to check for collisions. 48 | * 49 | * @param ball_velocity 50 | * Velocity of ball, might get mutated during collision response. 51 | * 52 | * @param paddle 53 | * Paddle to check for collisions with. 54 | * 55 | * @param entities 56 | * Collection of all entities, brick entities will be removed if a collision is detected. 57 | */ 58 | void check_collisions( 59 | const cpp::Entity &ball, 60 | cpp::Vector2 &ball_velocity, 61 | const cpp::Entity &paddle, 62 | std::vector &entities) 63 | { 64 | // check and handle ball and paddle collision 65 | if (paddle.intersects(ball)) 66 | { 67 | const auto ball_pos = ball.rectangle().position; 68 | const auto paddle_pos = paddle.rectangle().position; 69 | 70 | if (ball_pos.x < paddle_pos.x + 100.0f) 71 | { 72 | ball_velocity.x = -0.7f; 73 | ball_velocity.y = -0.7f; 74 | } 75 | else if (ball_pos.x < paddle_pos.x + 200.0f) 76 | { 77 | ball_velocity.x = 0.0f; 78 | ball_velocity.y = -1.0f; 79 | } 80 | else 81 | { 82 | ball_velocity.x = 0.7f; 83 | ball_velocity.y = -0.7f; 84 | } 85 | } 86 | else 87 | { 88 | // only check brick intersections if we didn't intersect the paddle, unlikely these will both happen in the same 89 | // frame due to the layout of the game 90 | 91 | // iterate over all entities, skipping the first two as these are the paddle and ball 92 | auto bricks_view = entities | std::views::drop(2u); 93 | auto hit_brick = 94 | std::ranges::find_if(bricks_view, [&ball](const auto &brick) { return ball.intersects(brick); }); 95 | 96 | if (hit_brick != std::ranges::end(bricks_view)) 97 | { 98 | // we hit a brick so update ball velocity and remove brick entity 99 | ball_velocity.y *= -1.0f; 100 | entities.erase(hit_brick); 101 | } 102 | } 103 | } 104 | 105 | /** 106 | * Helper function to update the ball. Will check if the ball leaves the window and adjust the velocity so it "bounces" 107 | * off walls. 108 | * 109 | * @param ball 110 | * Ball entity to update. 111 | * 112 | * @param velocity 113 | * Ball velocity, will be mutated if ball goes off screen. 114 | */ 115 | void update_ball(cpp::Entity &ball, cpp::Vector2 &velocity) 116 | { 117 | ball.translate(velocity); 118 | 119 | const auto ball_pos = ball.rectangle().position; 120 | 121 | if ((ball_pos.y > 800.0f) || (ball_pos.y < 0.0f)) 122 | { 123 | velocity.y *= -1.0f; 124 | } 125 | 126 | if ((ball_pos.x > 800.0f) || (ball_pos.x < 0.0f)) 127 | { 128 | velocity.x *= -1.0f; 129 | } 130 | } 131 | 132 | /** 133 | * Helper function to update the paddle. 134 | * 135 | * @param paddle 136 | * Paddle entity to update. 137 | * 138 | * @param velocity 139 | * Paddle velocity. 140 | */ 141 | void update_paddle(cpp::Entity &paddle, const cpp::Vector2 &velocity) 142 | { 143 | paddle.translate(velocity); 144 | } 145 | 146 | } 147 | 148 | int main() 149 | { 150 | std::cout << "hello world\n"; 151 | 152 | const cpp::Window window{}; 153 | auto running = true; 154 | 155 | std::vector entities{ 156 | {{{300.0f, 780.0f}, 300.0f, 20.0f}, 0xFFFFFF}, {{{420.0f, 400.0f}, 10.0f, 10.0f}, 0xFFFFFF}}; 157 | 158 | create_brick_row(entities, 50.0f, 0xff0000); 159 | create_brick_row(entities, 80.0f, 0xff0000); 160 | create_brick_row(entities, 110.0f, 0xffa500); 161 | create_brick_row(entities, 140.0f, 0xffa500); 162 | create_brick_row(entities, 170.0f, 0x00ff00); 163 | create_brick_row(entities, 200.0f, 0x00ff00); 164 | 165 | cpp::Vector2 ball_velocity{0.0f, 1.0f}; 166 | cpp::Vector2 paddle_velocity{0.0f, 0.0f}; 167 | const float paddle_speed = 1.0f; 168 | auto left_press = false; 169 | auto right_press = false; 170 | 171 | while (running) 172 | { 173 | for (;;) 174 | { 175 | if (const auto event = window.get_event(); event) 176 | { 177 | using enum cpp::Key; 178 | using enum cpp::KeyState; 179 | 180 | if ((event->key_state == DOWN) && (event->key == ESCAPE)) 181 | { 182 | running = false; 183 | } 184 | else if (event->key == LEFT) 185 | { 186 | left_press = (event->key_state == DOWN) ? true : false; 187 | } 188 | else if (event->key == RIGHT) 189 | { 190 | right_press = (event->key_state == DOWN) ? true : false; 191 | } 192 | } 193 | else 194 | { 195 | break; 196 | } 197 | } 198 | 199 | if ((left_press && right_press) || (!left_press && !right_press)) 200 | { 201 | paddle_velocity.x = 0.0f; 202 | } 203 | else if (left_press) 204 | { 205 | paddle_velocity.x = -paddle_speed; 206 | } 207 | else if (right_press) 208 | { 209 | paddle_velocity.x = paddle_speed; 210 | } 211 | 212 | // scope the references to the paddle and ball, if check_collisions results in an entity being removed then 213 | // that will invalidate our references, so prevent them from being accidentally used later 214 | { 215 | auto &paddle = entities[0]; 216 | auto &ball = entities[1]; 217 | 218 | update_paddle(paddle, paddle_velocity); 219 | update_ball(ball, ball_velocity); 220 | check_collisions(ball, ball_velocity, paddle, entities); 221 | } 222 | 223 | window.render(entities); 224 | } 225 | 226 | std::cout << "goodbye\n"; 227 | 228 | return 0; 229 | } 230 | -------------------------------------------------------------------------------- /Game II/rectangle.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "rectangle.h" 8 | 9 | #include 10 | 11 | #include "vector2.h" 12 | 13 | namespace cpp 14 | { 15 | 16 | Rectangle::Rectangle(const Vector2 &position, float width, float height) 17 | : position(position) 18 | , width(width) 19 | , height(height) 20 | { 21 | } 22 | 23 | void Rectangle::translate(const Vector2 &translation) 24 | { 25 | position += translation; 26 | } 27 | 28 | bool Rectangle::intersects(const Rectangle &rect) const 29 | { 30 | return ( 31 | (position.x < rect.position.x + rect.width) && (position.x + width > rect.position.x) && 32 | (position.y < rect.position.y + rect.height) && (height + position.y > rect.position.y)); 33 | } 34 | 35 | bool operator==(const Rectangle &r1, const Rectangle &r2) 36 | { 37 | return (r1.position == r2.position) && (r1.width == r2.width) && (r1.height == r2.height); 38 | } 39 | 40 | bool operator!=(const Rectangle &r1, const Rectangle &r2) 41 | { 42 | return !(r1 == r2); 43 | } 44 | 45 | std::ostream &operator<<(std::ostream &os, const Rectangle &rect) 46 | { 47 | os << "{ position: " << rect.position << ", w: " << rect.width << ", h: " << rect.height << " }"; 48 | return os; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Game II/rectangle.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "vector2.h" 12 | 13 | namespace cpp 14 | { 15 | 16 | /** 17 | * A Rectangle represents an axis aligned box defined by the coordinates of its upper left corner as well as width and 18 | * height. 19 | */ 20 | class Rectangle 21 | { 22 | public: 23 | /** 24 | * Construct a new Rectangle. 25 | * 26 | * @param position 27 | * Position of rectangle (upper left corner). 28 | * 29 | * @param width 30 | * Width of rectangle. 31 | * 32 | * @param height 33 | * Height of rectangle. 34 | */ 35 | Rectangle(const Vector2 &position, float width, float height); 36 | 37 | /** 38 | * Stream operator. 39 | * 40 | * @param os 41 | * Stream to write to. 42 | * 43 | * @param rect 44 | * Rectangle to write to stream. 45 | * 46 | * @returns 47 | * Reference to supplied stream. 48 | */ 49 | friend std::ostream &operator<<(std::ostream &os, const Rectangle &rect); 50 | 51 | /** 52 | * Translate the position of a rectangle. 53 | * 54 | * @param translation 55 | * Translation amount. 56 | */ 57 | void translate(const Vector2 &translation); 58 | 59 | /** 60 | * Check if another rectangle intersects this. 61 | * 62 | * @param rect 63 | * Rectangle to check for intersection. 64 | * 65 | * @returns 66 | * True if supplied rectangle intersects this, otherwise false. 67 | */ 68 | bool intersects(const Rectangle &rect) const; 69 | 70 | /** Position of upper left corner of rectangle. */ 71 | Vector2 position; 72 | 73 | /** Rectangle width. */ 74 | float width; 75 | 76 | /** Rectangle height. */ 77 | float height; 78 | }; 79 | 80 | /** 81 | * Check if two rectangles are equal. 82 | * 83 | * @param r1 84 | * First rectangle to check. 85 | * 86 | * @param r2 87 | * Second rectangle to check. 88 | * 89 | * @returns 90 | * True if both rectangles are equal, otherwise false. 91 | */ 92 | bool operator==(const Rectangle &r1, const Rectangle &r2); 93 | 94 | /** 95 | * Check if two rectangles are not equal. 96 | * 97 | * @param r1 98 | * First rectangle to check. 99 | * 100 | * @param r2 101 | * Second rectangle to check. 102 | * 103 | * @returns 104 | * True if both rectangles are not equal, otherwise false. 105 | */ 106 | bool operator!=(const Rectangle &r1, const Rectangle &r2); 107 | 108 | // see docs on class definition 109 | std::ostream &operator<<(std::ostream &os, const Rectangle &rect); 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Game II/vector2.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "vector2.h" 8 | 9 | #include 10 | 11 | namespace cpp 12 | { 13 | 14 | Vector2::Vector2() 15 | : Vector2(0.0f, 0.0f) 16 | { 17 | } 18 | 19 | Vector2::Vector2(float x, float y) 20 | : x(x) 21 | , y(y) 22 | { 23 | } 24 | 25 | bool operator==(const Vector2 &v1, const Vector2 &v2) 26 | { 27 | return (v1.x == v2.x) && (v1.y == v2.y); 28 | } 29 | 30 | bool operator!=(const Vector2 &v1, const Vector2 &v2) 31 | { 32 | return !(v1 == v2); 33 | } 34 | 35 | Vector2 operator+(const Vector2 &v1, const Vector2 &v2) 36 | { 37 | Vector2 new_vec{v1}; 38 | new_vec += v2; 39 | return new_vec; 40 | } 41 | 42 | Vector2 &operator+=(Vector2 &v1, const Vector2 &v2) 43 | { 44 | v1.x += v2.x; 45 | v1.y += v2.y; 46 | return v1; 47 | } 48 | 49 | std::ostream &operator<<(std::ostream &os, const Vector2 &v) 50 | { 51 | os << "{ x: " << v.x << ", y: " << v.y << "}"; 52 | return os; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Game II/vector2.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace cpp 12 | { 13 | 14 | /** 15 | * A Vector2 represents a two component (x and y) vector. 16 | */ 17 | class Vector2 18 | { 19 | public: 20 | /** 21 | * Construct a new Vector2, with both components 0.0. 22 | */ 23 | Vector2(); 24 | 25 | /** 26 | * Construct a new Vector2, with supplied component values. 27 | * 28 | * @param x 29 | * X component. 30 | * 31 | * @param y 32 | * Y component. 33 | */ 34 | Vector2(float x, float y); 35 | 36 | /** 37 | * Stream operator. 38 | * 39 | * @param os 40 | * Stream to write to. 41 | * 42 | * @param v 43 | * Vector to write to stream. 44 | * 45 | * @returns 46 | * Reference to supplied stream. 47 | */ 48 | friend std::ostream &operator<<(std::ostream &os, const Vector2 &v); 49 | 50 | /** X component. */ 51 | float x; 52 | 53 | /** Y component. */ 54 | float y; 55 | }; 56 | 57 | /** 58 | * Check if two vectors are equal. 59 | * 60 | * @param v1 61 | * First vector to check. 62 | * 63 | * @param v2 64 | * Second vector to check. 65 | * 66 | * @returns 67 | * True if both vectors are equal, otherwise false. 68 | */ 69 | bool operator==(const Vector2 &v1, const Vector2 &v2); 70 | 71 | /** 72 | * Check if two vectors are not equal. 73 | * 74 | * @param v1 75 | * First vector to check. 76 | * 77 | * @param v2 78 | * Second vector to check. 79 | * 80 | * @returns 81 | * True if both vectors are not equal, otherwise false. 82 | */ 83 | bool operator!=(const Vector2 &v1, const Vector2 &v2); 84 | 85 | /** 86 | * Construct a new vector by adding two supplied vectors. 87 | * 88 | * @param v1 89 | * First vector to add. 90 | * 91 | * @param v2 92 | * Second vector to add. 93 | * 94 | * @returns 95 | * v1 + v2. 96 | */ 97 | Vector2 operator+(const Vector2 &v1, const Vector2 &v2); 98 | 99 | /** 100 | * Add assign one vector to another. 101 | * 102 | * @param v1 103 | * Vector to add to, will be mutated. 104 | * 105 | * @param v2 106 | * Second vector to add. 107 | * 108 | * @returns 109 | * v1 += v2. 110 | */ 111 | Vector2 &operator+=(Vector2 &v1, const Vector2 &v2); 112 | 113 | // see docs on class definition 114 | std::ostream &operator<<(std::ostream &os, const Vector2 &v); 115 | 116 | } 117 | -------------------------------------------------------------------------------- /Game II/window.cpp: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #include "window.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "SDL.h" 15 | 16 | #include "entity.h" 17 | #include "key_event.h" 18 | 19 | namespace 20 | { 21 | 22 | /** 23 | * Helper function to map an SDL key code to an internal type. 24 | * 25 | * @param sql_code 26 | * SDL key code. 27 | * 28 | * @returns 29 | * Internal representation of the supplied key code, or empty optional if no mapping exists. 30 | */ 31 | std::optional map_sdl_key(SDL_Keycode sdl_code) 32 | { 33 | switch (sdl_code) 34 | { 35 | using enum cpp::Key; 36 | 37 | case SDLK_ESCAPE: return ESCAPE; 38 | case SDLK_LEFT: return LEFT; 39 | case SDLK_RIGHT: return RIGHT; 40 | default: return std::nullopt; 41 | } 42 | } 43 | 44 | } 45 | 46 | namespace cpp 47 | { 48 | 49 | Window::Window() 50 | : window_(nullptr, &SDL_DestroyWindow) 51 | , renderer_(nullptr, &SDL_DestroyRenderer) 52 | { 53 | if (::SDL_Init(SDL_INIT_VIDEO) != 0) 54 | { 55 | throw std::runtime_error("failed to init SDL"); 56 | } 57 | 58 | window_.reset( 59 | ::SDL_CreateWindow("cpp_game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 800, SDL_WINDOW_SHOWN)); 60 | if (!window_) 61 | { 62 | throw std::runtime_error("failed to create window"); 63 | } 64 | 65 | renderer_.reset(::SDL_CreateRenderer(window_.get(), -1, 0u)); 66 | if (!renderer_) 67 | { 68 | throw std::runtime_error("failed to create renderer"); 69 | } 70 | } 71 | 72 | std::optional Window::get_event() const 73 | { 74 | std::optional event{}; 75 | 76 | SDL_Event sdl_event = {0}; 77 | if (::SDL_PollEvent(&sdl_event) != 0u) 78 | { 79 | std::optional key_state; 80 | 81 | if (sdl_event.type == SDL_KEYDOWN) 82 | { 83 | key_state = KeyState::DOWN; 84 | } 85 | else if (sdl_event.type == SDL_KEYUP) 86 | { 87 | key_state = KeyState::UP; 88 | } 89 | 90 | // if we got a key state then it's safe to inspect the key code 91 | if (key_state) 92 | { 93 | if (const auto key = map_sdl_key(sdl_event.key.keysym.sym); key) 94 | { 95 | // got state and key - so create the KeyEvent 96 | event = KeyEvent{.key_state = *key_state, .key = *key}; 97 | } 98 | } 99 | } 100 | 101 | return event; 102 | } 103 | 104 | void Window::render(const std::vector &entities) const 105 | { 106 | if (::SDL_SetRenderDrawColor(renderer_.get(), 0x0, 0x0, 0x0, 0xff) != 0) 107 | { 108 | throw std::runtime_error("failed to set render draw colour"); 109 | } 110 | 111 | if (::SDL_RenderClear(renderer_.get()) != 0) 112 | { 113 | throw std::runtime_error("failed to clear renderer"); 114 | } 115 | 116 | for (const auto &entity : entities) 117 | { 118 | const auto entity_rect = entity.rectangle(); 119 | const auto entity_colour = entity.colour(); 120 | 121 | const SDL_Rect sdl_rect = { 122 | .x = static_cast(entity_rect.position.x), 123 | .y = static_cast(entity_rect.position.y), 124 | .w = static_cast(entity_rect.width), 125 | .h = static_cast(entity_rect.height), 126 | }; 127 | 128 | if (::SDL_SetRenderDrawColor(renderer_.get(), entity_colour.r, entity_colour.g, entity_colour.b, 0xff) != 0) 129 | { 130 | throw std::runtime_error("failed to draw entity"); 131 | } 132 | 133 | if (::SDL_RenderFillRect(renderer_.get(), &sdl_rect) != 0) 134 | { 135 | throw std::runtime_error("failed to draw filled rect"); 136 | } 137 | } 138 | 139 | ::SDL_RenderPresent(renderer_.get()); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /Game II/window.h: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////// 2 | // Distributed under the Boost Software License, Version 1.0. // 3 | // (See accompanying file LICENSE or copy at // 4 | // https://www.boost.org/LICENSE_1_0.txt) // 5 | //////////////////////////////////////////////////////////////////////////////// 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "entity.h" 14 | #include "key_event.h" 15 | 16 | struct SDL_Window; 17 | struct SDL_Renderer; 18 | 19 | using SDLWindowDelete = void (*)(SDL_Window *); 20 | using SDLRendererDelete = void (*)(SDL_Renderer *); 21 | 22 | namespace cpp 23 | { 24 | 25 | /** 26 | * Window is responsible for creating and destroying a platform window as well as rendering to it and getting events. 27 | */ 28 | class Window 29 | { 30 | public: 31 | /** 32 | * Construct a new Window. 33 | */ 34 | Window(); 35 | 36 | Window(const Window &) = delete; 37 | Window &operator=(const Window &) = delete; 38 | 39 | Window(Window &&) = default; 40 | Window &operator=(Window &&) = default; 41 | 42 | /** 43 | * Get an event if one is available. 44 | * 45 | * @returns 46 | * A KeyEvent if an event was available, otherwise an empty optional. 47 | */ 48 | std::optional get_event() const; 49 | 50 | /** 51 | * Render a collection of entities. 52 | * 53 | * @param entities 54 | * Entities to render. 55 | */ 56 | void render(const std::vector &entities) const; 57 | 58 | private: 59 | /** SDL window object. */ 60 | std::unique_ptr window_; 61 | 62 | /** SDL renderer object. */ 63 | std::unique_ptr renderer_; 64 | }; 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Game/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | enable_language(ASM_NASM) 2 | set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64) 3 | set(CMAKE_ASM_NASM_LINK_EXECUTABLE "ld -o ") 4 | set(CMAKE_ASM_NASM_FLAGS_DEBUG "-g -Fdwarf") 5 | 6 | set(SOURCE_FILES 7 | graphics.asm 8 | linked_list.asm 9 | main.asm 10 | memory.asm 11 | utils.asm 12 | ) 13 | set_source_files_properties(${SOURCE_FILES} PROPERTIES LANGUAGE ASM_NASM) 14 | 15 | add_executable(asm_game 16 | ${SOURCE_FILES} 17 | ) 18 | 19 | target_link_libraries(asm_game X11) 20 | target_link_options(asm_game PRIVATE --dynamic-linker /lib64/ld-linux-x86-64.so.2) 21 | -------------------------------------------------------------------------------- /Game/graphics.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Distributed under the Boost Software License, Version 1.0. ;; 3 | ;; (See accompanying file LICENSE or copy at ;; 4 | ;; https://www.boost.org/LICENSE_1_0.txt) ;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | global create_window 8 | global try_get_event 9 | 10 | extern XBlackPixel 11 | extern XCheckWindowEvent 12 | extern XClearWindow 13 | extern XCreateGC 14 | extern XCreateSimpleWindow 15 | extern XDefaultRootWindow 16 | extern XDefaultScreen 17 | extern XFillRectangle 18 | extern XFlush 19 | extern XLookupKeysym 20 | extern XMapWindow 21 | extern XNextEvent 22 | extern XSync 23 | extern XOpenDisplay 24 | extern XSelectInput 25 | extern XSetForeground 26 | extern XWhitePixel 27 | 28 | extern assert_not_null 29 | extern assert_null 30 | extern render_begin 31 | extern draw_rectangle 32 | extern render_end 33 | extern print 34 | extern print_num 35 | 36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 37 | ; This file contains functions for creating a window and rendering to it. 38 | 39 | 40 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 41 | ; Create and display an X Window. 42 | ; 43 | create_window: 44 | push rbp 45 | mov rbp, rsp 46 | 47 | ; X11 window setup 48 | 49 | mov rdi, 0x0 50 | call XOpenDisplay 51 | mov [display], rax 52 | mov rdi, rax 53 | lea rsi, [x_open_display_failed] 54 | call assert_not_null 55 | 56 | call XDefaultScreen 57 | mov [screen_number], rax 58 | 59 | mov rdi, [display] 60 | mov rsi, [screen_number] 61 | call XWhitePixel 62 | mov [white_colour], rax 63 | 64 | mov rdi, [display] 65 | mov rsi, [screen_number] 66 | call XBlackPixel 67 | mov [black_colour], rax 68 | 69 | mov rdi, [display] 70 | call XDefaultRootWindow 71 | mov [default_root_window], rax 72 | 73 | mov rdi, [display] 74 | mov rsi, [default_root_window] 75 | mov rdx, 0x0 76 | mov rcx, 0x0 77 | mov r8, 0x320 78 | mov r9, 0x320 79 | mov rax, [black_colour] 80 | push rax 81 | push rax 82 | push 0x0 83 | call XCreateSimpleWindow 84 | mov [window], rax 85 | add rsp, 0x18 86 | 87 | mov rdi, [display] 88 | mov rsi, [window] 89 | mov rdx, 0x20003 90 | call XSelectInput 91 | 92 | mov rdi, [display] 93 | mov rsi, [window] 94 | call XMapWindow 95 | 96 | mov rdi, [display] 97 | mov rsi, [window] 98 | mov rdx, 0x0 99 | mov rcx, 0x0 100 | call XCreateGC 101 | mov [gc], rax 102 | 103 | ; wait until window has appeared 104 | wait_loop_start: 105 | mov rdi, [display] 106 | lea rsi, [event] 107 | call XNextEvent 108 | 109 | mov eax, [event] 110 | cmp rax, 0x13 111 | je wait_loop_end 112 | 113 | jmp wait_loop_start 114 | wait_loop_end: 115 | 116 | pop rbp 117 | ret 118 | 119 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 120 | ; Try and get an event 121 | ; 122 | ; @returns 123 | ; Address of an event, or 0x0 if no event was available. 124 | ; 125 | try_get_event: 126 | push rbp 127 | mov rbp, rsp 128 | 129 | ; see if we want have events 130 | mov rdi, [display] 131 | mov rsi, [window] 132 | mov rdx, 0x03 133 | lea rcx, [event] 134 | call XCheckWindowEvent 135 | 136 | cmp rax, 0x0 137 | je try_get_event_end 138 | 139 | ; we got an event so return pointer to event object 140 | lea rax, [event] 141 | 142 | try_get_event_end: 143 | pop rbp 144 | ret 145 | 146 | ; Perform pre-render tasks 147 | render_begin: 148 | push rbp 149 | mov rbp, rsp 150 | 151 | ; clear window 152 | mov rdi, [display] 153 | mov rsi, [window] 154 | call XClearWindow 155 | 156 | pop rbp 157 | ret 158 | 159 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 160 | ; Draw a rectangle. 161 | ; 162 | ; @param rdi 163 | ; X coord of rectangle 164 | ; 165 | ; @param rsi 166 | ; Y coord of rectangle 167 | ; 168 | ; @param rdx 169 | ; Width of rectangle 170 | ; 171 | ; @param rcx 172 | ; Height of rectangle 173 | ; 174 | draw_rectangle: 175 | push rbp 176 | mov rbp, rsp 177 | 178 | ; push args to stack so we can easily pop them into the correct registers 179 | push rcx 180 | push rdx 181 | push rsi 182 | push rdi 183 | 184 | ; set foreground color for drawing 185 | mov rdi, [display] 186 | mov rsi, [gc] 187 | mov rdx, [white_colour] 188 | call XSetForeground 189 | 190 | ; draw paddle 191 | mov rdi, [display] 192 | mov rsi, [window] 193 | mov rdx, [gc] 194 | pop rcx 195 | pop r8 196 | pop r9 ; note that the last arg is now at at the top of the stack 197 | call XFillRectangle 198 | add rsp, 0x8 199 | 200 | pop rbp 201 | ret 202 | 203 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 204 | ; Perform post-render tasks 205 | ; 206 | render_end: 207 | push rbp 208 | mov rbp, rsp 209 | 210 | ; ensure all draw commands are flushed 211 | mov rdi, [display] 212 | call XFlush 213 | 214 | pop rbp 215 | ret 216 | 217 | section .data 218 | display: dq 0x0 219 | screen_number: dq 0x0 220 | black_colour: dq 0x0 221 | white_colour: dq 0x0 222 | default_root_window: dq 0x0 223 | window: dq 0x0 224 | gc: dq 0x0 225 | event: resb 0xc0 226 | 227 | section .rodata 228 | hello_world: db "hello world", 0xa, 0x0 229 | goodbye: db "goodbye", 0xa, 0x0 230 | sleep_for: db "sleep_for: ", 0x0 231 | x_open_display_failed: db "XOpenDisplay failed", 0xa, 0x0 232 | x_select_input_failed: db "XSelectInput failed", 0xa, 0x0 233 | x_set_foreground_failed: db "XSetForeground failed", 0xa, 0x0 234 | -------------------------------------------------------------------------------- /Game/linked_list.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Distributed under the Boost Software License, Version 1.0. ;; 3 | ;; (See accompanying file LICENSE or copy at ;; 4 | ;; https://www.boost.org/LICENSE_1_0.txt) ;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | global linked_list_init 8 | global linked_list_iterator 9 | global linked_list_iterator_advance 10 | global linked_list_iterator_remove 11 | global linked_list_iterator_value 12 | global linked_list_push_back 13 | 14 | extern memory_malloc 15 | 16 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 17 | ; Simple linked list data structure. Consists of a head node then optional data nodes. 18 | ; Each node has the following layout: 19 | ; +-------+ 20 | ; | value | = 8 bytes 21 | ; +-------+ 22 | ; | ptr | = 8 bytes 23 | ; +-------+ 24 | ; 25 | ; This means that each node can store 8 bytes of data, which could be anything, even a pointer to a larger allocated 26 | ; block of data 27 | 28 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 29 | ; Create a new linked list. 30 | ; 31 | ; @returns 32 | ; A handle to the linked list which can be passed to further linked list methods. 33 | ; 34 | linked_list_init: 35 | push rbp 36 | mov rbp, rsp 37 | 38 | mov rdi, 0x0 39 | call allocate_node ; create the head node 40 | 41 | ; we return the head node as the handle 42 | 43 | pop rbp 44 | ret 45 | 46 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 47 | ; Insert a new value to the back of the linked list. 48 | ; 49 | ; @param rdi 50 | ; Handle to linked list to insert into. 51 | ; 52 | ; @param rsi 53 | ; Value to insert. 54 | ; 55 | ; @returns 56 | ; Address if newly created node. 57 | ; 58 | linked_list_push_back: 59 | push rbp 60 | mov rbp, rsp 61 | 62 | mov rbx, rdi 63 | 64 | ; find end of list 65 | linked_list_push_back_find_end: 66 | mov rcx, [rbx + 0x8] ; get next pointer 67 | cmp rcx, 0x0 ; if null then we are at the last node 68 | je linked_list_push_back_do_insert 69 | 70 | add rbx, 0x10 71 | jmp linked_list_push_back_find_end 72 | 73 | linked_list_push_back_do_insert: 74 | push rbx 75 | mov rdi, rsi 76 | call allocate_node ; allocate new node 77 | 78 | pop rbx 79 | mov [rbx + 0x8], rax ; set new node as next of last node 80 | mov rax, [rbx + 0x8] ; set return value as address of new node 81 | 82 | pop rbp 83 | ret 84 | 85 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 86 | ; Get an iterator to the start of the linked list. This is a handle that can ba passed to other iterator functions. 87 | ; 88 | ; @rdi 89 | ; Handle to list to get iterator for. 90 | ; 91 | ; @returns 92 | ; Iterator handle. 93 | ; 94 | linked_list_iterator: 95 | push rbp 96 | mov rbp, rsp 97 | 98 | call linked_list_iterator_advance ; we can cheat here by just returning the address of the first node after the head 99 | 100 | pop rbp 101 | ret 102 | 103 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 104 | ; Remove a node from the linked list. 105 | ; 106 | ; @param rdi 107 | ; Handle to linked list to remove node from. 108 | ; 109 | ; @parma rsi 110 | ; Iterator to remove 111 | ; 112 | linked_list_iterator_remove: 113 | push rbp 114 | mov rbp, rsp 115 | 116 | linked_list_remove_find_begin: 117 | mov rax, [rdi + 8] 118 | cmp rax, 0x0 119 | je linked_list_remove_end 120 | 121 | cmp rax, rsi 122 | je linked_list_remove_find_end 123 | 124 | mov rdi, rax 125 | jmp linked_list_remove_find_begin 126 | 127 | linked_list_remove_find_end: 128 | 129 | mov rbx, [rsi + 8] ; get next of node we are removing 130 | mov [rdi + 8], rbx ; set prev nodes next to next of removing node 131 | 132 | linked_list_remove_end: 133 | pop rbp 134 | ret 135 | 136 | 137 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 138 | ; Advance an iterator. 139 | ; 140 | ; @param rdi 141 | ; Handle to iterator to advance. 142 | ; 143 | ; @returns 144 | ; Handle to advanced iterator. 145 | ; 146 | linked_list_iterator_advance: 147 | push rbp 148 | mov rbp, rsp 149 | 150 | mov rax, [rdi + 0x8] 151 | 152 | pop rbp 153 | ret 154 | 155 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 156 | ; Get the value from an iterator. 157 | ; 158 | ; @param rdi 159 | ; Handle to iterator to get value for. 160 | ; 161 | ; @returns 162 | ; Value stored in node iterator is referencing. 163 | ; 164 | linked_list_iterator_value: 165 | push rbp 166 | mov rbp, rsp 167 | 168 | mov rax, [rdi] 169 | 170 | pop rbp 171 | ret 172 | 173 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 174 | ; Allocate a new node and store a value in it. 175 | ; 176 | ; @param rdi 177 | ; Value to store in node 178 | ; 179 | ; @returns 180 | ; Address of allocated node. 181 | ; 182 | allocate_node: 183 | push rbp 184 | mov rbp, rsp 185 | 186 | push rdi 187 | 188 | mov rdi, 0x10 189 | call memory_malloc ; allocate space for node 190 | 191 | pop rdi 192 | mov rbx, 0x0 193 | mov [rax], rdi ; store value in node 194 | mov [rax + 0x8], rbx ; set next to be null 195 | 196 | pop rbp 197 | ret 198 | -------------------------------------------------------------------------------- /Game/memory.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Distributed under the Boost Software License, Version 1.0. ;; 3 | ;; (See accompanying file LICENSE or copy at ;; 4 | ;; https://www.boost.org/LICENSE_1_0.txt) ;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | global memory_mmap 8 | global memory_malloc 9 | 10 | extern assert_not_null 11 | 12 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 13 | ; This file contains various utilities for dynamically allocating memory. 14 | 15 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 16 | ; Map new pages into the process. 17 | ; 18 | ; @param rdi 19 | ; Number of bytes to map. 20 | ; 21 | ; @returns 22 | ; Address of allocated memory. 23 | ; 24 | memory_mmap: 25 | push rbp 26 | mov rbp, rsp 27 | 28 | push rdi 29 | 30 | mov rax, 0x9 31 | mov rdi, 0x0 ; kernel chooses address 32 | pop rsi ; number of bytes to map 33 | mov rdx, 0x3 ; PROT_READ | PROT_WRITE 34 | mov r10, 0x22 ; MAP_PRIVATE | MAP_ANONYMOUS 35 | mov r8, 0x0 ; no backing file 36 | mov r9, 0x0 ; no offset 37 | 38 | syscall 39 | 40 | push rax 41 | 42 | mov rdi, rax 43 | sub rdi, 0xffffffffffffffff ; check MAP_FAILED was not returned 44 | lea rsi, [mmap_failed] 45 | call assert_not_null 46 | pop rax 47 | 48 | pop rbp 49 | ret 50 | 51 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 52 | ; Simple implementation of malloc. 53 | ; 54 | ; Note that there is no equivalent of free, this just allocates memory from a large static buffer. 55 | ; 56 | ; @param rdi 57 | ; Number of bytes to allocate. 58 | ; 59 | ; @returns 60 | ; Address of allocated memory. 61 | ; 62 | memory_malloc: 63 | push rbp 64 | mov rbp, rsp 65 | 66 | push rdi 67 | 68 | ; if this is the first call then allocate a large fixed size buffer to "malloc" from 69 | mov rax, [malloc_init] 70 | cmp rax, 0x0 71 | jne malloc_do_init_done 72 | 73 | mov rdi, 4096000 74 | call memory_mmap 75 | 76 | mov [malloc_memory], rax 77 | mov rax, 0x1 78 | mov [malloc_init], rax 79 | malloc_do_init_done: 80 | 81 | pop rdi 82 | 83 | mov rax, [malloc_memory] ; get address from head of buffer 84 | mov rbx, rax 85 | add rbx, rdi ; advance buffer by requested size 86 | mov [malloc_memory], rbx 87 | 88 | pop rbp 89 | ret 90 | 91 | section .data 92 | malloc_init: dq 0x0 93 | malloc_memory: dq 0x0 94 | 95 | section .rodata 96 | mmap_failed: db "mmap failed", 0xa, 0x0 97 | -------------------------------------------------------------------------------- /Game/utils.asm: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ;; Distributed under the Boost Software License, Version 1.0. ;; 3 | ;; (See accompanying file LICENSE or copy at ;; 4 | ;; https://www.boost.org/LICENSE_1_0.txt) ;; 5 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 6 | 7 | global assert_not_null 8 | global assert_null 9 | global exit 10 | global game_malloc 11 | global game_mmap 12 | global get_time 13 | global print 14 | global print_num 15 | global sleep_ms 16 | 17 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 18 | ; This file contains various utilities. 19 | 20 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 21 | ; Print a string to STDOUT. 22 | ; 23 | ; @param rdi 24 | ; Address of null terminated string to print. 25 | ; 26 | ; @returns 27 | ; Number of bytes output. 28 | ; 29 | print: 30 | push rbp 31 | mov rbp, rsp 32 | 33 | mov r10, rdi ; save off string address 34 | mov r9, rdi ; iterator register for string 35 | movzx rax, byte [r9] ; load first byte 36 | mov rcx, 0x0 ; accumulator for string length 37 | 38 | count_null_start: 39 | cmp rax, 0x0 ; are we at the null byte? 40 | je count_null_end 41 | 42 | inc rcx ; increment accumulator 43 | inc r9 ; move to next byte 44 | movzx rax, byte [r9] ; load byte 45 | jmp count_null_start 46 | 47 | count_null_end: 48 | ; syscall to write string to stdout 49 | mov rax, 0x1 50 | mov rdi, 0x1; 51 | mov rsi, r10 52 | mov rdx, rcx 53 | syscall 54 | 55 | pop rbp 56 | ret 57 | 58 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 59 | ; Print an integer to STDOUT (with a new line). 60 | ; 61 | ; @param rdi 62 | ; Unsigned number to print. 63 | ; 64 | print_num: 65 | push rbp 66 | mov rbp, rsp 67 | sub rsp, 0x15 ; get stack space for two buffers, one to convert the number into a string (in reverse order)] 68 | ; and another to reverse the string into 69 | 70 | mov r9, rdi ; r9 will be the mutable copy of the input number 71 | mov rdx, rdi 72 | mov rcx, 0x0 ; accumulator for string length 73 | 74 | mov rdi, rsp ; set destination as start of first buffer 75 | 76 | write_loop_start: 77 | 78 | mov rax, r9 ; load number to be divided 79 | mov rdx, 0 ; zero out remainder 80 | mov r10, 0xa ; divisor by 10 81 | div r10 ; rdx = remainder, rax = quotient 82 | 83 | mov r11, 0x30 84 | add rdx, r11 ; add 0x30 to remainder to get ASCII code for number 85 | 86 | mov [rdi], dl ; write ASCII byte to buffer 87 | inc rcx ; increment how many characters have been written 88 | 89 | cmp rax, 0x0 ; check if we have reached the end 90 | je write_loop_end 91 | 92 | inc rdi 93 | mov r9, rax ; load remainder into r9 so it can be divided again 94 | jmp write_loop_start 95 | 96 | write_loop_end: 97 | 98 | mov rsi, rdi ; move destination into source so we can reverse it 99 | mov rdi, rsp 100 | add rdi, 0xa ; set destination to start of second buffer 101 | 102 | reverse_loop_start: 103 | cmp rcx, 0x0 104 | je reverse_loop_end 105 | 106 | movzx rax, byte[rsi] 107 | mov [rdi], al ; write ascii character into second buffer 108 | dec rsi 109 | inc rdi 110 | 111 | dec rcx; ; keep track of how many characters we've reversed 112 | jmp reverse_loop_start 113 | reverse_loop_end: 114 | 115 | mov rax, 0xa 116 | mov [rdi], al ; write newline character into the end 117 | 118 | mov rdi, rsp 119 | add rdi, 0xa ; print second buffer 120 | call print 121 | 122 | leave 123 | ret 124 | 125 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 126 | ; Assert the input is not null. 127 | ; 128 | ; @param rdi 129 | ; Value to check is not null. 130 | ; 131 | ; @param rsi 132 | ; Pointer to error message string. 133 | ; 134 | assert_not_null: 135 | push rbp 136 | mov rbp, rsp 137 | 138 | cmp rdi, 0x0 139 | jne assert_not_null_end 140 | 141 | mov rdi, rsi 142 | call print 143 | 144 | mov rdi, 0x1 145 | call exit 146 | 147 | assert_not_null_end: 148 | 149 | pop rbp 150 | ret 151 | 152 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 153 | ; Assert the input is null. 154 | ; 155 | ; @param rdi 156 | ; Value to check is null. 157 | ; 158 | ; @param rsi 159 | ; Pointer to error message string. 160 | ; 161 | assert_null: 162 | push rbp 163 | mov rbp, rsp 164 | 165 | cmp rdi, 0x0 166 | je assert_null_end 167 | 168 | mov rdi, rsi 169 | call print 170 | 171 | mov rdi, 0x1 172 | call exit 173 | 174 | assert_null_end: 175 | 176 | pop rbp 177 | ret 178 | 179 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 180 | ; Exit the program. 181 | ; 182 | ; @param rdi 183 | ; Exit code. 184 | ; 185 | exit: 186 | mov rax, 0x3c 187 | syscall 188 | 189 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 190 | ; Sleep the current process for the supplied number of milliseconds. 191 | ; 192 | ; @param rdi 193 | ; Number of milliseconds to sleep for. 194 | ; 195 | sleep_ms: 196 | push rbp 197 | mov rbp, rsp 198 | 199 | imul rdi, rdi, 1000000 ; convert supplied ms to ns 200 | xor rax, rax 201 | ; recreate struct timepec on the stack 202 | push rdi ; tv_nsec 203 | push rax ; tv_sec 204 | 205 | ; nanosleep syscall 206 | mov rax, 0x23 207 | mov rdi, rsp 208 | mov rsi, 0x0 209 | syscall 210 | 211 | add rsp, 16 212 | 213 | pop rbp 214 | ret 215 | 216 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 217 | ; Get the time since epoch in milliseconds. 218 | ; 219 | ; @returns 220 | ; Milliseconds since epoch. 221 | ; 222 | get_time: 223 | push rbp 224 | mov rbp, rsp 225 | 226 | ; create empty timeval struct on the stack 227 | push 0x0 ; tv_usec 228 | push 0x0 ; tv_sec 229 | 230 | ; gettimeofday syscall 231 | mov rax, 0x60 232 | mov rdi, rsp 233 | mov rsi, 0x0 234 | syscall 235 | 236 | pop rax ; seconds 237 | pop rbx ; microseconds 238 | 239 | imul rax, rax, 1000000 ; convert seconds to microseconds 240 | add rax, rbx ; add microseconds 241 | mov rdx, 0x0 242 | mov rbx, 1000 243 | div rbx ; convert to milliseconds 244 | 245 | pop rbp 246 | ret 247 | -------------------------------------------------------------------------------- /GetCompiler.c: -------------------------------------------------------------------------------- 1 | 2 | /* Return the compiler identification, if possible. */ 3 | 4 | #include "Python.h" 5 | 6 | #ifndef COMPILER 7 | 8 | // Note the __clang__ conditional has to come before the __GNUC__ one because 9 | // clang pretends to be GCC. 10 | #if defined(__clang__) 11 | #define COMPILER "[Clang " __clang_version__ "]" 12 | #elif defined(__GNUC__) 13 | #define COMPILER "[GCC " __VERSION__ "]" 14 | // Generic fallbacks. 15 | #elif defined(__cplusplus) 16 | #define COMPILER "[C++]" 17 | #else 18 | #define COMPILER "[C]" 19 | #endif 20 | 21 | #endif /* !COMPILER */ 22 | 23 | const char * 24 | Py_GetCompiler(void) 25 | { 26 | return COMPILER; 27 | } 28 | -------------------------------------------------------------------------------- /GetCopyRight.c: -------------------------------------------------------------------------------- 1 | /* Return the copyright string. This is updated manually. */ 2 | #include "Python.h" 3 | 4 | static const char cprt[] = 5 | "\ 6 | Copyright (c) 2001-2023 Python Software Foundation.\n\ 7 | All Rights Reserved.\n\ 8 | \n\ 9 | Copyright (c) 2000 BeOpen.com.\n\ 10 | All Rights Reserved.\n\ 11 | \n\ 12 | Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\ 13 | All Rights Reserved.\n\ 14 | \n\ 15 | Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\ 16 | All Rights Reserved."; 17 | 18 | const char * 19 | Py_GetCopyright(void) 20 | { 21 | return cprt; 22 | } 23 | -------------------------------------------------------------------------------- /GetCopyright.c: -------------------------------------------------------------------------------- 1 | /* Return the copyright string. This is updated manually. */ 2 | 3 | #include "Python.h" 4 | 5 | static const char cprt[] = 6 | "\ 7 | Copyright (c) 2001-2023 Python Software Foundation.\n\ 8 | All Rights Reserved.\n\ 9 | \n\ 10 | Copyright (c) 2000 BeOpen.com.\n\ 11 | All Rights Reserved.\n\ 12 | \n\ 13 | Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\ 14 | All Rights Reserved.\n\ 15 | \n\ 16 | Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\ 17 | All Rights Reserved."; 18 | 19 | const char * 20 | Py_GetCopyright(void) 21 | { 22 | return cprt; 23 | } 24 | -------------------------------------------------------------------------------- /GetOpt.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------* 2 | * 3 | * 4 | * C++ Library 5 | * 6 | * Copyright 1992-1994, David Gottner 7 | * 8 | * All Rights Reserved 9 | * 10 | * Permission to use, copy, modify, and distribute this software and its 11 | * documentation for any purpose and without fee is hereby granted, 12 | * provided that the above copyright notice, this permission notice and 13 | * the following disclaimer notice appear unmodified in all copies. 14 | * 15 | * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I 17 | * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 18 | * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER 19 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | *---------------------------------------------------------------------------*/ 22 | 23 | /* Modified to support --help and --version, as well as /? on Windows 24 | * by Georg Brandl. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "pycore_getopt.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | int _PyOS_opterr = 1; /* generate error messages */ 37 | Py_ssize_t _PyOS_optind = 1; /* index into argv array */ 38 | const wchar_t *_PyOS_optarg = NULL; /* optional argument */ 39 | 40 | static const wchar_t *opt_ptr = L""; 41 | 42 | /* Python command line short and long options */ 43 | 44 | #define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?" 45 | 46 | static const _PyOS_LongOption longopts[] = { 47 | /* name, has_arg, val (used in switch in initconfig.c) */ 48 | {L"check-hash-based-pycs", 1, 0}, 49 | {L"help-all", 0, 1}, 50 | {L"help-env", 0, 2}, 51 | {L"help-xoptions", 0, 3}, 52 | {NULL, 0, -1}, /* sentinel */ 53 | }; 54 | 55 | 56 | void _PyOS_ResetGetOpt(void) 57 | { 58 | _PyOS_opterr = 1; 59 | _PyOS_optind = 1; 60 | _PyOS_optarg = NULL; 61 | opt_ptr = L""; 62 | } 63 | 64 | int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex) 65 | { 66 | wchar_t *ptr; 67 | wchar_t option; 68 | 69 | if (*opt_ptr == '\0') { 70 | 71 | if (_PyOS_optind >= argc) 72 | return -1; 73 | #ifdef MS_WINDOWS 74 | else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) { 75 | ++_PyOS_optind; 76 | return 'h'; 77 | } 78 | #endif 79 | 80 | else if (argv[_PyOS_optind][0] != L'-' || 81 | argv[_PyOS_optind][1] == L'\0' /* lone dash */ ) 82 | return -1; 83 | 84 | else if (wcscmp(argv[_PyOS_optind], L"--") == 0) { 85 | ++_PyOS_optind; 86 | return -1; 87 | } 88 | 89 | else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) { 90 | ++_PyOS_optind; 91 | return 'h'; 92 | } 93 | 94 | else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) { 95 | ++_PyOS_optind; 96 | return 'V'; 97 | } 98 | 99 | opt_ptr = &argv[_PyOS_optind++][1]; 100 | } 101 | 102 | if ((option = *opt_ptr++) == L'\0') 103 | return -1; 104 | 105 | if (option == L'-') { 106 | // Parse long option. 107 | if (*opt_ptr == L'\0') { 108 | if (_PyOS_opterr) { 109 | fprintf(stderr, "expected long option\n"); 110 | } 111 | return -1; 112 | } 113 | *longindex = 0; 114 | const _PyOS_LongOption *opt; 115 | for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) { 116 | if (!wcscmp(opt->name, opt_ptr)) 117 | break; 118 | } 119 | if (!opt->name) { 120 | if (_PyOS_opterr) { 121 | fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); 122 | } 123 | return '_'; 124 | } 125 | opt_ptr = L""; 126 | if (!opt->has_arg) { 127 | return opt->val; 128 | } 129 | if (_PyOS_optind >= argc) { 130 | if (_PyOS_opterr) { 131 | fprintf(stderr, "Argument expected for the %ls options\n", 132 | argv[_PyOS_optind - 1]); 133 | } 134 | return '_'; 135 | } 136 | _PyOS_optarg = argv[_PyOS_optind++]; 137 | return opt->val; 138 | } 139 | 140 | if (option == 'J') { 141 | if (_PyOS_opterr) { 142 | fprintf(stderr, "-J is reserved for Jython\n"); 143 | } 144 | return '_'; 145 | } 146 | 147 | if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) { 148 | if (_PyOS_opterr) { 149 | fprintf(stderr, "Unknown option: -%c\n", (char)option); 150 | } 151 | return '_'; 152 | } 153 | 154 | if (*(ptr + 1) == L':') { 155 | if (*opt_ptr != L'\0') { 156 | _PyOS_optarg = opt_ptr; 157 | opt_ptr = L""; 158 | } 159 | 160 | else { 161 | if (_PyOS_optind >= argc) { 162 | if (_PyOS_opterr) { 163 | fprintf(stderr, 164 | "Argument expected for the -%c option\n", (char)option); 165 | } 166 | return '_'; 167 | } 168 | 169 | _PyOS_optarg = argv[_PyOS_optind++]; 170 | } 171 | } 172 | 173 | return option; 174 | } 175 | 176 | #ifdef __cplusplus 177 | } 178 | #endif 179 | -------------------------------------------------------------------------------- /GetPlatForm.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | 4 | #ifndef PLATFORM 5 | #define PLATFORM "unknown" 6 | #endif 7 | 8 | const char * 9 | Py_GetPlatform(void) 10 | { 11 | return PLATFORM; 12 | } 13 | -------------------------------------------------------------------------------- /GetVersion.c: -------------------------------------------------------------------------------- 1 | /* Return the full version string. */ 2 | 3 | #include "Python.h" 4 | 5 | #include "patchlevel.h" 6 | 7 | static int initialized = 0; 8 | static char version[250]; 9 | 10 | void _Py_InitVersion(void) 11 | { 12 | if (initialized) { 13 | return; 14 | } 15 | initialized = 1; 16 | PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s", 17 | PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); 18 | } 19 | 20 | const char * 21 | Py_GetVersion(void) 22 | { 23 | _Py_InitVersion(); 24 | return version; 25 | } 26 | 27 | // Export the Python hex version as a constant. 28 | const unsigned long Py_Version = PY_VERSION_HEX; 29 | -------------------------------------------------------------------------------- /Get_Compiler.c: -------------------------------------------------------------------------------- 1 | 2 | /* Return the compiler identification, if possible. */ 3 | 4 | #include "Python.h" 5 | 6 | #ifndef COMPILER 7 | 8 | // Note the __clang__ conditional has to come before the __GNUC__ one because 9 | // clang pretends to be GCC. 10 | #if defined(__clang__) 11 | #define COMPILER "[Clang " __clang_version__ "]" 12 | #elif defined(__GNUC__) 13 | #define COMPILER "[GCC " __VERSION__ "]" 14 | // Generic fallbacks. 15 | #elif defined(__cplusplus) 16 | #define COMPILER "[C++]" 17 | #else 18 | #define COMPILER "[C]" 19 | #endif 20 | 21 | #endif /* !COMPILER */ 22 | 23 | const char * 24 | Py_GetCompiler(void) 25 | { 26 | return COMPILER; 27 | } 28 | -------------------------------------------------------------------------------- /Get_Opt.c: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------* 2 | * 3 | * 4 | * C++ Library 5 | * 6 | * Copyright 1992-1994, David Gottner 7 | * 8 | * All Rights Reserved 9 | * 10 | * Permission to use, copy, modify, and distribute this software and its 11 | * documentation for any purpose and without fee is hereby granted, 12 | * provided that the above copyright notice, this permission notice and 13 | * the following disclaimer notice appear unmodified in all copies. 14 | * 15 | * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I 17 | * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 18 | * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER 19 | * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | *---------------------------------------------------------------------------*/ 22 | 23 | /* Modified to support --help and --version, as well as /? on Windows 24 | * by Georg Brandl. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "pycore_getopt.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | int _PyOS_opterr = 1; /* generate error messages */ 37 | Py_ssize_t _PyOS_optind = 1; /* index into argv array */ 38 | const wchar_t *_PyOS_optarg = NULL; /* optional argument */ 39 | 40 | static const wchar_t *opt_ptr = L""; 41 | 42 | /* Python command line short and long options */ 43 | 44 | #define SHORT_OPTS L"bBc:dEhiIJm:OPqRsStuvVW:xX:?" 45 | 46 | static const _PyOS_LongOption longopts[] = { 47 | /* name, has_arg, val (used in switch in initconfig.c) */ 48 | {L"check-hash-based-pycs", 1, 0}, 49 | {L"help-all", 0, 1}, 50 | {L"help-env", 0, 2}, 51 | {L"help-xoptions", 0, 3}, 52 | {NULL, 0, -1}, /* sentinel */ 53 | }; 54 | 55 | 56 | void _PyOS_ResetGetOpt(void) 57 | { 58 | _PyOS_opterr = 1; 59 | _PyOS_optind = 1; 60 | _PyOS_optarg = NULL; 61 | opt_ptr = L""; 62 | } 63 | 64 | int _PyOS_GetOpt(Py_ssize_t argc, wchar_t * const *argv, int *longindex) 65 | { 66 | wchar_t *ptr; 67 | wchar_t option; 68 | 69 | if (*opt_ptr == '\0') { 70 | 71 | if (_PyOS_optind >= argc) 72 | return -1; 73 | #ifdef MS_WINDOWS 74 | else if (wcscmp(argv[_PyOS_optind], L"/?") == 0) { 75 | ++_PyOS_optind; 76 | return 'h'; 77 | } 78 | #endif 79 | 80 | else if (argv[_PyOS_optind][0] != L'-' || 81 | argv[_PyOS_optind][1] == L'\0' /* lone dash */ ) 82 | return -1; 83 | 84 | else if (wcscmp(argv[_PyOS_optind], L"--") == 0) { 85 | ++_PyOS_optind; 86 | return -1; 87 | } 88 | 89 | else if (wcscmp(argv[_PyOS_optind], L"--help") == 0) { 90 | ++_PyOS_optind; 91 | return 'h'; 92 | } 93 | 94 | else if (wcscmp(argv[_PyOS_optind], L"--version") == 0) { 95 | ++_PyOS_optind; 96 | return 'V'; 97 | } 98 | 99 | opt_ptr = &argv[_PyOS_optind++][1]; 100 | } 101 | 102 | if ((option = *opt_ptr++) == L'\0') 103 | return -1; 104 | 105 | if (option == L'-') { 106 | // Parse long option. 107 | if (*opt_ptr == L'\0') { 108 | if (_PyOS_opterr) { 109 | fprintf(stderr, "expected long option\n"); 110 | } 111 | return -1; 112 | } 113 | *longindex = 0; 114 | const _PyOS_LongOption *opt; 115 | for (opt = &longopts[*longindex]; opt->name; opt = &longopts[++(*longindex)]) { 116 | if (!wcscmp(opt->name, opt_ptr)) 117 | break; 118 | } 119 | if (!opt->name) { 120 | if (_PyOS_opterr) { 121 | fprintf(stderr, "unknown option %ls\n", argv[_PyOS_optind - 1]); 122 | } 123 | return '_'; 124 | } 125 | opt_ptr = L""; 126 | if (!opt->has_arg) { 127 | return opt->val; 128 | } 129 | if (_PyOS_optind >= argc) { 130 | if (_PyOS_opterr) { 131 | fprintf(stderr, "Argument expected for the %ls options\n", 132 | argv[_PyOS_optind - 1]); 133 | } 134 | return '_'; 135 | } 136 | _PyOS_optarg = argv[_PyOS_optind++]; 137 | return opt->val; 138 | } 139 | 140 | if (option == 'J') { 141 | if (_PyOS_opterr) { 142 | fprintf(stderr, "-J is reserved for Jython\n"); 143 | } 144 | return '_'; 145 | } 146 | 147 | if ((ptr = wcschr(SHORT_OPTS, option)) == NULL) { 148 | if (_PyOS_opterr) { 149 | fprintf(stderr, "Unknown option: -%c\n", (char)option); 150 | } 151 | return '_'; 152 | } 153 | 154 | if (*(ptr + 1) == L':') { 155 | if (*opt_ptr != L'\0') { 156 | _PyOS_optarg = opt_ptr; 157 | opt_ptr = L""; 158 | } 159 | 160 | else { 161 | if (_PyOS_optind >= argc) { 162 | if (_PyOS_opterr) { 163 | fprintf(stderr, 164 | "Argument expected for the -%c option\n", (char)option); 165 | } 166 | return '_'; 167 | } 168 | 169 | _PyOS_optarg = argv[_PyOS_optind++]; 170 | } 171 | } 172 | 173 | return option; 174 | } 175 | 176 | #ifdef __cplusplus 177 | } 178 | #endif 179 | -------------------------------------------------------------------------------- /Get_Plat_Form.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | 4 | #ifndef PLATFORM 5 | #define PLATFORM "unknown" 6 | #endif 7 | 8 | const char * 9 | Py_GetPlatform(void) 10 | { 11 | return PLATFORM; 12 | } 13 | -------------------------------------------------------------------------------- /Getversion.c: -------------------------------------------------------------------------------- 1 | 2 | /* Return the full version string. */ 3 | 4 | #include "Python.h" 5 | 6 | #include "patchlevel.h" 7 | 8 | static int initialized = 0; 9 | static char version[250]; 10 | 11 | void _Py_InitVersion(void) 12 | { 13 | if (initialized) { 14 | return; 15 | } 16 | initialized = 1; 17 | PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s", 18 | PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); 19 | } 20 | 21 | const char * 22 | Py_GetVersion(void) 23 | { 24 | _Py_InitVersion(); 25 | return version; 26 | } 27 | 28 | // Export the Python hex version as a constant. 29 | const unsigned long Py_Version = PY_VERSION_HEX; 30 | -------------------------------------------------------------------------------- /ImPortdl.c: -------------------------------------------------------------------------------- 1 | 2 | /* Support for dynamic loading of extension modules */ 3 | 4 | #include "Python.h" 5 | #include "pycore_call.h" 6 | #include "pycore_import.h" 7 | #include "pycore_pystate.h" 8 | #include "pycore_runtime.h" 9 | 10 | /* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is 11 | supported on this platform. configure will then compile and link in one 12 | of the dynload_*.c files, as appropriate. We will call a function in 13 | those modules to get a function pointer to the module's init function. 14 | */ 15 | #ifdef HAVE_DYNAMIC_LOADING 16 | 17 | #include "importdl.h" 18 | 19 | #ifdef MS_WINDOWS 20 | extern dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, 21 | const char *shortname, 22 | PyObject *pathname, 23 | FILE *fp); 24 | #else 25 | extern dl_funcptr _PyImport_FindSharedFuncptr(const char *prefix, 26 | const char *shortname, 27 | const char *pathname, FILE *fp); 28 | #endif 29 | 30 | static const char * const ascii_only_prefix = "PyInit"; 31 | static const char * const nonascii_prefix = "PyInitU"; 32 | 33 | /* Get the variable part of a module's export symbol name. 34 | * Returns a bytes instance. For non-ASCII-named modules, the name is 35 | * encoded as per PEP 489. 36 | * The hook_prefix pointer is set to either ascii_only_prefix or 37 | * nonascii_prefix, as appropriate. 38 | */ 39 | static PyObject * 40 | get_encoded_name(PyObject *name, const char **hook_prefix) { 41 | PyObject *tmp; 42 | PyObject *encoded = NULL; 43 | PyObject *modname = NULL; 44 | Py_ssize_t name_len, lastdot; 45 | 46 | /* Get the short name (substring after last dot) */ 47 | name_len = PyUnicode_GetLength(name); 48 | if (name_len < 0) { 49 | return NULL; 50 | } 51 | lastdot = PyUnicode_FindChar(name, '.', 0, name_len, -1); 52 | if (lastdot < -1) { 53 | return NULL; 54 | } else if (lastdot >= 0) { 55 | tmp = PyUnicode_Substring(name, lastdot + 1, name_len); 56 | if (tmp == NULL) 57 | return NULL; 58 | name = tmp; 59 | /* "name" now holds a new reference to the substring */ 60 | } else { 61 | Py_INCREF(name); 62 | } 63 | 64 | /* Encode to ASCII or Punycode, as needed */ 65 | encoded = PyUnicode_AsEncodedString(name, "ascii", NULL); 66 | if (encoded != NULL) { 67 | *hook_prefix = ascii_only_prefix; 68 | } else { 69 | if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { 70 | PyErr_Clear(); 71 | encoded = PyUnicode_AsEncodedString(name, "punycode", NULL); 72 | if (encoded == NULL) { 73 | goto error; 74 | } 75 | *hook_prefix = nonascii_prefix; 76 | } else { 77 | goto error; 78 | } 79 | } 80 | 81 | /* Replace '-' by '_' */ 82 | modname = _PyObject_CallMethod(encoded, &_Py_ID(replace), "cc", '-', '_'); 83 | if (modname == NULL) 84 | goto error; 85 | 86 | Py_DECREF(name); 87 | Py_DECREF(encoded); 88 | return modname; 89 | error: 90 | Py_DECREF(name); 91 | Py_XDECREF(encoded); 92 | return NULL; 93 | } 94 | 95 | PyObject * 96 | _PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *fp) 97 | { 98 | #ifndef MS_WINDOWS 99 | PyObject *pathbytes = NULL; 100 | #endif 101 | PyObject *name_unicode = NULL, *name = NULL, *path = NULL, *m = NULL; 102 | const char *name_buf, *hook_prefix; 103 | const char *oldcontext, *newcontext; 104 | dl_funcptr exportfunc; 105 | PyModuleDef *def; 106 | PyModInitFunction p0; 107 | 108 | name_unicode = PyObject_GetAttrString(spec, "name"); 109 | if (name_unicode == NULL) { 110 | return NULL; 111 | } 112 | if (!PyUnicode_Check(name_unicode)) { 113 | PyErr_SetString(PyExc_TypeError, 114 | "spec.name must be a string"); 115 | goto error; 116 | } 117 | newcontext = PyUnicode_AsUTF8(name_unicode); 118 | if (newcontext == NULL) { 119 | goto error; 120 | } 121 | 122 | name = get_encoded_name(name_unicode, &hook_prefix); 123 | if (name == NULL) { 124 | goto error; 125 | } 126 | name_buf = PyBytes_AS_STRING(name); 127 | 128 | path = PyObject_GetAttrString(spec, "origin"); 129 | if (path == NULL) 130 | goto error; 131 | 132 | if (PySys_Audit("import", "OOOOO", name_unicode, path, 133 | Py_None, Py_None, Py_None) < 0) { 134 | goto error; 135 | } 136 | 137 | #ifdef MS_WINDOWS 138 | exportfunc = _PyImport_FindSharedFuncptrWindows(hook_prefix, name_buf, 139 | path, fp); 140 | #else 141 | pathbytes = PyUnicode_EncodeFSDefault(path); 142 | if (pathbytes == NULL) 143 | goto error; 144 | exportfunc = _PyImport_FindSharedFuncptr(hook_prefix, name_buf, 145 | PyBytes_AS_STRING(pathbytes), 146 | fp); 147 | Py_DECREF(pathbytes); 148 | #endif 149 | 150 | if (exportfunc == NULL) { 151 | if (!PyErr_Occurred()) { 152 | PyObject *msg; 153 | msg = PyUnicode_FromFormat( 154 | "dynamic module does not define " 155 | "module export function (%s_%s)", 156 | hook_prefix, name_buf); 157 | if (msg == NULL) 158 | goto error; 159 | PyErr_SetImportError(msg, name_unicode, path); 160 | Py_DECREF(msg); 161 | } 162 | goto error; 163 | } 164 | 165 | p0 = (PyModInitFunction)exportfunc; 166 | 167 | /* Package context is needed for single-phase init */ 168 | oldcontext = _PyImport_SwapPackageContext(newcontext); 169 | m = _PyImport_InitFunc_TrampolineCall(p0); 170 | _PyImport_SwapPackageContext(oldcontext); 171 | 172 | if (m == NULL) { 173 | if (!PyErr_Occurred()) { 174 | PyErr_Format( 175 | PyExc_SystemError, 176 | "initialization of %s failed without raising an exception", 177 | name_buf); 178 | } 179 | goto error; 180 | } else if (PyErr_Occurred()) { 181 | _PyErr_FormatFromCause( 182 | PyExc_SystemError, 183 | "initialization of %s raised unreported exception", 184 | name_buf); 185 | m = NULL; 186 | goto error; 187 | } 188 | if (Py_IS_TYPE(m, NULL)) { 189 | /* This can happen when a PyModuleDef is returned without calling 190 | * PyModuleDef_Init on it 191 | */ 192 | PyErr_Format(PyExc_SystemError, 193 | "init function of %s returned uninitialized object", 194 | name_buf); 195 | m = NULL; /* prevent segfault in DECREF */ 196 | goto error; 197 | } 198 | if (PyObject_TypeCheck(m, &PyModuleDef_Type)) { 199 | Py_DECREF(name_unicode); 200 | Py_DECREF(name); 201 | Py_DECREF(path); 202 | return PyModule_FromDefAndSpec((PyModuleDef*)m, spec); 203 | } 204 | 205 | /* Fall back to single-phase init mechanism */ 206 | 207 | if (_PyImport_CheckSubinterpIncompatibleExtensionAllowed(name_buf) < 0) { 208 | goto error; 209 | } 210 | 211 | if (hook_prefix == nonascii_prefix) { 212 | /* don't allow legacy init for non-ASCII module names */ 213 | PyErr_Format( 214 | PyExc_SystemError, 215 | "initialization of %s did not return PyModuleDef", 216 | name_buf); 217 | goto error; 218 | } 219 | 220 | /* Remember pointer to module init function. */ 221 | def = PyModule_GetDef(m); 222 | if (def == NULL) { 223 | PyErr_Format(PyExc_SystemError, 224 | "initialization of %s did not return an extension " 225 | "module", name_buf); 226 | goto error; 227 | } 228 | def->m_base.m_init = p0; 229 | 230 | /* Remember the filename as the __file__ attribute */ 231 | if (PyModule_AddObjectRef(m, "__file__", path) < 0) { 232 | PyErr_Clear(); /* Not important enough to report */ 233 | } 234 | 235 | PyObject *modules = PyImport_GetModuleDict(); 236 | if (_PyImport_FixupExtensionObject(m, name_unicode, path, modules) < 0) 237 | goto error; 238 | 239 | Py_DECREF(name_unicode); 240 | Py_DECREF(name); 241 | Py_DECREF(path); 242 | 243 | return m; 244 | 245 | error: 246 | Py_DECREF(name_unicode); 247 | Py_XDECREF(name); 248 | Py_XDECREF(path); 249 | Py_XDECREF(m); 250 | return NULL; 251 | } 252 | 253 | #endif /* HAVE_DYNAMIC_LOADING */ 254 | -------------------------------------------------------------------------------- /ImPortdl.h: -------------------------------------------------------------------------------- 1 | #ifndef Py_IMPORTDL_H 2 | #define Py_IMPORTDL_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | 9 | extern const char *_PyImport_DynLoadFiletab[]; 10 | 11 | extern PyObject *_PyImport_LoadDynamicModuleWithSpec(PyObject *spec, FILE *); 12 | 13 | typedef PyObject *(*PyModInitFunction)(void); 14 | 15 | #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE) 16 | extern PyObject *_PyImport_InitFunc_TrampolineCall(PyModInitFunction func); 17 | #else 18 | #define _PyImport_InitFunc_TrampolineCall(func) (func)() 19 | #endif 20 | 21 | /* Max length of module suffix searched for -- accommodates "module.slb" */ 22 | #define MAXSUFFIXSIZE 12 23 | 24 | #ifdef MS_WINDOWS 25 | #include 26 | typedef FARPROC dl_funcptr; 27 | #else 28 | typedef void (*dl_funcptr)(void); 29 | #endif 30 | 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | #endif /* !Py_IMPORTDL_H */ 36 | -------------------------------------------------------------------------------- /MakeOpCodeTargets.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | """Generate C code for the jump table of the threaded code interpreter 3 | (for compilers supporting computed gotos or "labels-as-values", such as gcc). 4 | """ 5 | 6 | import os 7 | import sys 8 | 9 | 10 | # 2023-04-27(warsaw): Pre-Python 3.12, this would catch ImportErrors and try to 11 | # import imp, and then use imp.load_module(). The imp module was removed in 12 | # Python 3.12 (and long deprecated before that), and it's unclear under what 13 | # conditions this import will now fail, so the fallback was simply removed. 14 | from importlib.machinery import SourceFileLoader 15 | 16 | def find_module(modname): 17 | """Finds and returns a module in the local dist/checkout. 18 | """ 19 | modpath = os.path.join( 20 | os.path.dirname(os.path.dirname(__file__)), "Lib", modname + ".py") 21 | return SourceFileLoader(modname, modpath).load_module() 22 | 23 | 24 | def write_contents(f): 25 | """Write C code contents to the target file object. 26 | """ 27 | opcode = find_module('opcode') 28 | targets = ['_unknown_opcode'] * 256 29 | for opname, op in opcode.opmap.items(): 30 | if not opcode.is_pseudo(op): 31 | targets[op] = "TARGET_%s" % opname 32 | next_op = 1 33 | for opname in opcode._specialized_instructions: 34 | while targets[next_op] != '_unknown_opcode': 35 | next_op += 1 36 | targets[next_op] = "TARGET_%s" % opname 37 | f.write("static void *opcode_targets[256] = {\n") 38 | f.write(",\n".join([" &&%s" % s for s in targets])) 39 | f.write("\n};\n") 40 | 41 | 42 | def main(): 43 | if len(sys.argv) >= 3: 44 | sys.exit("Too many arguments") 45 | if len(sys.argv) == 2: 46 | target = sys.argv[1] 47 | else: 48 | target = "Python/opcode_targets.h" 49 | with open(target, "w") as f: 50 | write_contents(f) 51 | print("Jump table written into %s" % target) 52 | 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /MySnPrintf.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | 3 | /* snprintf() and vsnprintf() wrappers. 4 | 5 | If the platform has vsnprintf, we use it, else we 6 | emulate it in a half-hearted way. Even if the platform has it, we wrap 7 | it because platforms differ in what vsnprintf does in case the buffer 8 | is too small: C99 behavior is to return the number of characters that 9 | would have been written had the buffer not been too small, and to set 10 | the last byte of the buffer to \0. At least MS _vsnprintf returns a 11 | negative value instead, and fills the entire buffer with non-\0 data. 12 | Unlike C99, our wrappers do not support passing a null buffer. 13 | 14 | The wrappers ensure that str[size-1] is always \0 upon return. 15 | 16 | PyOS_snprintf and PyOS_vsnprintf never write more than size bytes 17 | (including the trailing '\0') into str. 18 | 19 | Return value (rv): 20 | 21 | When 0 <= rv < size, the output conversion was unexceptional, and 22 | rv characters were written to str (excluding a trailing \0 byte at 23 | str[rv]). 24 | 25 | When rv >= size, output conversion was truncated, and a buffer of 26 | size rv+1 would have been needed to avoid truncation. str[size-1] 27 | is \0 in this case. 28 | 29 | When rv < 0, "something bad happened". str[size-1] is \0 in this 30 | case too, but the rest of str is unreliable. It could be that 31 | an error in format codes was detected by libc, or on platforms 32 | with a non-C99 vsnprintf simply that the buffer wasn't big enough 33 | to avoid truncation, or on platforms without any vsnprintf that 34 | PyMem_Malloc couldn't obtain space for a temp buffer. 35 | 36 | CAUTION: Unlike C99, str != NULL and size > 0 are required. 37 | Also, size must be smaller than INT_MAX. 38 | */ 39 | 40 | int 41 | PyOS_snprintf(char *str, size_t size, const char *format, ...) 42 | { 43 | int rc; 44 | va_list va; 45 | 46 | va_start(va, format); 47 | rc = PyOS_vsnprintf(str, size, format, va); 48 | va_end(va); 49 | return rc; 50 | } 51 | 52 | int 53 | PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) 54 | { 55 | assert(str != NULL); 56 | assert(size > 0); 57 | assert(size <= (INT_MAX - 1)); 58 | assert(format != NULL); 59 | 60 | int len; /* # bytes written, excluding \0 */ 61 | /* We take a size_t as input but return an int. Sanity check 62 | * our input so that it won't cause an overflow in the 63 | * vsnprintf return value. */ 64 | if (size > INT_MAX - 1) { 65 | len = -666; 66 | goto Done; 67 | } 68 | 69 | #if defined(_MSC_VER) 70 | len = _vsnprintf(str, size, format, va); 71 | #else 72 | len = vsnprintf(str, size, format, va); 73 | #endif 74 | 75 | Done: 76 | if (size > 0) { 77 | str[size-1] = '\0'; 78 | } 79 | return len; 80 | } 81 | -------------------------------------------------------------------------------- /OpCode_Targets.h: -------------------------------------------------------------------------------- 1 | static void *opcode_targets[256] = { 2 | &&TARGET_CACHE, 3 | &&TARGET_POP_TOP, 4 | &&TARGET_PUSH_NULL, 5 | &&TARGET_INTERPRETER_EXIT, 6 | &&TARGET_END_FOR, 7 | &&TARGET_END_SEND, 8 | &&TARGET_BINARY_OP_ADD_FLOAT, 9 | &&TARGET_BINARY_OP_ADD_INT, 10 | &&TARGET_BINARY_OP_ADD_UNICODE, 11 | &&TARGET_NOP, 12 | &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, 13 | &&TARGET_UNARY_NEGATIVE, 14 | &&TARGET_UNARY_NOT, 15 | &&TARGET_BINARY_OP_MULTIPLY_FLOAT, 16 | &&TARGET_BINARY_OP_MULTIPLY_INT, 17 | &&TARGET_UNARY_INVERT, 18 | &&TARGET_BINARY_OP_SUBTRACT_FLOAT, 19 | &&TARGET_RESERVED, 20 | &&TARGET_BINARY_OP_SUBTRACT_INT, 21 | &&TARGET_BINARY_SUBSCR_DICT, 22 | &&TARGET_BINARY_SUBSCR_GETITEM, 23 | &&TARGET_BINARY_SUBSCR_LIST_INT, 24 | &&TARGET_BINARY_SUBSCR_TUPLE_INT, 25 | &&TARGET_CALL_PY_EXACT_ARGS, 26 | &&TARGET_CALL_PY_WITH_DEFAULTS, 27 | &&TARGET_BINARY_SUBSCR, 28 | &&TARGET_BINARY_SLICE, 29 | &&TARGET_STORE_SLICE, 30 | &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, 31 | &&TARGET_CALL_BUILTIN_CLASS, 32 | &&TARGET_GET_LEN, 33 | &&TARGET_MATCH_MAPPING, 34 | &&TARGET_MATCH_SEQUENCE, 35 | &&TARGET_MATCH_KEYS, 36 | &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, 37 | &&TARGET_PUSH_EXC_INFO, 38 | &&TARGET_CHECK_EXC_MATCH, 39 | &&TARGET_CHECK_EG_MATCH, 40 | &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, 41 | &&TARGET_CALL_NO_KW_BUILTIN_FAST, 42 | &&TARGET_CALL_NO_KW_BUILTIN_O, 43 | &&TARGET_CALL_NO_KW_ISINSTANCE, 44 | &&TARGET_CALL_NO_KW_LEN, 45 | &&TARGET_CALL_NO_KW_LIST_APPEND, 46 | &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, 47 | &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, 48 | &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, 49 | &&TARGET_CALL_NO_KW_STR_1, 50 | &&TARGET_CALL_NO_KW_TUPLE_1, 51 | &&TARGET_WITH_EXCEPT_START, 52 | &&TARGET_GET_AITER, 53 | &&TARGET_GET_ANEXT, 54 | &&TARGET_BEFORE_ASYNC_WITH, 55 | &&TARGET_BEFORE_WITH, 56 | &&TARGET_END_ASYNC_FOR, 57 | &&TARGET_CLEANUP_THROW, 58 | &&TARGET_CALL_NO_KW_TYPE_1, 59 | &&TARGET_COMPARE_OP_FLOAT, 60 | &&TARGET_COMPARE_OP_INT, 61 | &&TARGET_COMPARE_OP_STR, 62 | &&TARGET_STORE_SUBSCR, 63 | &&TARGET_DELETE_SUBSCR, 64 | &&TARGET_FOR_ITER_LIST, 65 | &&TARGET_FOR_ITER_TUPLE, 66 | &&TARGET_FOR_ITER_RANGE, 67 | &&TARGET_FOR_ITER_GEN, 68 | &&TARGET_LOAD_SUPER_ATTR_ATTR, 69 | &&TARGET_LOAD_SUPER_ATTR_METHOD, 70 | &&TARGET_GET_ITER, 71 | &&TARGET_GET_YIELD_FROM_ITER, 72 | &&TARGET_LOAD_ATTR_CLASS, 73 | &&TARGET_LOAD_BUILD_CLASS, 74 | &&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN, 75 | &&TARGET_LOAD_ATTR_INSTANCE_VALUE, 76 | &&TARGET_LOAD_ASSERTION_ERROR, 77 | &&TARGET_RETURN_GENERATOR, 78 | &&TARGET_LOAD_ATTR_MODULE, 79 | &&TARGET_LOAD_ATTR_PROPERTY, 80 | &&TARGET_LOAD_ATTR_SLOT, 81 | &&TARGET_LOAD_ATTR_WITH_HINT, 82 | &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, 83 | &&TARGET_LOAD_ATTR_METHOD_NO_DICT, 84 | &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, 85 | &&TARGET_RETURN_VALUE, 86 | &&TARGET_LOAD_CONST__LOAD_FAST, 87 | &&TARGET_SETUP_ANNOTATIONS, 88 | &&TARGET_LOAD_FAST__LOAD_CONST, 89 | &&TARGET_LOAD_LOCALS, 90 | &&TARGET_LOAD_FAST__LOAD_FAST, 91 | &&TARGET_POP_EXCEPT, 92 | &&TARGET_STORE_NAME, 93 | &&TARGET_DELETE_NAME, 94 | &&TARGET_UNPACK_SEQUENCE, 95 | &&TARGET_FOR_ITER, 96 | &&TARGET_UNPACK_EX, 97 | &&TARGET_STORE_ATTR, 98 | &&TARGET_DELETE_ATTR, 99 | &&TARGET_STORE_GLOBAL, 100 | &&TARGET_DELETE_GLOBAL, 101 | &&TARGET_SWAP, 102 | &&TARGET_LOAD_CONST, 103 | &&TARGET_LOAD_NAME, 104 | &&TARGET_BUILD_TUPLE, 105 | &&TARGET_BUILD_LIST, 106 | &&TARGET_BUILD_SET, 107 | &&TARGET_BUILD_MAP, 108 | &&TARGET_LOAD_ATTR, 109 | &&TARGET_COMPARE_OP, 110 | &&TARGET_IMPORT_NAME, 111 | &&TARGET_IMPORT_FROM, 112 | &&TARGET_JUMP_FORWARD, 113 | &&TARGET_LOAD_GLOBAL_BUILTIN, 114 | &&TARGET_LOAD_GLOBAL_MODULE, 115 | &&TARGET_STORE_ATTR_INSTANCE_VALUE, 116 | &&TARGET_POP_JUMP_IF_FALSE, 117 | &&TARGET_POP_JUMP_IF_TRUE, 118 | &&TARGET_LOAD_GLOBAL, 119 | &&TARGET_IS_OP, 120 | &&TARGET_CONTAINS_OP, 121 | &&TARGET_RERAISE, 122 | &&TARGET_COPY, 123 | &&TARGET_RETURN_CONST, 124 | &&TARGET_BINARY_OP, 125 | &&TARGET_SEND, 126 | &&TARGET_LOAD_FAST, 127 | &&TARGET_STORE_FAST, 128 | &&TARGET_DELETE_FAST, 129 | &&TARGET_LOAD_FAST_CHECK, 130 | &&TARGET_POP_JUMP_IF_NOT_NONE, 131 | &&TARGET_POP_JUMP_IF_NONE, 132 | &&TARGET_RAISE_VARARGS, 133 | &&TARGET_GET_AWAITABLE, 134 | &&TARGET_MAKE_FUNCTION, 135 | &&TARGET_BUILD_SLICE, 136 | &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, 137 | &&TARGET_MAKE_CELL, 138 | &&TARGET_LOAD_CLOSURE, 139 | &&TARGET_LOAD_DEREF, 140 | &&TARGET_STORE_DEREF, 141 | &&TARGET_DELETE_DEREF, 142 | &&TARGET_JUMP_BACKWARD, 143 | &&TARGET_LOAD_SUPER_ATTR, 144 | &&TARGET_CALL_FUNCTION_EX, 145 | &&TARGET_LOAD_FAST_AND_CLEAR, 146 | &&TARGET_EXTENDED_ARG, 147 | &&TARGET_LIST_APPEND, 148 | &&TARGET_SET_ADD, 149 | &&TARGET_MAP_ADD, 150 | &&TARGET_STORE_ATTR_SLOT, 151 | &&TARGET_COPY_FREE_VARS, 152 | &&TARGET_YIELD_VALUE, 153 | &&TARGET_RESUME, 154 | &&TARGET_MATCH_CLASS, 155 | &&TARGET_STORE_ATTR_WITH_HINT, 156 | &&TARGET_STORE_FAST__LOAD_FAST, 157 | &&TARGET_FORMAT_VALUE, 158 | &&TARGET_BUILD_CONST_KEY_MAP, 159 | &&TARGET_BUILD_STRING, 160 | &&TARGET_STORE_FAST__STORE_FAST, 161 | &&TARGET_STORE_SUBSCR_DICT, 162 | &&TARGET_STORE_SUBSCR_LIST_INT, 163 | &&TARGET_UNPACK_SEQUENCE_LIST, 164 | &&TARGET_LIST_EXTEND, 165 | &&TARGET_SET_UPDATE, 166 | &&TARGET_DICT_MERGE, 167 | &&TARGET_DICT_UPDATE, 168 | &&TARGET_UNPACK_SEQUENCE_TUPLE, 169 | &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, 170 | &&TARGET_SEND_GEN, 171 | &&_unknown_opcode, 172 | &&_unknown_opcode, 173 | &&TARGET_CALL, 174 | &&TARGET_KW_NAMES, 175 | &&TARGET_CALL_INTRINSIC_1, 176 | &&TARGET_CALL_INTRINSIC_2, 177 | &&TARGET_LOAD_FROM_DICT_OR_GLOBALS, 178 | &&TARGET_LOAD_FROM_DICT_OR_DEREF, 179 | &&_unknown_opcode, 180 | &&_unknown_opcode, 181 | &&_unknown_opcode, 182 | &&_unknown_opcode, 183 | &&_unknown_opcode, 184 | &&_unknown_opcode, 185 | &&_unknown_opcode, 186 | &&_unknown_opcode, 187 | &&_unknown_opcode, 188 | &&_unknown_opcode, 189 | &&_unknown_opcode, 190 | &&_unknown_opcode, 191 | &&_unknown_opcode, 192 | &&_unknown_opcode, 193 | &&_unknown_opcode, 194 | &&_unknown_opcode, 195 | &&_unknown_opcode, 196 | &&_unknown_opcode, 197 | &&_unknown_opcode, 198 | &&_unknown_opcode, 199 | &&_unknown_opcode, 200 | &&_unknown_opcode, 201 | &&_unknown_opcode, 202 | &&_unknown_opcode, 203 | &&_unknown_opcode, 204 | &&_unknown_opcode, 205 | &&_unknown_opcode, 206 | &&_unknown_opcode, 207 | &&_unknown_opcode, 208 | &&_unknown_opcode, 209 | &&_unknown_opcode, 210 | &&_unknown_opcode, 211 | &&_unknown_opcode, 212 | &&_unknown_opcode, 213 | &&_unknown_opcode, 214 | &&_unknown_opcode, 215 | &&_unknown_opcode, 216 | &&_unknown_opcode, 217 | &&_unknown_opcode, 218 | &&_unknown_opcode, 219 | &&_unknown_opcode, 220 | &&_unknown_opcode, 221 | &&_unknown_opcode, 222 | &&_unknown_opcode, 223 | &&_unknown_opcode, 224 | &&_unknown_opcode, 225 | &&_unknown_opcode, 226 | &&_unknown_opcode, 227 | &&_unknown_opcode, 228 | &&_unknown_opcode, 229 | &&_unknown_opcode, 230 | &&_unknown_opcode, 231 | &&_unknown_opcode, 232 | &&_unknown_opcode, 233 | &&_unknown_opcode, 234 | &&_unknown_opcode, 235 | &&_unknown_opcode, 236 | &&_unknown_opcode, 237 | &&_unknown_opcode, 238 | &&_unknown_opcode, 239 | &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, 240 | &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE, 241 | &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE, 242 | &&TARGET_INSTRUMENTED_RESUME, 243 | &&TARGET_INSTRUMENTED_CALL, 244 | &&TARGET_INSTRUMENTED_RETURN_VALUE, 245 | &&TARGET_INSTRUMENTED_YIELD_VALUE, 246 | &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, 247 | &&TARGET_INSTRUMENTED_JUMP_FORWARD, 248 | &&TARGET_INSTRUMENTED_JUMP_BACKWARD, 249 | &&TARGET_INSTRUMENTED_RETURN_CONST, 250 | &&TARGET_INSTRUMENTED_FOR_ITER, 251 | &&TARGET_INSTRUMENTED_POP_JUMP_IF_FALSE, 252 | &&TARGET_INSTRUMENTED_POP_JUMP_IF_TRUE, 253 | &&TARGET_INSTRUMENTED_END_FOR, 254 | &&TARGET_INSTRUMENTED_END_SEND, 255 | &&TARGET_INSTRUMENTED_INSTRUCTION, 256 | &&TARGET_INSTRUMENTED_LINE, 257 | &&_unknown_opcode 258 | }; 259 | -------------------------------------------------------------------------------- /OptiMizer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "Python.h" 3 | #include "opcode.h" 4 | #include "pycore_interp.h" 5 | #include "pycore_opcode.h" 6 | #include "pycore_pystate.h" 7 | #include "cpython/optimizer.h" 8 | #include 9 | #include 10 | #include 11 | 12 | /* Returns the index of the next space, or -1 if there is no 13 | * more space. Doesn't set an exception. */ 14 | static int32_t 15 | get_next_free_in_executor_array(PyCodeObject *code) 16 | { 17 | _PyExecutorArray *old = code->co_executors; 18 | int size = 0; 19 | int capacity = 0; 20 | if (old != NULL) { 21 | size = old->size; 22 | capacity = old->capacity; 23 | if (capacity >= 256) { 24 | return -1; 25 | } 26 | } 27 | assert(size <= capacity); 28 | if (size == capacity) { 29 | /* Array is full. Grow array */ 30 | int new_capacity = capacity ? capacity * 2 : 4; 31 | _PyExecutorArray *new = PyMem_Realloc( 32 | old, 33 | offsetof(_PyExecutorArray, executors) + 34 | new_capacity * sizeof(_PyExecutorObject *)); 35 | if (new == NULL) { 36 | return -1; 37 | } 38 | new->capacity = new_capacity; 39 | new->size = size; 40 | code->co_executors = new; 41 | } 42 | assert(size < code->co_executors->capacity); 43 | code->co_executors->size++; 44 | return size; 45 | } 46 | 47 | static void 48 | insert_executor(PyCodeObject *code, _Py_CODEUNIT *instr, int index, _PyExecutorObject *executor) 49 | { 50 | if (instr->op.code == ENTER_EXECUTOR) { 51 | assert(index == instr->op.arg); 52 | _PyExecutorObject *old = code->co_executors->executors[index]; 53 | executor->vm_data.opcode = old->vm_data.opcode; 54 | executor->vm_data.oparg = old->vm_data.oparg; 55 | old->vm_data.opcode = 0; 56 | Py_INCREF(executor); 57 | code->co_executors->executors[index] = executor; 58 | Py_DECREF(old); 59 | } 60 | else { 61 | Py_INCREF(executor); 62 | executor->vm_data.opcode = instr->op.code; 63 | executor->vm_data.oparg = instr->op.arg; 64 | code->co_executors->executors[index] = executor; 65 | assert(index < 256); 66 | instr->op.code = ENTER_EXECUTOR; 67 | instr->op.arg = index; 68 | } 69 | return; 70 | } 71 | 72 | static int 73 | get_executor_index(PyCodeObject *code, _Py_CODEUNIT *instr) 74 | { 75 | if (instr->op.code == ENTER_EXECUTOR) { 76 | return instr->op.arg; 77 | } 78 | else { 79 | return get_next_free_in_executor_array(code); 80 | } 81 | } 82 | 83 | int 84 | PyUnstable_Replace_Executor(PyCodeObject *code, _Py_CODEUNIT *instr, _PyExecutorObject *new) 85 | { 86 | if (instr->op.code != ENTER_EXECUTOR) { 87 | PyErr_Format(PyExc_ValueError, "No executor to replace"); 88 | return -1; 89 | } 90 | int index = get_executor_index(code, instr); 91 | assert(index >= 0); 92 | insert_executor(code, instr, index, new); 93 | return 0; 94 | } 95 | 96 | static int 97 | error_optimize( 98 | _PyOptimizerObject* self, 99 | PyCodeObject *code, 100 | _Py_CODEUNIT *instr, 101 | _PyExecutorObject **exec) 102 | { 103 | PyErr_Format(PyExc_SystemError, "Should never call error_optimize"); 104 | return -1; 105 | } 106 | 107 | static PyTypeObject DefaultOptimizer_Type = { 108 | PyVarObject_HEAD_INIT(&PyType_Type, 0) 109 | .tp_name = "noop_optimizer", 110 | .tp_basicsize = sizeof(_PyOptimizerObject), 111 | .tp_itemsize = 0, 112 | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, 113 | }; 114 | 115 | _PyOptimizerObject _PyOptimizer_Default = { 116 | PyObject_HEAD_INIT(&DefaultOptimizer_Type) 117 | .optimize = error_optimize, 118 | .resume_threshold = UINT16_MAX, 119 | .backedge_threshold = UINT16_MAX, 120 | }; 121 | 122 | _PyOptimizerObject * 123 | PyUnstable_GetOptimizer(void) 124 | { 125 | PyInterpreterState *interp = PyInterpreterState_Get(); 126 | if (interp->optimizer == &_PyOptimizer_Default) { 127 | return NULL; 128 | } 129 | Py_INCREF(interp->optimizer); 130 | return interp->optimizer; 131 | } 132 | 133 | void 134 | PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer) 135 | { 136 | PyInterpreterState *interp = PyInterpreterState_Get(); 137 | if (optimizer == NULL) { 138 | optimizer = &_PyOptimizer_Default; 139 | } 140 | _PyOptimizerObject *old = interp->optimizer; 141 | Py_INCREF(optimizer); 142 | interp->optimizer = optimizer; 143 | interp->optimizer_backedge_threshold = optimizer->backedge_threshold; 144 | interp->optimizer_resume_threshold = optimizer->resume_threshold; 145 | Py_DECREF(old); 146 | } 147 | 148 | _PyInterpreterFrame * 149 | _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer) 150 | { 151 | PyInterpreterState *interp = PyInterpreterState_Get(); 152 | int index = get_executor_index(frame->f_code, src); 153 | if (index < 0) { 154 | _PyFrame_SetStackPointer(frame, stack_pointer); 155 | return frame; 156 | } 157 | _PyOptimizerObject *opt = interp->optimizer; 158 | _PyExecutorObject *executor; 159 | int err = opt->optimize(opt, frame->f_code, dest, &executor); 160 | if (err <= 0) { 161 | if (err < 0) { 162 | return NULL; 163 | } 164 | _PyFrame_SetStackPointer(frame, stack_pointer); 165 | return frame; 166 | } 167 | insert_executor(frame->f_code, src, index, executor); 168 | return executor->execute(executor, frame, stack_pointer); 169 | } 170 | 171 | /** Test support **/ 172 | 173 | 174 | typedef struct { 175 | _PyOptimizerObject base; 176 | int64_t count; 177 | } _PyCounterOptimizerObject; 178 | 179 | typedef struct { 180 | _PyExecutorObject executor; 181 | _PyCounterOptimizerObject *optimizer; 182 | _Py_CODEUNIT *next_instr; 183 | } _PyCounterExecutorObject; 184 | 185 | static void 186 | counter_dealloc(_PyCounterExecutorObject *self) { 187 | Py_DECREF(self->optimizer); 188 | PyObject_Free(self); 189 | } 190 | 191 | static PyTypeObject CounterExecutor_Type = { 192 | PyVarObject_HEAD_INIT(&PyType_Type, 0) 193 | .tp_name = "counting_executor", 194 | .tp_basicsize = sizeof(_PyCounterExecutorObject), 195 | .tp_itemsize = 0, 196 | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, 197 | .tp_dealloc = (destructor)counter_dealloc, 198 | }; 199 | 200 | static _PyInterpreterFrame * 201 | counter_execute(_PyExecutorObject *self, _PyInterpreterFrame *frame, PyObject **stack_pointer) 202 | { 203 | ((_PyCounterExecutorObject *)self)->optimizer->count++; 204 | _PyFrame_SetStackPointer(frame, stack_pointer); 205 | frame->prev_instr = ((_PyCounterExecutorObject *)self)->next_instr - 1; 206 | Py_DECREF(self); 207 | return frame; 208 | } 209 | 210 | static int 211 | counter_optimize( 212 | _PyOptimizerObject* self, 213 | PyCodeObject *code, 214 | _Py_CODEUNIT *instr, 215 | _PyExecutorObject **exec_ptr) 216 | { 217 | _PyCounterExecutorObject *executor = (_PyCounterExecutorObject *)_PyObject_New(&CounterExecutor_Type); 218 | if (executor == NULL) { 219 | return -1; 220 | } 221 | executor->executor.execute = counter_execute; 222 | Py_INCREF(self); 223 | executor->optimizer = (_PyCounterOptimizerObject *)self; 224 | executor->next_instr = instr; 225 | *exec_ptr = (_PyExecutorObject *)executor; 226 | return 1; 227 | } 228 | 229 | static PyObject * 230 | counter_get_counter(PyObject *self, PyObject *args) 231 | { 232 | return PyLong_FromLongLong(((_PyCounterOptimizerObject *)self)->count); 233 | } 234 | 235 | static PyMethodDef counter_methods[] = { 236 | { "get_count", counter_get_counter, METH_NOARGS, NULL }, 237 | { NULL, NULL }, 238 | }; 239 | 240 | static PyTypeObject CounterOptimizer_Type = { 241 | PyVarObject_HEAD_INIT(&PyType_Type, 0) 242 | .tp_name = "Counter optimizer", 243 | .tp_basicsize = sizeof(_PyCounterOptimizerObject), 244 | .tp_itemsize = 0, 245 | .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, 246 | .tp_methods = counter_methods, 247 | }; 248 | 249 | PyObject * 250 | PyUnstable_Optimizer_NewCounter(void) 251 | { 252 | _PyCounterOptimizerObject *opt = (_PyCounterOptimizerObject *)_PyObject_New(&CounterOptimizer_Type); 253 | if (opt == NULL) { 254 | return NULL; 255 | } 256 | opt->base.optimize = counter_optimize; 257 | opt->base.resume_threshold = UINT16_MAX; 258 | opt->base.backedge_threshold = 0; 259 | opt->count = 0; 260 | return (PyObject *)opt; 261 | } 262 | -------------------------------------------------------------------------------- /PyArena.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | #include "pycore_pyarena.h" // PyArena 3 | 4 | /* A simple arena block structure. 5 | 6 | Measurements with standard library modules suggest the average 7 | allocation is about 20 bytes and that most compiles use a single 8 | block. 9 | 10 | TODO(jhylton): Think about a realloc API, maybe just for the last 11 | allocation? 12 | */ 13 | 14 | #define DEFAULT_BLOCK_SIZE 8192 15 | #define ALIGNMENT 8 16 | 17 | typedef struct _block { 18 | /* Total number of bytes owned by this block available to pass out. 19 | * Read-only after initialization. The first such byte starts at 20 | * ab_mem. 21 | */ 22 | size_t ab_size; 23 | 24 | /* Total number of bytes already passed out. The next byte available 25 | * to pass out starts at ab_mem + ab_offset. 26 | */ 27 | size_t ab_offset; 28 | 29 | /* An arena maintains a singly-linked, NULL-terminated list of 30 | * all blocks owned by the arena. These are linked via the 31 | * ab_next member. 32 | */ 33 | struct _block *ab_next; 34 | 35 | /* Pointer to the first allocatable byte owned by this block. Read- 36 | * only after initialization. 37 | */ 38 | void *ab_mem; 39 | } block; 40 | 41 | /* The arena manages two kinds of memory, blocks of raw memory 42 | and a list of PyObject* pointers. PyObjects are decrefed 43 | when the arena is freed. 44 | */ 45 | 46 | struct _arena { 47 | /* Pointer to the first block allocated for the arena, never NULL. 48 | It is used only to find the first block when the arena is 49 | being freed. 50 | */ 51 | block *a_head; 52 | 53 | /* Pointer to the block currently used for allocation. Its 54 | ab_next field should be NULL. If it is not-null after a 55 | call to block_alloc(), it means a new block has been allocated 56 | and a_cur should be reset to point it. 57 | */ 58 | block *a_cur; 59 | 60 | /* A Python list object containing references to all the PyObject 61 | pointers associated with this arena. They will be DECREFed 62 | when the arena is freed. 63 | */ 64 | PyObject *a_objects; 65 | 66 | #if defined(Py_DEBUG) 67 | /* Debug output */ 68 | size_t total_allocs; 69 | size_t total_size; 70 | size_t total_blocks; 71 | size_t total_block_size; 72 | size_t total_big_blocks; 73 | #endif 74 | }; 75 | 76 | static block * 77 | block_new(size_t size) 78 | { 79 | /* Allocate header and block as one unit. 80 | ab_mem points just past header. */ 81 | block *b = (block *)PyMem_Malloc(sizeof(block) + size); 82 | if (!b) 83 | return NULL; 84 | b->ab_size = size; 85 | b->ab_mem = (void *)(b + 1); 86 | b->ab_next = NULL; 87 | b->ab_offset = (char *)_Py_ALIGN_UP(b->ab_mem, ALIGNMENT) - 88 | (char *)(b->ab_mem); 89 | return b; 90 | } 91 | 92 | static void 93 | block_free(block *b) { 94 | while (b) { 95 | block *next = b->ab_next; 96 | PyMem_Free(b); 97 | b = next; 98 | } 99 | } 100 | 101 | static void * 102 | block_alloc(block *b, size_t size) 103 | { 104 | void *p; 105 | assert(b); 106 | size = _Py_SIZE_ROUND_UP(size, ALIGNMENT); 107 | if (b->ab_offset + size > b->ab_size) { 108 | /* If we need to allocate more memory than will fit in 109 | the default block, allocate a one-off block that is 110 | exactly the right size. */ 111 | /* TODO(jhylton): Think about space waste at end of block */ 112 | block *newbl = block_new( 113 | size < DEFAULT_BLOCK_SIZE ? 114 | DEFAULT_BLOCK_SIZE : size); 115 | if (!newbl) 116 | return NULL; 117 | assert(!b->ab_next); 118 | b->ab_next = newbl; 119 | b = newbl; 120 | } 121 | 122 | assert(b->ab_offset + size <= b->ab_size); 123 | p = (void *)(((char *)b->ab_mem) + b->ab_offset); 124 | b->ab_offset += size; 125 | return p; 126 | } 127 | 128 | PyArena * 129 | _PyArena_New(void) 130 | { 131 | PyArena* arena = (PyArena *)PyMem_Malloc(sizeof(PyArena)); 132 | if (!arena) 133 | return (PyArena*)PyErr_NoMemory(); 134 | 135 | arena->a_head = block_new(DEFAULT_BLOCK_SIZE); 136 | arena->a_cur = arena->a_head; 137 | if (!arena->a_head) { 138 | PyMem_Free((void *)arena); 139 | return (PyArena*)PyErr_NoMemory(); 140 | } 141 | arena->a_objects = PyList_New(0); 142 | if (!arena->a_objects) { 143 | block_free(arena->a_head); 144 | PyMem_Free((void *)arena); 145 | return (PyArena*)PyErr_NoMemory(); 146 | } 147 | #if defined(Py_DEBUG) 148 | arena->total_allocs = 0; 149 | arena->total_size = 0; 150 | arena->total_blocks = 1; 151 | arena->total_block_size = DEFAULT_BLOCK_SIZE; 152 | arena->total_big_blocks = 0; 153 | #endif 154 | return arena; 155 | } 156 | 157 | void 158 | _PyArena_Free(PyArena *arena) 159 | { 160 | assert(arena); 161 | #if defined(Py_DEBUG) 162 | /* 163 | fprintf(stderr, 164 | "alloc=%zu size=%zu blocks=%zu block_size=%zu big=%zu objects=%zu\n", 165 | arena->total_allocs, arena->total_size, arena->total_blocks, 166 | arena->total_block_size, arena->total_big_blocks, 167 | PyList_Size(arena->a_objects)); 168 | */ 169 | #endif 170 | block_free(arena->a_head); 171 | /* This property normally holds, except when the code being compiled 172 | is sys.getobjects(0), in which case there will be two references. 173 | assert(arena->a_objects->ob_refcnt == 1); 174 | */ 175 | 176 | Py_DECREF(arena->a_objects); 177 | PyMem_Free(arena); 178 | } 179 | 180 | void * 181 | _PyArena_Malloc(PyArena *arena, size_t size) 182 | { 183 | void *p = block_alloc(arena->a_cur, size); 184 | if (!p) 185 | return PyErr_NoMemory(); 186 | #if defined(Py_DEBUG) 187 | arena->total_allocs++; 188 | arena->total_size += size; 189 | #endif 190 | /* Reset cur if we allocated a new block. */ 191 | if (arena->a_cur->ab_next) { 192 | arena->a_cur = arena->a_cur->ab_next; 193 | #if defined(Py_DEBUG) 194 | arena->total_blocks++; 195 | arena->total_block_size += arena->a_cur->ab_size; 196 | if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) 197 | ++arena->total_big_blocks; 198 | #endif 199 | } 200 | return p; 201 | } 202 | 203 | int 204 | _PyArena_AddPyObject(PyArena *arena, PyObject *obj) 205 | { 206 | int r = PyList_Append(arena->a_objects, obj); 207 | if (r >= 0) { 208 | Py_DECREF(obj); 209 | } 210 | return r; 211 | } 212 | -------------------------------------------------------------------------------- /PyCtype.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | 3 | /* Our own locale-independent ctype.h-like macros */ 4 | 5 | const unsigned int _Py_ctype_table[256] = { 6 | 0, /* 0x0 '\x00' */ 7 | 0, /* 0x1 '\x01' */ 8 | 0, /* 0x2 '\x02' */ 9 | 0, /* 0x3 '\x03' */ 10 | 0, /* 0x4 '\x04' */ 11 | 0, /* 0x5 '\x05' */ 12 | 0, /* 0x6 '\x06' */ 13 | 0, /* 0x7 '\x07' */ 14 | 0, /* 0x8 '\x08' */ 15 | PY_CTF_SPACE, /* 0x9 '\t' */ 16 | PY_CTF_SPACE, /* 0xa '\n' */ 17 | PY_CTF_SPACE, /* 0xb '\v' */ 18 | PY_CTF_SPACE, /* 0xc '\f' */ 19 | PY_CTF_SPACE, /* 0xd '\r' */ 20 | 0, /* 0xe '\x0e' */ 21 | 0, /* 0xf '\x0f' */ 22 | 0, /* 0x10 '\x10' */ 23 | 0, /* 0x11 '\x11' */ 24 | 0, /* 0x12 '\x12' */ 25 | 0, /* 0x13 '\x13' */ 26 | 0, /* 0x14 '\x14' */ 27 | 0, /* 0x15 '\x15' */ 28 | 0, /* 0x16 '\x16' */ 29 | 0, /* 0x17 '\x17' */ 30 | 0, /* 0x18 '\x18' */ 31 | 0, /* 0x19 '\x19' */ 32 | 0, /* 0x1a '\x1a' */ 33 | 0, /* 0x1b '\x1b' */ 34 | 0, /* 0x1c '\x1c' */ 35 | 0, /* 0x1d '\x1d' */ 36 | 0, /* 0x1e '\x1e' */ 37 | 0, /* 0x1f '\x1f' */ 38 | PY_CTF_SPACE, /* 0x20 ' ' */ 39 | 0, /* 0x21 '!' */ 40 | 0, /* 0x22 '"' */ 41 | 0, /* 0x23 '#' */ 42 | 0, /* 0x24 '$' */ 43 | 0, /* 0x25 '%' */ 44 | 0, /* 0x26 '&' */ 45 | 0, /* 0x27 "'" */ 46 | 0, /* 0x28 '(' */ 47 | 0, /* 0x29 ')' */ 48 | 0, /* 0x2a '*' */ 49 | 0, /* 0x2b '+' */ 50 | 0, /* 0x2c ',' */ 51 | 0, /* 0x2d '-' */ 52 | 0, /* 0x2e '.' */ 53 | 0, /* 0x2f '/' */ 54 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x30 '0' */ 55 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x31 '1' */ 56 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x32 '2' */ 57 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x33 '3' */ 58 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x34 '4' */ 59 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x35 '5' */ 60 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x36 '6' */ 61 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x37 '7' */ 62 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x38 '8' */ 63 | PY_CTF_DIGIT|PY_CTF_XDIGIT, /* 0x39 '9' */ 64 | 0, /* 0x3a ':' */ 65 | 0, /* 0x3b ';' */ 66 | 0, /* 0x3c '<' */ 67 | 0, /* 0x3d '=' */ 68 | 0, /* 0x3e '>' */ 69 | 0, /* 0x3f '?' */ 70 | 0, /* 0x40 '@' */ 71 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x41 'A' */ 72 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x42 'B' */ 73 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x43 'C' */ 74 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x44 'D' */ 75 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x45 'E' */ 76 | PY_CTF_UPPER|PY_CTF_XDIGIT, /* 0x46 'F' */ 77 | PY_CTF_UPPER, /* 0x47 'G' */ 78 | PY_CTF_UPPER, /* 0x48 'H' */ 79 | PY_CTF_UPPER, /* 0x49 'I' */ 80 | PY_CTF_UPPER, /* 0x4a 'J' */ 81 | PY_CTF_UPPER, /* 0x4b 'K' */ 82 | PY_CTF_UPPER, /* 0x4c 'L' */ 83 | PY_CTF_UPPER, /* 0x4d 'M' */ 84 | PY_CTF_UPPER, /* 0x4e 'N' */ 85 | PY_CTF_UPPER, /* 0x4f 'O' */ 86 | PY_CTF_UPPER, /* 0x50 'P' */ 87 | PY_CTF_UPPER, /* 0x51 'Q' */ 88 | PY_CTF_UPPER, /* 0x52 'R' */ 89 | PY_CTF_UPPER, /* 0x53 'S' */ 90 | PY_CTF_UPPER, /* 0x54 'T' */ 91 | PY_CTF_UPPER, /* 0x55 'U' */ 92 | PY_CTF_UPPER, /* 0x56 'V' */ 93 | PY_CTF_UPPER, /* 0x57 'W' */ 94 | PY_CTF_UPPER, /* 0x58 'X' */ 95 | PY_CTF_UPPER, /* 0x59 'Y' */ 96 | PY_CTF_UPPER, /* 0x5a 'Z' */ 97 | 0, /* 0x5b '[' */ 98 | 0, /* 0x5c '\\' */ 99 | 0, /* 0x5d ']' */ 100 | 0, /* 0x5e '^' */ 101 | 0, /* 0x5f '_' */ 102 | 0, /* 0x60 '`' */ 103 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x61 'a' */ 104 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x62 'b' */ 105 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x63 'c' */ 106 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x64 'd' */ 107 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x65 'e' */ 108 | PY_CTF_LOWER|PY_CTF_XDIGIT, /* 0x66 'f' */ 109 | PY_CTF_LOWER, /* 0x67 'g' */ 110 | PY_CTF_LOWER, /* 0x68 'h' */ 111 | PY_CTF_LOWER, /* 0x69 'i' */ 112 | PY_CTF_LOWER, /* 0x6a 'j' */ 113 | PY_CTF_LOWER, /* 0x6b 'k' */ 114 | PY_CTF_LOWER, /* 0x6c 'l' */ 115 | PY_CTF_LOWER, /* 0x6d 'm' */ 116 | PY_CTF_LOWER, /* 0x6e 'n' */ 117 | PY_CTF_LOWER, /* 0x6f 'o' */ 118 | PY_CTF_LOWER, /* 0x70 'p' */ 119 | PY_CTF_LOWER, /* 0x71 'q' */ 120 | PY_CTF_LOWER, /* 0x72 'r' */ 121 | PY_CTF_LOWER, /* 0x73 's' */ 122 | PY_CTF_LOWER, /* 0x74 't' */ 123 | PY_CTF_LOWER, /* 0x75 'u' */ 124 | PY_CTF_LOWER, /* 0x76 'v' */ 125 | PY_CTF_LOWER, /* 0x77 'w' */ 126 | PY_CTF_LOWER, /* 0x78 'x' */ 127 | PY_CTF_LOWER, /* 0x79 'y' */ 128 | PY_CTF_LOWER, /* 0x7a 'z' */ 129 | 0, /* 0x7b '{' */ 130 | 0, /* 0x7c '|' */ 131 | 0, /* 0x7d '}' */ 132 | 0, /* 0x7e '~' */ 133 | 0, /* 0x7f '\x7f' */ 134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 142 | }; 143 | 144 | 145 | const unsigned char _Py_ctype_tolower[256] = { 146 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 147 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 148 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 149 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 150 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 151 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 152 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 153 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 154 | 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 155 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 156 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 157 | 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 158 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 159 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 160 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 161 | 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 162 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 163 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 164 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 165 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 166 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 167 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 168 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 169 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 170 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 171 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 172 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 173 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 174 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 175 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 176 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 177 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 178 | }; 179 | 180 | const unsigned char _Py_ctype_toupper[256] = { 181 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 182 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 183 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 184 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 185 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 186 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 187 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 188 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 189 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 190 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 191 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 192 | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 193 | 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 194 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 195 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 196 | 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 197 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 198 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 199 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 200 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 201 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 202 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 203 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 204 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 205 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 206 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 207 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 208 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 209 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 210 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 211 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 212 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 213 | }; 214 | 215 | -------------------------------------------------------------------------------- /PyFpc.c: -------------------------------------------------------------------------------- 1 | /* These variables used to be used when Python was built with --with-fpectl, 2 | * but support for that was dropped in 3.7. We continue to define them, 3 | * though, because they may be referenced by extensions using the stable ABI. 4 | */ 5 | 6 | #ifdef HAVE_SETJMP_H 7 | #include 8 | 9 | jmp_buf PyFPE_jbuf; 10 | #endif 11 | 12 | int PyFPE_counter; 13 | 14 | double 15 | PyFPE_dummy(void *dummy) 16 | { 17 | return 1.0; 18 | } 19 | -------------------------------------------------------------------------------- /PyMath.c: -------------------------------------------------------------------------------- 1 | #include "Python.h" 2 | 3 | 4 | #ifdef HAVE_GCC_ASM_FOR_X87 5 | // Inline assembly for getting and setting the 387 FPU control word on 6 | // GCC/x86. 7 | #ifdef _Py_MEMORY_SANITIZER 8 | __attribute__((no_sanitize_memory)) 9 | #endif 10 | unsigned short _Py_get_387controlword(void) { 11 | unsigned short cw; 12 | __asm__ __volatile__ ("fnstcw %0" : "=m" (cw)); 13 | return cw; 14 | } 15 | 16 | void _Py_set_387controlword(unsigned short cw) { 17 | __asm__ __volatile__ ("fldcw %0" : : "m" (cw)); 18 | } 19 | #endif // HAVE_GCC_ASM_FOR_X87 20 | -------------------------------------------------------------------------------- /PyStrcmp.c: -------------------------------------------------------------------------------- 1 | /* Cross platform case insensitive string compare functions 2 | */ 3 | 4 | #include "Python.h" 5 | 6 | int 7 | PyOS_mystrnicmp(const char *s1, const char *s2, Py_ssize_t size) 8 | { 9 | const unsigned char *p1, *p2; 10 | if (size == 0) 11 | return 0; 12 | p1 = (const unsigned char *)s1; 13 | p2 = (const unsigned char *)s2; 14 | for (; (--size > 0) && *p1 && *p2 && (tolower(*p1) == tolower(*p2)); 15 | p1++, p2++) { 16 | ; 17 | } 18 | return tolower(*p1) - tolower(*p2); 19 | } 20 | 21 | int 22 | PyOS_mystricmp(const char *s1, const char *s2) 23 | { 24 | const unsigned char *p1 = (const unsigned char *)s1; 25 | const unsigned char *p2 = (const unsigned char *)s2; 26 | for (; *p1 && *p2 && (tolower(*p1) == tolower(*p2)); p1++, p2++) { 27 | ; 28 | } 29 | return (tolower(*p1) - tolower(*p2)); 30 | } 31 | -------------------------------------------------------------------------------- /PyStrhex.c: -------------------------------------------------------------------------------- 1 | /* Format bytes as hexadecimal */ 2 | 3 | #include "Python.h" 4 | #include "pycore_strhex.h" // _Py_strhex_with_sep() 5 | #include // abs() 6 | 7 | static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, 8 | PyObject* sep, int bytes_per_sep_group, 9 | const int return_bytes) 10 | { 11 | assert(arglen >= 0); 12 | 13 | Py_UCS1 sep_char = 0; 14 | if (sep) { 15 | Py_ssize_t seplen = PyObject_Length((PyObject*)sep); 16 | if (seplen < 0) { 17 | return NULL; 18 | } 19 | if (seplen != 1) { 20 | PyErr_SetString(PyExc_ValueError, "sep must be length 1."); 21 | return NULL; 22 | } 23 | if (PyUnicode_Check(sep)) { 24 | if (PyUnicode_READY(sep)) 25 | return NULL; 26 | if (PyUnicode_KIND(sep) != PyUnicode_1BYTE_KIND) { 27 | PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); 28 | return NULL; 29 | } 30 | sep_char = PyUnicode_READ_CHAR(sep, 0); 31 | } 32 | else if (PyBytes_Check(sep)) { 33 | sep_char = PyBytes_AS_STRING(sep)[0]; 34 | } 35 | else { 36 | PyErr_SetString(PyExc_TypeError, "sep must be str or bytes."); 37 | return NULL; 38 | } 39 | if (sep_char > 127 && !return_bytes) { 40 | PyErr_SetString(PyExc_ValueError, "sep must be ASCII."); 41 | return NULL; 42 | } 43 | } 44 | else { 45 | bytes_per_sep_group = 0; 46 | } 47 | 48 | unsigned int abs_bytes_per_sep = abs(bytes_per_sep_group); 49 | Py_ssize_t resultlen = 0; 50 | if (bytes_per_sep_group && arglen > 0) { 51 | /* How many sep characters we'll be inserting. */ 52 | resultlen = (arglen - 1) / abs_bytes_per_sep; 53 | } 54 | /* Bounds checking for our Py_ssize_t indices. */ 55 | if (arglen >= PY_SSIZE_T_MAX / 2 - resultlen) { 56 | return PyErr_NoMemory(); 57 | } 58 | resultlen += arglen * 2; 59 | 60 | if ((size_t)abs_bytes_per_sep >= (size_t)arglen) { 61 | bytes_per_sep_group = 0; 62 | abs_bytes_per_sep = 0; 63 | } 64 | 65 | PyObject *retval; 66 | Py_UCS1 *retbuf; 67 | if (return_bytes) { 68 | /* If _PyBytes_FromSize() were public we could avoid malloc+copy. */ 69 | retval = PyBytes_FromStringAndSize(NULL, resultlen); 70 | if (!retval) { 71 | return NULL; 72 | } 73 | retbuf = (Py_UCS1 *)PyBytes_AS_STRING(retval); 74 | } 75 | else { 76 | retval = PyUnicode_New(resultlen, 127); 77 | if (!retval) { 78 | return NULL; 79 | } 80 | retbuf = PyUnicode_1BYTE_DATA(retval); 81 | } 82 | 83 | /* Hexlify */ 84 | Py_ssize_t i, j; 85 | unsigned char c; 86 | 87 | if (bytes_per_sep_group == 0) { 88 | for (i = j = 0; i < arglen; ++i) { 89 | assert((j + 1) < resultlen); 90 | c = argbuf[i]; 91 | retbuf[j++] = Py_hexdigits[c >> 4]; 92 | retbuf[j++] = Py_hexdigits[c & 0x0f]; 93 | } 94 | assert(j == resultlen); 95 | } 96 | else { 97 | /* The number of complete chunk+sep periods */ 98 | Py_ssize_t chunks = (arglen - 1) / abs_bytes_per_sep; 99 | Py_ssize_t chunk; 100 | unsigned int k; 101 | 102 | if (bytes_per_sep_group < 0) { 103 | i = j = 0; 104 | for (chunk = 0; chunk < chunks; chunk++) { 105 | for (k = 0; k < abs_bytes_per_sep; k++) { 106 | c = argbuf[i++]; 107 | retbuf[j++] = Py_hexdigits[c >> 4]; 108 | retbuf[j++] = Py_hexdigits[c & 0x0f]; 109 | } 110 | retbuf[j++] = sep_char; 111 | } 112 | while (i < arglen) { 113 | c = argbuf[i++]; 114 | retbuf[j++] = Py_hexdigits[c >> 4]; 115 | retbuf[j++] = Py_hexdigits[c & 0x0f]; 116 | } 117 | assert(j == resultlen); 118 | } 119 | else { 120 | i = arglen - 1; 121 | j = resultlen - 1; 122 | for (chunk = 0; chunk < chunks; chunk++) { 123 | for (k = 0; k < abs_bytes_per_sep; k++) { 124 | c = argbuf[i--]; 125 | retbuf[j--] = Py_hexdigits[c & 0x0f]; 126 | retbuf[j--] = Py_hexdigits[c >> 4]; 127 | } 128 | retbuf[j--] = sep_char; 129 | } 130 | while (i >= 0) { 131 | c = argbuf[i--]; 132 | retbuf[j--] = Py_hexdigits[c & 0x0f]; 133 | retbuf[j--] = Py_hexdigits[c >> 4]; 134 | } 135 | assert(j == -1); 136 | } 137 | } 138 | 139 | #ifdef Py_DEBUG 140 | if (!return_bytes) { 141 | assert(_PyUnicode_CheckConsistency(retval, 1)); 142 | } 143 | #endif 144 | 145 | return retval; 146 | } 147 | 148 | PyObject * _Py_strhex(const char* argbuf, const Py_ssize_t arglen) 149 | { 150 | return _Py_strhex_impl(argbuf, arglen, NULL, 0, 0); 151 | } 152 | 153 | /* Same as above but returns a bytes() instead of str() to avoid the 154 | * need to decode the str() when bytes are needed. */ 155 | PyObject* _Py_strhex_bytes(const char* argbuf, const Py_ssize_t arglen) 156 | { 157 | return _Py_strhex_impl(argbuf, arglen, NULL, 0, 1); 158 | } 159 | 160 | /* These variants include support for a separator between every N bytes: */ 161 | 162 | PyObject* _Py_strhex_with_sep(const char* argbuf, const Py_ssize_t arglen, 163 | PyObject* sep, const int bytes_per_group) 164 | { 165 | return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 0); 166 | } 167 | 168 | /* Same as above but returns a bytes() instead of str() to avoid the 169 | * need to decode the str() when bytes are needed. */ 170 | PyObject* _Py_strhex_bytes_with_sep(const char* argbuf, const Py_ssize_t arglen, 171 | PyObject* sep, const int bytes_per_group) 172 | { 173 | return _Py_strhex_impl(argbuf, arglen, sep, bytes_per_group, 1); 174 | } 175 | -------------------------------------------------------------------------------- /Stdlib_Module_Names.h: -------------------------------------------------------------------------------- 1 | // Auto-generated by Tools/build/generate_stdlib_module_names.py. 2 | // List used to create sys.stdlib_module_names. 3 | 4 | static const char* _Py_stdlib_module_names[] = { 5 | "__future__", 6 | "_abc", 7 | "_aix_support", 8 | "_ast", 9 | "_asyncio", 10 | "_bisect", 11 | "_blake2", 12 | "_bz2", 13 | "_codecs", 14 | "_codecs_cn", 15 | "_codecs_hk", 16 | "_codecs_iso2022", 17 | "_codecs_jp", 18 | "_codecs_kr", 19 | "_codecs_tw", 20 | "_collections", 21 | "_collections_abc", 22 | "_compat_pickle", 23 | "_compression", 24 | "_contextvars", 25 | "_csv", 26 | "_ctypes", 27 | "_curses", 28 | "_curses_panel", 29 | "_datetime", 30 | "_dbm", 31 | "_decimal", 32 | "_elementtree", 33 | "_frozen_importlib", 34 | "_frozen_importlib_external", 35 | "_functools", 36 | "_gdbm", 37 | "_hashlib", 38 | "_heapq", 39 | "_imp", 40 | "_io", 41 | "_json", 42 | "_locale", 43 | "_lsprof", 44 | "_lzma", 45 | "_markupbase", 46 | "_md5", 47 | "_multibytecodec", 48 | "_multiprocessing", 49 | "_opcode", 50 | "_operator", 51 | "_osx_support", 52 | "_overlapped", 53 | "_pickle", 54 | "_posixshmem", 55 | "_posixsubprocess", 56 | "_py_abc", 57 | "_pydatetime", 58 | "_pydecimal", 59 | "_pyio", 60 | "_pylong", 61 | "_queue", 62 | "_random", 63 | "_scproxy", 64 | "_sha1", 65 | "_sha2", 66 | "_sha3", 67 | "_signal", 68 | "_sitebuiltins", 69 | "_socket", 70 | "_sqlite3", 71 | "_sre", 72 | "_ssl", 73 | "_stat", 74 | "_statistics", 75 | "_string", 76 | "_strptime", 77 | "_struct", 78 | "_symtable", 79 | "_thread", 80 | "_threading_local", 81 | "_tkinter", 82 | "_tokenize", 83 | "_tracemalloc", 84 | "_typing", 85 | "_uuid", 86 | "_warnings", 87 | "_weakref", 88 | "_weakrefset", 89 | "_winapi", 90 | "_zoneinfo", 91 | "abc", 92 | "antigravity", 93 | "argparse", 94 | "array", 95 | "ast", 96 | "asyncio", 97 | "atexit", 98 | "base64", 99 | "bdb", 100 | "binascii", 101 | "bisect", 102 | "builtins", 103 | "bz2", 104 | "cProfile", 105 | "calendar", 106 | "cmath", 107 | "cmd", 108 | "code", 109 | "codecs", 110 | "codeop", 111 | "collections", 112 | "colorsys", 113 | "compileall", 114 | "concurrent", 115 | "configparser", 116 | "contextlib", 117 | "contextvars", 118 | "copy", 119 | "copyreg", 120 | "csv", 121 | "ctypes", 122 | "curses", 123 | "dataclasses", 124 | "datetime", 125 | "dbm", 126 | "decimal", 127 | "difflib", 128 | "dis", 129 | "doctest", 130 | "email", 131 | "encodings", 132 | "ensurepip", 133 | "enum", 134 | "errno", 135 | "faulthandler", 136 | "fcntl", 137 | "filecmp", 138 | "fileinput", 139 | "fnmatch", 140 | "fractions", 141 | "ftplib", 142 | "functools", 143 | "gc", 144 | "genericpath", 145 | "getopt", 146 | "getpass", 147 | "gettext", 148 | "glob", 149 | "graphlib", 150 | "grp", 151 | "gzip", 152 | "hashlib", 153 | "heapq", 154 | "hmac", 155 | "html", 156 | "http", 157 | "idlelib", 158 | "imaplib", 159 | "importlib", 160 | "inspect", 161 | "io", 162 | "ipaddress", 163 | "itertools", 164 | "json", 165 | "keyword", 166 | "linecache", 167 | "locale", 168 | "logging", 169 | "lzma", 170 | "mailbox", 171 | "marshal", 172 | "math", 173 | "mimetypes", 174 | "mmap", 175 | "modulefinder", 176 | "msvcrt", 177 | "multiprocessing", 178 | "netrc", 179 | "nt", 180 | "ntpath", 181 | "nturl2path", 182 | "numbers", 183 | "opcode", 184 | "operator", 185 | "optparse", 186 | "os", 187 | "pathlib", 188 | "pdb", 189 | "pickle", 190 | "pickletools", 191 | "pkgutil", 192 | "platform", 193 | "plistlib", 194 | "poplib", 195 | "posix", 196 | "posixpath", 197 | "pprint", 198 | "profile", 199 | "pstats", 200 | "pty", 201 | "pwd", 202 | "py_compile", 203 | "pyclbr", 204 | "pydoc", 205 | "pydoc_data", 206 | "pyexpat", 207 | "queue", 208 | "quopri", 209 | "random", 210 | "re", 211 | "readline", 212 | "reprlib", 213 | "resource", 214 | "rlcompleter", 215 | "runpy", 216 | "sched", 217 | "secrets", 218 | "select", 219 | "selectors", 220 | "shelve", 221 | "shlex", 222 | "shutil", 223 | "signal", 224 | "site", 225 | "smtplib", 226 | "socket", 227 | "socketserver", 228 | "sqlite3", 229 | "sre_compile", 230 | "sre_constants", 231 | "sre_parse", 232 | "ssl", 233 | "stat", 234 | "statistics", 235 | "string", 236 | "stringprep", 237 | "struct", 238 | "subprocess", 239 | "symtable", 240 | "sys", 241 | "sysconfig", 242 | "syslog", 243 | "tabnanny", 244 | "tarfile", 245 | "tempfile", 246 | "termios", 247 | "textwrap", 248 | "this", 249 | "threading", 250 | "time", 251 | "timeit", 252 | "tkinter", 253 | "token", 254 | "tokenize", 255 | "tomllib", 256 | "trace", 257 | "traceback", 258 | "tracemalloc", 259 | "tty", 260 | "turtle", 261 | "turtledemo", 262 | "types", 263 | "typing", 264 | "unicodedata", 265 | "unittest", 266 | "urllib", 267 | "uuid", 268 | "venv", 269 | "warnings", 270 | "wave", 271 | "weakref", 272 | "webbrowser", 273 | "winreg", 274 | "winsound", 275 | "wsgiref", 276 | "xml", 277 | "xmlrpc", 278 | "zipapp", 279 | "zipfile", 280 | "zipimport", 281 | "zlib", 282 | "zoneinfo", 283 | }; 284 | -------------------------------------------------------------------------------- /Thread.c: -------------------------------------------------------------------------------- 1 | 2 | /* Thread package. 3 | This is intended to be usable independently from Python. 4 | The implementation for system foobar is in a file thread_foobar.h 5 | which is included by this file dependent on config settings. 6 | Stuff shared by all thread_*.h files is collected here. */ 7 | 8 | #include "Python.h" 9 | #include "pycore_pystate.h" // _PyInterpreterState_GET() 10 | #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() 11 | #include "pycore_pythread.h" 12 | 13 | #ifndef DONT_HAVE_STDIO_H 14 | #include 15 | #endif 16 | 17 | #include 18 | 19 | 20 | static void PyThread__init_thread(void); /* Forward */ 21 | 22 | #define initialized _PyRuntime.threads.initialized 23 | 24 | void 25 | PyThread_init_thread(void) 26 | { 27 | if (initialized) { 28 | return; 29 | } 30 | initialized = 1; 31 | PyThread__init_thread(); 32 | } 33 | 34 | #if defined(HAVE_PTHREAD_STUBS) 35 | # define PYTHREAD_NAME "pthread-stubs" 36 | # include "thread_pthread_stubs.h" 37 | #elif defined(_USE_PTHREADS) /* AKA _PTHREADS */ 38 | # if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__) 39 | # define PYTHREAD_NAME "pthread-stubs" 40 | # else 41 | # define PYTHREAD_NAME "pthread" 42 | # endif 43 | # include "thread_pthread.h" 44 | #elif defined(NT_THREADS) 45 | # define PYTHREAD_NAME "nt" 46 | # include "thread_nt.h" 47 | #else 48 | # error "Require native threads. See https://bugs.python.org/issue31370" 49 | #endif 50 | 51 | 52 | /* return the current thread stack size */ 53 | size_t 54 | PyThread_get_stacksize(void) 55 | { 56 | return _PyInterpreterState_GET()->threads.stacksize; 57 | } 58 | 59 | /* Only platforms defining a THREAD_SET_STACKSIZE() macro 60 | in thread_.h support changing the stack size. 61 | Return 0 if stack size is valid, 62 | -1 if stack size value is invalid, 63 | -2 if setting stack size is not supported. */ 64 | int 65 | PyThread_set_stacksize(size_t size) 66 | { 67 | #if defined(THREAD_SET_STACKSIZE) 68 | return THREAD_SET_STACKSIZE(size); 69 | #else 70 | return -2; 71 | #endif 72 | } 73 | 74 | 75 | /* Thread Specific Storage (TSS) API 76 | 77 | Cross-platform components of TSS API implementation. 78 | */ 79 | 80 | Py_tss_t * 81 | PyThread_tss_alloc(void) 82 | { 83 | Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t)); 84 | if (new_key == NULL) { 85 | return NULL; 86 | } 87 | new_key->_is_initialized = 0; 88 | return new_key; 89 | } 90 | 91 | void 92 | PyThread_tss_free(Py_tss_t *key) 93 | { 94 | if (key != NULL) { 95 | PyThread_tss_delete(key); 96 | PyMem_RawFree((void *)key); 97 | } 98 | } 99 | 100 | int 101 | PyThread_tss_is_created(Py_tss_t *key) 102 | { 103 | assert(key != NULL); 104 | return key->_is_initialized; 105 | } 106 | 107 | 108 | PyDoc_STRVAR(threadinfo__doc__, 109 | "sys.thread_info\n\ 110 | \n\ 111 | A named tuple holding information about the thread implementation."); 112 | 113 | static PyStructSequence_Field threadinfo_fields[] = { 114 | {"name", "name of the thread implementation"}, 115 | {"lock", "name of the lock implementation"}, 116 | {"version", "name and version of the thread library"}, 117 | {0} 118 | }; 119 | 120 | static PyStructSequence_Desc threadinfo_desc = { 121 | "sys.thread_info", /* name */ 122 | threadinfo__doc__, /* doc */ 123 | threadinfo_fields, /* fields */ 124 | 3 125 | }; 126 | 127 | static PyTypeObject ThreadInfoType; 128 | 129 | PyObject* 130 | PyThread_GetInfo(void) 131 | { 132 | PyObject *threadinfo, *value; 133 | int pos = 0; 134 | #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ 135 | && defined(_CS_GNU_LIBPTHREAD_VERSION)) 136 | char buffer[255]; 137 | int len; 138 | #endif 139 | 140 | PyInterpreterState *interp = _PyInterpreterState_GET(); 141 | if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) { 142 | return NULL; 143 | } 144 | 145 | threadinfo = PyStructSequence_New(&ThreadInfoType); 146 | if (threadinfo == NULL) 147 | return NULL; 148 | 149 | value = PyUnicode_FromString(PYTHREAD_NAME); 150 | if (value == NULL) { 151 | Py_DECREF(threadinfo); 152 | return NULL; 153 | } 154 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); 155 | 156 | #ifdef HAVE_PTHREAD_STUBS 157 | value = Py_NewRef(Py_None); 158 | #elif defined(_POSIX_THREADS) 159 | #ifdef USE_SEMAPHORES 160 | value = PyUnicode_FromString("semaphore"); 161 | #else 162 | value = PyUnicode_FromString("mutex+cond"); 163 | #endif 164 | if (value == NULL) { 165 | Py_DECREF(threadinfo); 166 | return NULL; 167 | } 168 | #else 169 | value = Py_NewRef(Py_None); 170 | #endif 171 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); 172 | 173 | #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ 174 | && defined(_CS_GNU_LIBPTHREAD_VERSION)) 175 | value = NULL; 176 | len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); 177 | if (1 < len && (size_t)len < sizeof(buffer)) { 178 | value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); 179 | if (value == NULL) 180 | PyErr_Clear(); 181 | } 182 | if (value == NULL) 183 | #endif 184 | { 185 | value = Py_NewRef(Py_None); 186 | } 187 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); 188 | return threadinfo; 189 | } 190 | 191 | 192 | void 193 | _PyThread_FiniType(PyInterpreterState *interp) 194 | { 195 | _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); 196 | } 197 | -------------------------------------------------------------------------------- /Thread_Pthread_Dtubs.h: -------------------------------------------------------------------------------- 1 | #include "cpython/pthread_stubs.h" 2 | 3 | // mutex 4 | int 5 | pthread_mutex_init(pthread_mutex_t *restrict mutex, 6 | const pthread_mutexattr_t *restrict attr) 7 | { 8 | return 0; 9 | } 10 | 11 | int 12 | pthread_mutex_destroy(pthread_mutex_t *mutex) 13 | { 14 | return 0; 15 | } 16 | 17 | int 18 | pthread_mutex_trylock(pthread_mutex_t *mutex) 19 | { 20 | return 0; 21 | } 22 | 23 | int 24 | pthread_mutex_lock(pthread_mutex_t *mutex) 25 | { 26 | return 0; 27 | } 28 | 29 | int 30 | pthread_mutex_unlock(pthread_mutex_t *mutex) 31 | { 32 | return 0; 33 | } 34 | 35 | // condition 36 | int 37 | pthread_cond_init(pthread_cond_t *restrict cond, 38 | const pthread_condattr_t *restrict attr) 39 | { 40 | return 0; 41 | } 42 | 43 | PyAPI_FUNC(int)pthread_cond_destroy(pthread_cond_t *cond) 44 | { 45 | return 0; 46 | } 47 | 48 | int 49 | pthread_cond_wait(pthread_cond_t *restrict cond, 50 | pthread_mutex_t *restrict mutex) 51 | { 52 | return 0; 53 | } 54 | 55 | int 56 | pthread_cond_timedwait(pthread_cond_t *restrict cond, 57 | pthread_mutex_t *restrict mutex, 58 | const struct timespec *restrict abstime) 59 | { 60 | return 0; 61 | } 62 | 63 | int 64 | pthread_cond_signal(pthread_cond_t *cond) 65 | { 66 | return 0; 67 | } 68 | 69 | int 70 | pthread_condattr_init(pthread_condattr_t *attr) 71 | { 72 | return 0; 73 | } 74 | 75 | int 76 | pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id) 77 | { 78 | return 0; 79 | } 80 | 81 | // pthread 82 | int 83 | pthread_create(pthread_t *restrict thread, 84 | const pthread_attr_t *restrict attr, 85 | void *(*start_routine)(void *), 86 | void *restrict arg) 87 | { 88 | return EAGAIN; 89 | } 90 | 91 | int 92 | pthread_detach(pthread_t thread) 93 | { 94 | return 0; 95 | } 96 | 97 | PyAPI_FUNC(pthread_t) pthread_self(void) 98 | { 99 | return 0; 100 | } 101 | 102 | int 103 | pthread_exit(void *retval) 104 | { 105 | exit(0); 106 | } 107 | 108 | int 109 | pthread_attr_init(pthread_attr_t *attr) 110 | { 111 | return 0; 112 | } 113 | 114 | int 115 | pthread_attr_setstacksize( 116 | pthread_attr_t *attr, size_t stacksize) 117 | { 118 | return 0; 119 | } 120 | 121 | int 122 | pthread_attr_destroy(pthread_attr_t *attr) 123 | { 124 | return 0; 125 | } 126 | 127 | 128 | typedef struct py_stub_tls_entry py_tls_entry; 129 | 130 | #define py_tls_entries (_PyRuntime.threads.stubs.tls_entries) 131 | 132 | int 133 | pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) 134 | { 135 | if (!key) { 136 | return EINVAL; 137 | } 138 | if (destr_function != NULL) { 139 | Py_FatalError("pthread_key_create destructor is not supported"); 140 | } 141 | for (pthread_key_t idx = 0; idx < PTHREAD_KEYS_MAX; idx++) { 142 | if (!py_tls_entries[idx].in_use) { 143 | py_tls_entries[idx].in_use = true; 144 | *key = idx; 145 | return 0; 146 | } 147 | } 148 | return EAGAIN; 149 | } 150 | 151 | int 152 | pthread_key_delete(pthread_key_t key) 153 | { 154 | if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { 155 | return EINVAL; 156 | } 157 | py_tls_entries[key].in_use = false; 158 | py_tls_entries[key].value = NULL; 159 | return 0; 160 | } 161 | 162 | 163 | void * 164 | pthread_getspecific(pthread_key_t key) { 165 | if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { 166 | return NULL; 167 | } 168 | return py_tls_entries[key].value; 169 | } 170 | 171 | int 172 | pthread_setspecific(pthread_key_t key, const void *value) 173 | { 174 | if (key < 0 || key >= PTHREAD_KEYS_MAX || !py_tls_entries[key].in_use) { 175 | return EINVAL; 176 | } 177 | py_tls_entries[key].value = (void *)value; 178 | return 0; 179 | } 180 | 181 | // let thread_pthread define the Python API 182 | #include "thread_pthread.h" 183 | --------------------------------------------------------------------------------