1# Copyright 2021, Kay Hayen, mailto:kay.hayen@gmail.com 2# 3# Part of "Nuitka", an optimizing Python compiler that is compatible and 4# integrates with CPython, but also works on its own. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18""" Code generation for code objects. 19 20Right now only the creation is done here. But more should be added later on. 21""" 22 23import os 24 25from nuitka import Options 26 27 28def getCodeObjectsDeclCode(context): 29 statements = [] 30 31 for _code_object_key, code_identifier in context.getCodeObjects(): 32 declaration = "static PyCodeObject *%s;" % code_identifier 33 34 statements.append(declaration) 35 36 if context.getOwner().getFullName() == "__main__": 37 statements.append('/* For use in "MainProgram.c". */') 38 statements.append("PyCodeObject *codeobj_main = NULL;") 39 40 return statements 41 42 43def _getMakeCodeObjectArgs(code_object_handle, context): 44 """Code objects have many flags for creation. 45 46 This is also version dependent, but we hide this behind macros 47 that ignore some arguments. 48 """ 49 50 co_flags = [] 51 52 if code_object_handle.co_kind in ("Module", "Class", "Function"): 53 pass 54 elif code_object_handle.co_kind == "Generator": 55 co_flags.append("CO_GENERATOR") 56 elif code_object_handle.co_kind == "Coroutine": 57 co_flags.append("CO_COROUTINE") 58 elif code_object_handle.co_kind == "Asyncgen": 59 co_flags.append("CO_ASYNC_GENERATOR") 60 else: 61 assert False, code_object_handle.co_kind 62 63 if code_object_handle.is_optimized: 64 co_flags.append("CO_OPTIMIZED") 65 66 if code_object_handle.co_new_locals: 67 co_flags.append("CO_NEWLOCALS") 68 69 if code_object_handle.co_has_starlist: 70 co_flags.append("CO_VARARGS") 71 72 if code_object_handle.co_has_stardict: 73 co_flags.append("CO_VARKEYWORDS") 74 75 if not code_object_handle.co_freevars: 76 co_flags.append("CO_NOFREE") 77 78 co_flags.extend(code_object_handle.future_flags) 79 80 return ( 81 code_object_handle.line_number, 82 " | ".join(co_flags) or "0", 83 context.getConstantCode(constant=code_object_handle.co_name), 84 context.getConstantCode(constant=code_object_handle.co_varnames) 85 if code_object_handle.co_varnames 86 else "NULL", 87 context.getConstantCode(constant=code_object_handle.co_freevars) 88 if code_object_handle.co_freevars 89 else "NULL", 90 code_object_handle.co_argcount, 91 code_object_handle.co_kwonlyargcount, 92 code_object_handle.co_posonlyargcount, 93 ) 94 95 96def getCodeObjectsInitCode(context): 97 # There is a bit of details to this, and we are making some optimizations as 98 # well as customization to what path should be put there. 99 100 statements = [] 101 102 code_objects = context.getCodeObjects() 103 104 # Create the always identical, but dynamic filename first thing. 105 module_filename = context.getOwner().getRunTimeFilename() 106 107 # We do not care about release of this object, as code object live 108 # forever anyway. 109 if Options.getFileReferenceMode() == "frozen" or os.path.isabs(module_filename): 110 template = "module_filename_obj = %s; CHECK_OBJECT(module_filename_obj);" 111 else: 112 template = "module_filename_obj = MAKE_RELATIVE_PATH(%s); CHECK_OBJECT(module_filename_obj);" 113 114 statements.append(template % (context.getConstantCode(constant=module_filename))) 115 116 for code_object_key, code_identifier in code_objects: 117 # Make sure the filename is always identical. 118 assert code_object_key.co_filename == module_filename, code_object_key 119 120 args = ( 121 code_identifier, 122 ", ".join(str(s) for s in _getMakeCodeObjectArgs(code_object_key, context)), 123 ) 124 125 code = "%s = MAKE_CODEOBJECT(module_filename_obj, %s);" % args 126 127 statements.append(code) 128 129 if context.getOwner().getFullName() == "__main__": 130 if code_object_key[1] == "<module>": 131 statements.append("codeobj_main = %s;" % code_identifier) 132 133 return statements 134