1 // Python Tools for Visual Studio
2 // Copyright(c) Microsoft Corporation
3 // All rights reserved.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License); you may not use
6 // this file except in compliance with the License. You may obtain a copy of the
7 // License at http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // THIS CODE IS PROVIDED ON AN  *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
10 // OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
11 // IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
12 // MERCHANTABILITY OR NON-INFRINGEMENT.
13 //
14 // See the Apache Version 2.0 License for specific language governing
15 // permissions and limitations under the License.
16 
17 #ifndef __PYTHON_H__
18 #define __PYTHON_H__
19 
20 #include "../common/py_version.hpp"
21 
22 #ifndef _WIN32
23 typedef unsigned int DWORD;
24 typedef ssize_t SSIZE_T;
25 #endif
26 typedef SSIZE_T Py_ssize_t;
27 
28 // defines limited header of Python API for compatible access across a number of Pythons.
29 
30 class PyTypeObject;
31 class PyThreadState;
32 
33 #define PyObject_HEAD           \
34     size_t ob_refcnt;           \
35     PyTypeObject *ob_type;
36 
37 #define PyObject_VAR_HEAD       \
38     PyObject_HEAD               \
39     size_t ob_size; /* Number of items in variable part */
40 
41 class PyObject {
42 public:
43     PyObject_HEAD
44 };
45 
46 class PyVarObject : public PyObject {
47 public:
48     size_t ob_size; /* Number of items in variable part */
49 };
50 
51 // 2.5 - 3.7
52 class PyFunctionObject : public PyObject {
53 public:
54     PyObject *func_code;    /* A code object */
55 };
56 
57 // 2.5 - 2.7 compatible
58 class PyStringObject : public PyVarObject {
59 public:
60     long ob_shash;
61     int ob_sstate;
62     char ob_sval[1];
63 
64     /* Invariants:
65      *     ob_sval contains space for 'ob_size+1' elements.
66      *     ob_sval[ob_size] == 0.
67      *     ob_shash is the hash of the string or -1 if not computed yet.
68      *     ob_sstate != 0 iff the string object is in stringobject.c's
69      *       'interned' dictionary; in this case the two references
70      *       from 'interned' to this object are *not counted* in ob_refcnt.
71      */
72 };
73 
74 // 2.4 - 3.7 compatible
75 typedef struct {
76     PyObject_HEAD
77     size_t length;      /* Length of raw Unicode data in buffer */
78     wchar_t *str;       /* Raw Unicode buffer */
79     long hash;          /* Hash value; -1 if not set */
80 } PyUnicodeObject;
81 
82 
83 class PyFrameObject : public PyVarObject {
84     // After 3.10 we don't really have things we want to reuse common, so,
85     // create an empty base (based on PyVarObject).
86 };
87 
88 // 2.4 - 3.7 compatible
89 class PyFrameObjectBaseUpTo39 : public PyFrameObject {
90 public:
91     PyFrameObjectBaseUpTo39 *f_back;  /* previous frame, or nullptr */
92     PyObject *f_code;           /* code segment */
93     PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
94     PyObject *f_globals;        /* global symbol table (PyDictObject) */
95     PyObject *f_locals;         /* local symbol table (any mapping) */
96     PyObject **f_valuestack;    /* points after the last local */
97     /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
98        Frame evaluation usually NULLs it, but a frame that yields sets it
99        to the current stack top. */
100     PyObject **f_stacktop;
101     PyObject *f_trace;          /* Trace function */
102 
103     // It has more things, but we're only interested in things up to f_trace.
104 
105 };
106 
107 
108 // https://github.com/python/cpython/blob/3.10/Include/cpython/frameobject.h
109 class PyFrameObject310 : public PyFrameObject {
110 public:
111     PyFrameObject310 *f_back;      /* previous frame, or NULL */
112     PyObject *f_code;       /* code segment */
113     PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
114     PyObject *f_globals;        /* global symbol table (PyDictObject) */
115     PyObject *f_locals;         /* local symbol table (any mapping) */
116     PyObject **f_valuestack;    /* points after the last local */
117     PyObject *f_trace;          /* Trace function */
118 
119     // It has more things, but we're only interested in things up to f_trace.
120 };
121 
122 
123 typedef void (*destructor)(PyObject *);
124 
125 // 2.4 - 3.7
126 class PyMethodDef {
127 public:
128     char    *ml_name;    /* The name of the built-in function/method */
129 };
130 
131 
132 //
133 // 2.5 - 3.7
134 // While these are compatible there are fields only available on later versions.
135 class PyTypeObject : public PyVarObject {
136 public:
137     const char *tp_name; /* For printing, in format "<module>.<name>" */
138     size_t tp_basicsize, tp_itemsize; /* For allocation */
139 
140     /* Methods to implement standard operations */
141 
142     destructor tp_dealloc;
143     void *tp_print;
144     void *tp_getattr;
145     void *tp_setattr;
146     union {
147         void *tp_compare; /* 2.4 - 3.4 */
148         void *tp_as_async; /* 3.5 - 3.7 */
149     };
150     void *tp_repr;
151 
152     /* Method suites for standard classes */
153 
154     void *tp_as_number;
155     void *tp_as_sequence;
156     void *tp_as_mapping;
157 
158     /* More standard operations (here for binary compatibility) */
159 
160     void *tp_hash;
161     void *tp_call;
162     void *tp_str;
163     void *tp_getattro;
164     void *tp_setattro;
165 
166     /* Functions to access object as input/output buffer */
167     void *tp_as_buffer;
168 
169     /* Flags to define presence of optional/expanded features */
170     long tp_flags;
171 
172     const char *tp_doc; /* Documentation string */
173 
174     /* Assigned meaning in release 2.0 */
175     /* call function for all accessible objects */
176     void *tp_traverse;
177 
178     /* delete references to contained objects */
179     void *tp_clear;
180 
181     /* Assigned meaning in release 2.1 */
182     /* rich comparisons */
183     void *tp_richcompare;
184 
185     /* weak reference enabler */
186     size_t tp_weaklistoffset;
187 
188     /* Added in release 2.2 */
189     /* Iterators */
190     void *tp_iter;
191     void *tp_iternext;
192 
193     /* Attribute descriptor and subclassing stuff */
194     PyMethodDef *tp_methods;
195     struct PyMemberDef *tp_members;
196     struct PyGetSetDef *tp_getset;
197     struct _typeobject *tp_base;
198     PyObject *tp_dict;
199     void *tp_descr_get;
200     void *tp_descr_set;
201     size_t tp_dictoffset;
202     void *tp_init;
203     void *tp_alloc;
204     void *tp_new;
205     void *tp_free; /* Low-level free-memory routine */
206     void *tp_is_gc; /* For PyObject_IS_GC */
207     PyObject *tp_bases;
208     PyObject *tp_mro; /* method resolution order */
209     PyObject *tp_cache;
210     PyObject *tp_subclasses;
211     PyObject *tp_weaklist;
212     void *tp_del;
213 
214     /* Type attribute cache version tag. Added in version 2.6 */
215     unsigned int tp_version_tag;
216 };
217 
218 // 2.4 - 3.7
219 class PyTupleObject : public PyVarObject {
220 public:
221     PyObject *ob_item[1];
222 
223     /* ob_item contains space for 'ob_size' elements.
224      * Items must normally not be nullptr, except during construction when
225      * the tuple is not yet visible outside the function that builds it.
226      */
227 };
228 
229 // 2.4 - 3.7
230 class PyCFunctionObject : public PyObject {
231 public:
232     PyMethodDef *m_ml;      /* Description of the C function to call */
233     PyObject    *m_self;    /* Passed as 'self' arg to the C func, can be nullptr */
234     PyObject    *m_module;  /* The __module__ attribute, can be anything */
235 };
236 
237 typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
238 
239 #define PyTrace_CALL 0
240 #define PyTrace_EXCEPTION 1
241 #define PyTrace_LINE 2
242 #define PyTrace_RETURN 3
243 #define PyTrace_C_CALL 4
244 #define PyTrace_C_EXCEPTION 5
245 #define PyTrace_C_RETURN 6
246 
247 class PyInterpreterState {
248 };
249 
250 class PyThreadState { };
251 
252 class PyThreadState_25_27 : public PyThreadState {
253 public:
254     /* See Python/ceval.c for comments explaining most fields */
255 
256     PyThreadState *next;
257     PyInterpreterState *interp;
258 
259     PyFrameObjectBaseUpTo39 *frame;
260     int recursion_depth;
261     /* 'tracing' keeps track of the execution depth when tracing/profiling.
262        This is to prevent the actual trace/profile code from being recorded in
263        the trace/profile. */
264     int tracing;
265     int use_tracing;
266 
267     Py_tracefunc c_profilefunc;
268     Py_tracefunc c_tracefunc;
269     PyObject *c_profileobj;
270     PyObject *c_traceobj;
271 
272     PyObject *curexc_type;
273     PyObject *curexc_value;
274     PyObject *curexc_traceback;
275 
276     PyObject *exc_type;
277     PyObject *exc_value;
278     PyObject *exc_traceback;
279 
280     PyObject *dict;  /* Stores per-thread state */
281 
282     /* tick_counter is incremented whenever the check_interval ticker
283      * reaches zero. The purpose is to give a useful measure of the number
284      * of interpreted bytecode instructions in a given thread.  This
285      * extremely lightweight statistic collector may be of interest to
286      * profilers (like psyco.jit()), although nothing in the core uses it.
287      */
288     int tick_counter;
289 
290     int gilstate_counter;
291 
292     PyObject *async_exc; /* Asynchronous exception to raise */
293     long thread_id; /* Thread id where this tstate was created */
294 
295     /* XXX signal handlers should also be here */
IsFor(int majorVersion,int minorVersion)296     static bool IsFor(int majorVersion, int minorVersion) {
297         return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
298     }
299 
IsFor(PythonVersion version)300     static bool IsFor(PythonVersion version) {
301         return version >= PythonVersion_25 && version <= PythonVersion_27;
302     }
303 };
304 
305 class PyThreadState_30_33 : public PyThreadState {
306 public:
307     PyThreadState *next;
308     PyInterpreterState *interp;
309 
310     PyFrameObjectBaseUpTo39 *frame;
311     int recursion_depth;
312     char overflowed; /* The stack has overflowed. Allow 50 more calls
313                         to handle the runtime error. */
314     char recursion_critical; /* The current calls must not cause
315                                 a stack overflow. */
316     /* 'tracing' keeps track of the execution depth when tracing/profiling.
317        This is to prevent the actual trace/profile code from being recorded in
318        the trace/profile. */
319     int tracing;
320     int use_tracing;
321 
322     Py_tracefunc c_profilefunc;
323     Py_tracefunc c_tracefunc;
324     PyObject *c_profileobj;
325     PyObject *c_traceobj;
326 
327     PyObject *curexc_type;
328     PyObject *curexc_value;
329     PyObject *curexc_traceback;
330 
331     PyObject *exc_type;
332     PyObject *exc_value;
333     PyObject *exc_traceback;
334 
335     PyObject *dict;  /* Stores per-thread state */
336 
337     /* tick_counter is incremented whenever the check_interval ticker
338      * reaches zero. The purpose is to give a useful measure of the number
339      * of interpreted bytecode instructions in a given thread.  This
340      * extremely lightweight statistic collector may be of interest to
341      * profilers (like psyco.jit()), although nothing in the core uses it.
342      */
343     int tick_counter;
344 
345     int gilstate_counter;
346 
347     PyObject *async_exc; /* Asynchronous exception to raise */
348     long thread_id; /* Thread id where this tstate was created */
349 
350     /* XXX signal handlers should also be here */
IsFor(int majorVersion,int minorVersion)351     static bool IsFor(int majorVersion, int minorVersion) {
352         return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
353     }
354 
IsFor(PythonVersion version)355     static bool IsFor(PythonVersion version) {
356         return version >= PythonVersion_30 && version <= PythonVersion_33;
357     }
358 };
359 
360 class PyThreadState_34_36 : public PyThreadState {
361 public:
362     PyThreadState *prev;
363     PyThreadState *next;
364     PyInterpreterState *interp;
365 
366     PyFrameObjectBaseUpTo39 *frame;
367     int recursion_depth;
368     char overflowed; /* The stack has overflowed. Allow 50 more calls
369                         to handle the runtime error. */
370     char recursion_critical; /* The current calls must not cause
371                                 a stack overflow. */
372     /* 'tracing' keeps track of the execution depth when tracing/profiling.
373         This is to prevent the actual trace/profile code from being recorded in
374         the trace/profile. */
375     int tracing;
376     int use_tracing;
377 
378     Py_tracefunc c_profilefunc;
379     Py_tracefunc c_tracefunc;
380     PyObject *c_profileobj;
381     PyObject *c_traceobj;
382 
383     PyObject *curexc_type;
384     PyObject *curexc_value;
385     PyObject *curexc_traceback;
386 
387     PyObject *exc_type;
388     PyObject *exc_value;
389     PyObject *exc_traceback;
390 
391     PyObject *dict;  /* Stores per-thread state */
392 
393     int gilstate_counter;
394 
395     PyObject *async_exc; /* Asynchronous exception to raise */
396 
397     long thread_id; /* Thread id where this tstate was created */
398     /* XXX signal handlers should also be here */
399 
IsFor(int majorVersion,int minorVersion)400     static bool IsFor(int majorVersion, int minorVersion) {
401         return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 6;
402     }
403 
IsFor(PythonVersion version)404     static bool IsFor(PythonVersion version) {
405         return version >= PythonVersion_34 && version <= PythonVersion_36;
406     }
407 };
408 
409 struct _PyErr_StackItem {
410     PyObject *exc_type, *exc_value, *exc_traceback;
411     struct _PyErr_StackItem *previous_item;
412 };
413 
414 
415 class PyThreadState_37_38 : public PyThreadState {
416 public:
417     PyThreadState *prev;
418     PyThreadState *next;
419     PyInterpreterState *interp;
420 
421     PyFrameObjectBaseUpTo39 *frame;
422     int recursion_depth;
423     char overflowed; /* The stack has overflowed. Allow 50 more calls
424                      to handle the runtime error. */
425     char recursion_critical; /* The current calls must not cause
426                              a stack overflow. */
427                              /* 'tracing' keeps track of the execution depth when tracing/profiling.
428                              This is to prevent the actual trace/profile code from being recorded in
429                              the trace/profile. */
430     int stackcheck_counter;
431 
432     int tracing;
433     int use_tracing;
434 
435     Py_tracefunc c_profilefunc;
436     Py_tracefunc c_tracefunc;
437     PyObject *c_profileobj;
438     PyObject *c_traceobj;
439 
440     PyObject *curexc_type;
441     PyObject *curexc_value;
442     PyObject *curexc_traceback;
443 
444     _PyErr_StackItem exc_state;
445     _PyErr_StackItem *exc_info;
446 
447     PyObject *dict;  /* Stores per-thread state */
448 
449     int gilstate_counter;
450 
451     PyObject *async_exc; /* Asynchronous exception to raise */
452 
453     unsigned long thread_id; /* Thread id where this tstate was created */
454 
IsFor(int majorVersion,int minorVersion)455     static bool IsFor(int majorVersion, int minorVersion) {
456         return majorVersion == 3 && (minorVersion == 7 || minorVersion == 8);
457     }
458 
IsFor(PythonVersion version)459     static bool IsFor(PythonVersion version) {
460         return version == PythonVersion_37 || version == PythonVersion_38;
461     }
462 };
463 
464 // i.e.: https://github.com/python/cpython/blob/master/Include/cpython/pystate.h
465 class PyThreadState_39 : public PyThreadState {
466 public:
467     PyThreadState *prev;
468     PyThreadState *next;
469     PyInterpreterState *interp;
470 
471     PyFrameObjectBaseUpTo39 *frame;
472     int recursion_depth;
473     char overflowed; /* The stack has overflowed. Allow 50 more calls
474                      to handle the runtime error. */
475     int stackcheck_counter;
476 
477     int tracing;
478     int use_tracing;
479 
480     Py_tracefunc c_profilefunc;
481     Py_tracefunc c_tracefunc;
482     PyObject *c_profileobj;
483     PyObject *c_traceobj;
484 
485     PyObject *curexc_type;
486     PyObject *curexc_value;
487     PyObject *curexc_traceback;
488 
489     _PyErr_StackItem exc_state;
490     _PyErr_StackItem *exc_info;
491 
492     PyObject *dict;  /* Stores per-thread state */
493 
494     int gilstate_counter;
495 
496     PyObject *async_exc; /* Asynchronous exception to raise */
497 
498     unsigned long thread_id; /* Thread id where this tstate was created */
499 
IsFor(int majorVersion,int minorVersion)500     static bool IsFor(int majorVersion, int minorVersion) {
501         return majorVersion == 3 && minorVersion == 9;
502     }
503 
IsFor(PythonVersion version)504     static bool IsFor(PythonVersion version) {
505         return version == PythonVersion_39;
506     }
507 };
508 
509 typedef struct _cframe {
510     /* This struct will be threaded through the C stack
511      * allowing fast access to per-thread state that needs
512      * to be accessed quickly by the interpreter, but can
513      * be modified outside of the interpreter.
514      *
515      * WARNING: This makes data on the C stack accessible from
516      * heap objects. Care must be taken to maintain stack
517      * discipline and make sure that instances of this struct cannot
518      * accessed outside of their lifetime.
519      */
520     int use_tracing;
521     struct _cframe *previous;
522 } CFrame;
523 
524 // i.e.: https://github.com/python/cpython/blob/master/Include/cpython/pystate.h
525 class PyThreadState_310 : public PyThreadState {
526 public:
527     PyThreadState *prev;
528     PyThreadState *next;
529     PyInterpreterState *interp;
530 
531     PyFrameObject310 *frame;
532     int recursion_depth;
533     int recursion_headroom; /* Allow 50 more calls to handle any errors. */
534     int stackcheck_counter;
535 
536     /* 'tracing' keeps track of the execution depth when tracing/profiling.
537        This is to prevent the actual trace/profile code from being recorded in
538        the trace/profile. */
539     int tracing;
540 
541     /* Pointer to current CFrame in the C stack frame of the currently,
542      * or most recently, executing _PyEval_EvalFrameDefault. */
543     CFrame *cframe;
544 
545 
546     Py_tracefunc c_profilefunc;
547     Py_tracefunc c_tracefunc;
548     PyObject *c_profileobj;
549     PyObject *c_traceobj;
550 
551     PyObject *curexc_type;
552     PyObject *curexc_value;
553     PyObject *curexc_traceback;
554 
555     _PyErr_StackItem exc_state;
556     _PyErr_StackItem *exc_info;
557 
558     PyObject *dict;  /* Stores per-thread state */
559 
560     int gilstate_counter;
561 
562     PyObject *async_exc; /* Asynchronous exception to raise */
563 
564     unsigned long thread_id; /* Thread id where this tstate was created */
565 
IsFor(int majorVersion,int minorVersion)566     static bool IsFor(int majorVersion, int minorVersion) {
567         return majorVersion == 3 && minorVersion == 10;
568     }
569 
IsFor(PythonVersion version)570     static bool IsFor(PythonVersion version) {
571         return version == PythonVersion_310;
572     }
573 };
574 
575 class PyIntObject : public PyObject {
576 public:
577     long ob_ival;
578 };
579 
580 class Py3kLongObject : public PyVarObject {
581 public:
582     DWORD ob_digit[1];
583 };
584 
585 class PyOldStyleClassObject : public PyObject {
586 public:
587     PyObject *cl_bases; /* A tuple of class objects */
588     PyObject *cl_dict; /* A dictionary */
589     PyObject *cl_name; /* A string */
590     /* The following three are functions or nullptr */
591     PyObject *cl_getattr;
592     PyObject *cl_setattr;
593     PyObject *cl_delattr;
594 };
595 
596 class PyInstanceObject : public PyObject {
597 public:
598     PyOldStyleClassObject *in_class; /* The class object */
599     PyObject *in_dict; /* A dictionary */
600     PyObject *in_weakreflist; /* List of weak references */
601 };
602 
603 #endif
604