1
0

codeobject.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #pragma once
  2. #include "pocketpy/common/any.h"
  3. #include "pocketpy/objects/tuplelist.hpp"
  4. #include "pocketpy/objects/namedict.hpp"
  5. #include "pocketpy/objects/sourcedata.hpp"
  6. namespace pkpy {
  7. #if PK_ENABLE_STD_FUNCTION
  8. using NativeFuncC = function<PyVar(VM*, ArgsView)>;
  9. #else
  10. typedef PyVar (*NativeFuncC)(VM*, ArgsView);
  11. #endif
  12. enum class BindType {
  13. DEFAULT,
  14. STATICMETHOD,
  15. CLASSMETHOD,
  16. };
  17. enum NameScope { NAME_LOCAL, NAME_GLOBAL, NAME_GLOBAL_UNKNOWN };
  18. enum Opcode : uint8_t {
  19. #define OPCODE(name) OP_##name,
  20. #include "pocketpy/opcodes.h"
  21. #undef OPCODE
  22. };
  23. struct Bytecode {
  24. uint8_t op;
  25. uint16_t arg;
  26. void set_signed_arg(int arg) {
  27. assert(arg >= INT16_MIN && arg <= INT16_MAX);
  28. this->arg = (int16_t)arg;
  29. }
  30. bool is_forward_jump() const { return op >= OP_JUMP_FORWARD && op <= OP_LOOP_BREAK; }
  31. };
  32. enum class CodeBlockType {
  33. NO_BLOCK,
  34. FOR_LOOP,
  35. WHILE_LOOP,
  36. CONTEXT_MANAGER,
  37. TRY_EXCEPT,
  38. };
  39. const inline uint8_t BC_NOARG = 0;
  40. const inline int BC_KEEPLINE = -1;
  41. struct CodeBlock {
  42. CodeBlockType type;
  43. int parent; // parent index in blocks
  44. int start; // start index of this block in codes, inclusive
  45. int end; // end index of this block in codes, exclusive
  46. int end2; // ...
  47. CodeBlock(CodeBlockType type, int parent, int start) :
  48. type(type), parent(parent), start(start), end(-1), end2(-1) {}
  49. int get_break_end() const {
  50. if(end2 != -1) return end2;
  51. return end;
  52. }
  53. };
  54. struct CodeObject;
  55. struct FuncDecl;
  56. using CodeObject_ = std::shared_ptr<CodeObject>;
  57. using FuncDecl_ = std::shared_ptr<FuncDecl>;
  58. struct CodeObject {
  59. struct LineInfo {
  60. int lineno; // line number for each bytecode
  61. bool is_virtual; // whether this bytecode is virtual (not in source code)
  62. int iblock; // block index
  63. };
  64. std::shared_ptr<SourceData> src;
  65. Str name;
  66. vector<Bytecode> codes;
  67. vector<LineInfo> lines;
  68. small_vector_2<PyVar, 8> consts; // constants
  69. small_vector_2<StrName, 8> varnames; // local variables
  70. int nlocals; // varnames.size()
  71. small_map<StrName, int> varnames_inv;
  72. vector<CodeBlock> blocks;
  73. small_map<StrName, int> labels;
  74. vector<FuncDecl_> func_decls;
  75. int start_line;
  76. int end_line;
  77. const CodeBlock& _get_block_codei(int codei) const { return blocks[lines[codei].iblock]; }
  78. CodeObject(std::shared_ptr<SourceData> src, const Str& name);
  79. void _gc_mark(VM*) const;
  80. };
  81. enum class FuncType {
  82. UNSET,
  83. NORMAL,
  84. SIMPLE,
  85. EMPTY,
  86. GENERATOR,
  87. };
  88. struct FuncDecl {
  89. struct KwArg {
  90. int index; // index in co->varnames
  91. StrName key; // name of this argument
  92. PyVar value; // default value
  93. };
  94. CodeObject_ code; // code object of this function
  95. small_vector_2<int, 8> args; // indices in co->varnames
  96. small_vector_2<KwArg, 6> kwargs; // indices in co->varnames
  97. int starred_arg = -1; // index in co->varnames, -1 if no *arg
  98. int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
  99. bool nested = false; // whether this function is nested
  100. const char* docstring; // docstring of this function (weak ref)
  101. FuncType type = FuncType::UNSET;
  102. small_map<StrName, int> kw_to_index;
  103. void add_kwarg(int index, StrName key, PyVar value) {
  104. kw_to_index.insert(key, index);
  105. kwargs.push_back(KwArg{index, key, value});
  106. }
  107. void _gc_mark(VM*) const;
  108. };
  109. struct NativeFunc {
  110. NativeFuncC f;
  111. int argc; // old style argc-based call
  112. FuncDecl_ decl; // new style decl-based call
  113. any _userdata;
  114. NativeFunc(NativeFuncC f, int argc, any userdata = {}) :
  115. f(f), argc(argc), decl(nullptr), _userdata(std::move(userdata)) {}
  116. NativeFunc(NativeFuncC f, FuncDecl_ decl, any userdata = {}) :
  117. f(f), argc(-1), decl(decl), _userdata(std::move(userdata)) {}
  118. PyVar call(VM* vm, ArgsView args) const { return f(vm, args); }
  119. void _gc_mark(VM*) const;
  120. };
  121. struct Function {
  122. FuncDecl_ decl;
  123. PyObject* _module; // weak ref
  124. PyObject* _class; // weak ref
  125. NameDict_ _closure;
  126. explicit Function(FuncDecl_ decl, PyObject* _module, PyObject* _class, NameDict_ _closure) :
  127. decl(decl), _module(_module), _class(_class), _closure(_closure) {}
  128. void _gc_mark(VM*) const;
  129. };
  130. template <typename T>
  131. T lambda_get_userdata(PyVar* p) {
  132. static_assert(std::is_same_v<T, std::decay_t<T>>);
  133. static_assert(is_pod_v<T>);
  134. int offset = p[-1] != nullptr ? -1 : -2;
  135. NativeFunc& nf = p[offset].obj_get<NativeFunc>();
  136. return nf._userdata.as<T>();
  137. }
  138. } // namespace pkpy