1
0

codeobject.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #pragma once
  2. #include "obj.h"
  3. #include "error.h"
  4. namespace pkpy{
  5. enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
  6. enum Opcode: uint8_t {
  7. #define OPCODE(name) OP_##name,
  8. #include "opcodes.h"
  9. #undef OPCODE
  10. };
  11. inline const char* OP_NAMES[] = {
  12. #define OPCODE(name) #name,
  13. #include "opcodes.h"
  14. #undef OPCODE
  15. };
  16. struct Bytecode{
  17. uint8_t op;
  18. uint16_t arg;
  19. };
  20. enum class CodeBlockType {
  21. NO_BLOCK,
  22. FOR_LOOP,
  23. WHILE_LOOP,
  24. CONTEXT_MANAGER,
  25. TRY_EXCEPT,
  26. };
  27. inline const uint8_t BC_NOARG = 0;
  28. inline const int BC_KEEPLINE = -1;
  29. struct CodeBlock {
  30. CodeBlockType type;
  31. int parent; // parent index in blocks
  32. int base_stack_size; // this is used for exception handling
  33. int start; // start index of this block in codes, inclusive
  34. int end; // end index of this block in codes, exclusive
  35. int end2; // ...
  36. CodeBlock(CodeBlockType type, int parent, int base_stack_size, int start):
  37. type(type), parent(parent), base_stack_size(base_stack_size), start(start), end(-1), end2(-1) {}
  38. int get_break_end() const{
  39. if(end2 != -1) return end2;
  40. return end;
  41. }
  42. };
  43. struct CodeObject;
  44. struct FuncDecl;
  45. using CodeObject_ = std::shared_ptr<CodeObject>;
  46. using FuncDecl_ = std::shared_ptr<FuncDecl>;
  47. struct CodeObject {
  48. struct LineInfo{
  49. int lineno; // line number for each bytecode
  50. bool is_virtual; // whether this bytecode is virtual (not in source code)
  51. };
  52. std::shared_ptr<SourceData> src;
  53. Str name;
  54. bool is_generator;
  55. std::vector<Bytecode> codes;
  56. std::vector<int> iblocks; // block index for each bytecode
  57. std::vector<LineInfo> lines;
  58. small_vector_no_copy_and_move<PyObject*, 8> consts; // constants
  59. small_vector_no_copy_and_move<StrName, 8> varnames; // local variables
  60. NameDictInt varnames_inv;
  61. std::vector<CodeBlock> blocks;
  62. NameDictInt labels;
  63. std::vector<FuncDecl_> func_decls;
  64. int start_line;
  65. int end_line;
  66. const CodeBlock& _get_block_codei(int codei) const{
  67. return blocks[iblocks[codei]];
  68. }
  69. CodeObject(std::shared_ptr<SourceData> src, const Str& name);
  70. void _gc_mark() const;
  71. };
  72. struct FuncDecl {
  73. struct KwArg {
  74. int index; // index in co->varnames
  75. StrName key; // name of this argument
  76. PyObject* value; // default value
  77. };
  78. CodeObject_ code; // code object of this function
  79. small_vector_no_copy_and_move<int, 6> args; // indices in co->varnames
  80. small_vector_no_copy_and_move<KwArg, 6> kwargs; // indices in co->varnames
  81. int starred_arg = -1; // index in co->varnames, -1 if no *arg
  82. int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
  83. bool nested = false; // whether this function is nested
  84. Str signature; // signature of this function
  85. Str docstring; // docstring of this function
  86. bool is_simple; // whether this function is simple (no *arg, **kwarg, nested)
  87. bool is_empty; // whether this function is empty (no code)
  88. NameDictInt kw_to_index;
  89. void add_kwarg(int index, StrName key, PyObject* value){
  90. kw_to_index.set(key, index);
  91. kwargs.push_back(KwArg{index, key, value});
  92. }
  93. void _gc_mark() const;
  94. };
  95. struct UserData{
  96. char data[12];
  97. bool empty;
  98. UserData(): empty(true) {}
  99. template<typename T>
  100. UserData(T t): empty(false){
  101. static_assert(std::is_trivially_copyable_v<T>);
  102. static_assert(sizeof(T) <= sizeof(data));
  103. memcpy(data, &t, sizeof(T));
  104. }
  105. template <typename T>
  106. T get() const{
  107. static_assert(std::is_trivially_copyable_v<T>);
  108. static_assert(sizeof(T) <= sizeof(data));
  109. #if PK_DEBUG_EXTRA_CHECK
  110. PK_ASSERT(!empty);
  111. #endif
  112. return reinterpret_cast<const T&>(data);
  113. }
  114. };
  115. struct NativeFunc {
  116. NativeFuncC f;
  117. // old style argc-based call
  118. int argc;
  119. // new style decl-based call
  120. FuncDecl_ decl;
  121. UserData _userdata;
  122. void set_userdata(UserData data) {
  123. if(!_userdata.empty && !data.empty){
  124. // override is not supported
  125. throw std::runtime_error("userdata already set");
  126. }
  127. _userdata = data;
  128. }
  129. NativeFunc(NativeFuncC f, int argc, bool method);
  130. NativeFunc(NativeFuncC f, FuncDecl_ decl);
  131. void check_size(VM* vm, ArgsView args) const;
  132. PyObject* call(VM* vm, ArgsView args) const;
  133. };
  134. struct Function{
  135. FuncDecl_ decl;
  136. PyObject* _module; // weak ref
  137. PyObject* _class; // weak ref
  138. NameDict_ _closure;
  139. explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure):
  140. decl(decl), _module(_module), _class(_class), _closure(_closure) {}
  141. };
  142. template<>
  143. struct Py_<Function> final: PyObject {
  144. Function _value;
  145. template<typename... Args>
  146. Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
  147. // _enable_instance_dict();
  148. }
  149. void _obj_gc_mark() override {
  150. _value.decl->_gc_mark();
  151. if(_value._closure != nullptr) gc_mark_namedict(*_value._closure);
  152. }
  153. void* _value_ptr() override {
  154. return &_value;
  155. }
  156. };
  157. template<>
  158. struct Py_<NativeFunc> final: PyObject {
  159. NativeFunc _value;
  160. template<typename... Args>
  161. Py_(Type type, Args&&... args): PyObject(type), _value(std::forward<Args>(args)...) {
  162. // _enable_instance_dict();
  163. }
  164. void _obj_gc_mark() override {
  165. if(_value.decl != nullptr){
  166. _value.decl->_gc_mark();
  167. }
  168. }
  169. void* _value_ptr() override {
  170. return &_value;
  171. }
  172. };
  173. template<typename T>
  174. T lambda_get_userdata(PyObject** p){
  175. if(p[-1] != PY_NULL) return PK_OBJ_GET(NativeFunc, p[-1])._userdata.get<T>();
  176. else return PK_OBJ_GET(NativeFunc, p[-2])._userdata.get<T>();
  177. }
  178. } // namespace pkpy