1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation.
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6  * copy of the license can be found in the License.html file at the root of this distribution. If
7  * you cannot locate the Apache License, Version 2.0, please send an email to
8  * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  * ***************************************************************************/
14 
15 #ifndef __PYTHON_H__
16 #define __PYTHON_H__
17 #include <string.h>
18 
19 // must be kept in sync with PythonLanguageVersion.cs
20 enum PythonVersion {
21     PythonVersion_Unknown,
22     PythonVersion_25 = 0x0205,
23     PythonVersion_26 = 0x0206,
24     PythonVersion_27 = 0x0207,
25     PythonVersion_30 = 0x0300,
26     PythonVersion_31 = 0x0301,
27     PythonVersion_32 = 0x0302,
28     PythonVersion_33 = 0x0303,
29     PythonVersion_34 = 0x0304
30 };
31 
32 
33 // defines limited header of Python API for compatible access across a number of Pythons.
34 
35 class PyTypeObject;
36 class PyThreadState;
37 
38 #define PyObject_HEAD           \
39     size_t ob_refcnt;           \
40     PyTypeObject *ob_type;
41 
42 #define PyObject_VAR_HEAD       \
43     PyObject_HEAD               \
44     size_t ob_size; /* Number of items in variable part */
45 
46 class PyObject {
47 public:
48     PyObject_HEAD
49 };
50 
51 class PyVarObject : public PyObject {
52 public:
53     size_t ob_size; /* Number of items in variable part */
54 };
55 
56 // 2.4 - 2.7 compatible
57 class PyCodeObject25_27 : public PyObject {
58 public:
59     int co_argcount;        /* #arguments, except *args */
60     int co_nlocals;         /* #local variables */
61     int co_stacksize;       /* #entries needed for evaluation stack */
62     int co_flags;           /* CO_..., see below */
63     PyObject *co_code;      /* instruction opcodes */
64     PyObject *co_consts;    /* list (constants used) */
65     PyObject *co_names;     /* list of strings (names used) */
66     PyObject *co_varnames;  /* tuple of strings (local variable names) */
67     PyObject *co_freevars;  /* tuple of strings (free variable names) */
68     PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
69     /* The rest doesn't count for hash/cmp */
70     PyObject *co_filename;  /* string (where it was loaded from) */
71     PyObject *co_name;      /* string (name, for reference) */
72     int co_firstlineno;     /* first source line number */
73     PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
74 
IsFor(int majorVersion,int minorVersion)75     static bool IsFor(int majorVersion, int minorVersion) {
76         return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
77     }
78 
IsFor(PythonVersion version)79     static bool IsFor(PythonVersion version) {
80         return version >= PythonVersion_25 && version <= PythonVersion_27;
81     }
82 };
83 
84 // 3.0-3.2
85 class PyCodeObject30_32 : public PyObject {
86 public:
87     int co_argcount;        /* #arguments, except *args */
88     int co_kwonlyargcount;  /* #keyword only arguments */
89     int co_nlocals;         /* #local variables */
90     int co_stacksize;       /* #entries needed for evaluation stack */
91     int co_flags;           /* CO_..., see below */
92     PyObject *co_code;      /* instruction opcodes */
93     PyObject *co_consts;    /* list (constants used) */
94     PyObject *co_names;     /* list of strings (names used) */
95     PyObject *co_varnames;  /* tuple of strings (local variable names) */
96     PyObject *co_freevars;  /* tuple of strings (free variable names) */
97     PyObject *co_cellvars;  /* tuple of strings (cell variable names) */
98     /* The rest doesn't count for hash or comparisons */
99     PyObject *co_filename;  /* unicode (where it was loaded from) */
100     PyObject *co_name;      /* unicode (name, for reference) */
101     int co_firstlineno;     /* first source line number */
102     PyObject *co_lnotab;    /* string (encoding addr<->lineno mapping) */
103     void *co_zombieframe;   /* for optimization only (see frameobject.c) */
104 
IsFor(int majorVersion,int minorVersion)105     static bool IsFor(int majorVersion, int minorVersion) {
106         return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 2);
107     }
108 
IsFor(PythonVersion version)109     static bool IsFor(PythonVersion version) {
110         return version >= PythonVersion_30 && version <= PythonVersion_32;
111     }
112 };
113 
114 // 3.3-3.4
115 class PyCodeObject33_34 : public PyObject {
116 public:
117     int co_argcount;            /* #arguments, except *args */
118     int co_kwonlyargcount;      /* #keyword only arguments */
119     int co_nlocals;             /* #local variables */
120     int co_stacksize;           /* #entries needed for evaluation stack */
121     int co_flags;               /* CO_..., see below */
122     PyObject *co_code;          /* instruction opcodes */
123     PyObject *co_consts;        /* list (constants used) */
124     PyObject *co_names;         /* list of strings (names used) */
125     PyObject *co_varnames;      /* tuple of strings (local variable names) */
126     PyObject *co_freevars;      /* tuple of strings (free variable names) */
127     PyObject *co_cellvars;      /* tuple of strings (cell variable names) */
128     /* The rest doesn't count for hash or comparisons */
129     unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
130     PyObject *co_filename;      /* unicode (where it was loaded from) */
131     PyObject *co_name;          /* unicode (name, for reference) */
132     int co_firstlineno;         /* first source line number */
133     PyObject *co_lnotab;        /* string (encoding addr<->lineno mapping) */
134     void *co_zombieframe;       /* for optimization only (see frameobject.c) */
135 
IsFor(int majorVersion,int minorVersion)136     static bool IsFor(int majorVersion, int minorVersion) {
137         return majorVersion == 3 && (minorVersion >= 3 && minorVersion <= 4);
138     }
139 
IsFor(PythonVersion version)140     static bool IsFor(PythonVersion version) {
141         return version >= PythonVersion_33 && version <= PythonVersion_34;
142     }
143 };
144 
145 // 2.5 - 3.1
146 class PyFunctionObject : public PyObject {
147 public:
148     PyObject *func_code;    /* A code object */
149 };
150 
151 // 2.5 - 2.7 compatible
152 class PyStringObject : public PyVarObject {
153 public:
154     long ob_shash;
155     int ob_sstate;
156     char ob_sval[1];
157 
158     /* Invariants:
159      *     ob_sval contains space for 'ob_size+1' elements.
160      *     ob_sval[ob_size] == 0.
161      *     ob_shash is the hash of the string or -1 if not computed yet.
162      *     ob_sstate != 0 iff the string object is in stringobject.c's
163      *       'interned' dictionary; in this case the two references
164      *       from 'interned' to this object are *not counted* in ob_refcnt.
165      */
166 };
167 
168 // 2.4 - 3.2 compatible
169 typedef struct {
170     PyObject_HEAD
171     size_t length;      /* Length of raw Unicode data in buffer */
172     wchar_t *str;       /* Raw Unicode buffer */
173     long hash;          /* Hash value; -1 if not set */
174 } PyUnicodeObject;
175 
176 // 2.4 - 3.4 compatible
177 class PyFrameObject : public PyVarObject {
178 public:
179     PyFrameObject *f_back;  /* previous frame, or NULL */
180     PyObject *f_code;           /* code segment */
181     PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
182     PyObject *f_globals;        /* global symbol table (PyDictObject) */
183     PyObject *f_locals;         /* local symbol table (any mapping) */
184     PyObject **f_valuestack;    /* points after the last local */
185     /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
186        Frame evaluation usually NULLs it, but a frame that yields sets it
187        to the current stack top. */
188     PyObject **f_stacktop;
189     PyObject *f_trace;          /* Trace function */
190     PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
191 };
192 
193 #define CO_MAXBLOCKS 20
194 typedef struct {
195     int b_type;         /* what kind of block this is */
196     int b_handler;      /* where to jump to find handler */
197     int b_level;        /* value stack level to pop to */
198 } PyTryBlock;
199 
200 class PyFrameObject25_33 : public PyFrameObject {
201 public:
202     PyThreadState* f_tstate;
203     int f_lasti;                /* Last instruction if called */
204     /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
205        f_trace is set) -- at other times use PyCode_Addr2Line instead. */
206     int f_lineno;               /* Current line number */
207     int f_iblock;       /* index in f_blockstack */
208     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
209     PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
210 
IsFor(int majorVersion,int minorVersion)211     static bool IsFor(int majorVersion, int minorVersion) {
212         return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7) ||
213             majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
214     }
215 };
216 
217 class PyFrameObject34 : public PyFrameObject {
218 public:
219     /* Borrowed reference to a generator, or NULL */
220     PyObject *f_gen;
221 
222     int f_lasti;                /* Last instruction if called */
223     /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
224        f_trace is set) -- at other times use PyCode_Addr2Line instead. */
225     int f_lineno;               /* Current line number */
226     int f_iblock;       /* index in f_blockstack */
227     char f_executing;           /* whether the frame is still executing */
228     PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
229     PyObject *f_localsplus[1];    /* locals+stack, dynamically sized */
230 
IsFor(int majorVersion,int minorVersion)231     static bool IsFor(int majorVersion, int minorVersion) {
232         return majorVersion == 3 && minorVersion == 4;
233     }
234 };
235 
236 
237 typedef void (*destructor)(PyObject *);
238 
239 // 2.4 - 3.4
240 class PyMethodDef {
241 public:
242     char    *ml_name;    /* The name of the built-in function/method */
243 };
244 
245 
246 //
247 // 2.4 - 3.4, 2.4 has different compat in 64-bit but we don't support any of the released 64-bit platforms (which includes only IA-64)
248 // While these are compatible there are fields only available on later versions.
249 class PyTypeObject : public PyVarObject {
250 public:
251     const char *tp_name; /* For printing, in format "<module>.<name>" */
252     size_t tp_basicsize, tp_itemsize; /* For allocation */
253 
254     /* Methods to implement standard operations */
255 
256     destructor tp_dealloc;
257     void* tp_print;
258     void* tp_getattr;
259     void* tp_setattr;
260     void* tp_compare;
261     void* tp_repr;
262 
263     /* Method suites for standard classes */
264 
265     void *tp_as_number;
266     void*tp_as_sequence;
267     void*tp_as_mapping;
268 
269     /* More standard operations (here for binary compatibility) */
270 
271     void* tp_hash;
272     void* tp_call;
273     void* tp_str;
274     void* tp_getattro;
275     void* tp_setattro;
276 
277     /* Functions to access object as input/output buffer */
278     void*tp_as_buffer;
279 
280     /* Flags to define presence of optional/expanded features */
281     long tp_flags;
282 
283     const char *tp_doc; /* Documentation string */
284 
285     /* Assigned meaning in release 2.0 */
286     /* call function for all accessible objects */
287     void*  tp_traverse;
288 
289     /* delete references to contained objects */
290     void* tp_clear;
291 
292     /* Assigned meaning in release 2.1 */
293     /* rich comparisons */
294     void*  tp_richcompare;
295 
296     /* weak reference enabler */
297     size_t tp_weaklistoffset;
298 
299     /* Added in release 2.2 */
300     /* Iterators */
301     void*  tp_iter;
302     void*  tp_iternext;
303 
304     /* Attribute descriptor and subclassing stuff */
305     PyMethodDef *tp_methods;
306     struct PyMemberDef *tp_members;
307     struct PyGetSetDef *tp_getset;
308     struct _typeobject *tp_base;
309     PyObject *tp_dict;
310     void*  tp_descr_get;
311     void*  tp_descr_set;
312     size_t tp_dictoffset;
313     void* tp_init;
314     void* tp_alloc;
315     void* tp_new;
316     void* tp_free; /* Low-level free-memory routine */
317     void* tp_is_gc; /* For PyObject_IS_GC */
318     PyObject *tp_bases;
319     PyObject *tp_mro; /* method resolution order */
320     PyObject *tp_cache;
321     PyObject *tp_subclasses;
322     PyObject *tp_weaklist;
323     void*  tp_del;
324 
325     /* Type attribute cache version tag. Added in version 2.6 */
326     unsigned int tp_version_tag;
327 };
328 
329 // 2.4 - 3.4
330 class PyTupleObject : public PyVarObject {
331 public:
332     PyObject *ob_item[1];
333 
334     /* ob_item contains space for 'ob_size' elements.
335      * Items must normally not be NULL, except during construction when
336      * the tuple is not yet visible outside the function that builds it.
337      */
338 };
339 
340 // 2.4 - 3.4
341 class PyCFunctionObject : public PyObject {
342 public:
343     PyMethodDef *m_ml;      /* Description of the C function to call */
344     PyObject    *m_self;    /* Passed as 'self' arg to the C func, can be NULL */
345     PyObject    *m_module;  /* The __module__ attribute, can be anything */
346 };
347 
348 typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
349 
350 #define PyTrace_CALL 0
351 #define PyTrace_EXCEPTION 1
352 #define PyTrace_LINE 2
353 #define PyTrace_RETURN 3
354 #define PyTrace_C_CALL 4
355 #define PyTrace_C_EXCEPTION 5
356 #define PyTrace_C_RETURN 6
357 
358 class PyInterpreterState {
359 };
360 
361 class PyThreadState { };
362 
363 class PyThreadState_25_27 : public PyThreadState {
364 public:
365     /* See Python/ceval.c for comments explaining most fields */
366 
367     PyThreadState *next;
368     PyInterpreterState *interp;
369 
370     PyFrameObject *frame;
371     int recursion_depth;
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     /* tick_counter is incremented whenever the check_interval ticker
394      * reaches zero. The purpose is to give a useful measure of the number
395      * of interpreted bytecode instructions in a given thread.  This
396      * extremely lightweight statistic collector may be of interest to
397      * profilers (like psyco.jit()), although nothing in the core uses it.
398      */
399     int tick_counter;
400 
401     int gilstate_counter;
402 
403     PyObject *async_exc; /* Asynchronous exception to raise */
404     long thread_id; /* Thread id where this tstate was created */
405 
406     /* XXX signal handlers should also be here */
IsFor(int majorVersion,int minorVersion)407     static bool IsFor(int majorVersion, int minorVersion) {
408         return majorVersion == 2 && (minorVersion >= 5 && minorVersion <= 7);
409     }
410 
IsFor(PythonVersion version)411     static bool IsFor(PythonVersion version) {
412         return version >= PythonVersion_25 && version <= PythonVersion_27;
413     }
414 };
415 
416 class PyThreadState_30_33 : public PyThreadState {
417 public:
418     PyThreadState *next;
419     PyInterpreterState *interp;
420 
421     PyFrameObject *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 tracing;
431     int use_tracing;
432 
433     Py_tracefunc c_profilefunc;
434     Py_tracefunc c_tracefunc;
435     PyObject *c_profileobj;
436     PyObject *c_traceobj;
437 
438     PyObject *curexc_type;
439     PyObject *curexc_value;
440     PyObject *curexc_traceback;
441 
442     PyObject *exc_type;
443     PyObject *exc_value;
444     PyObject *exc_traceback;
445 
446     PyObject *dict;  /* Stores per-thread state */
447 
448     /* tick_counter is incremented whenever the check_interval ticker
449      * reaches zero. The purpose is to give a useful measure of the number
450      * of interpreted bytecode instructions in a given thread.  This
451      * extremely lightweight statistic collector may be of interest to
452      * profilers (like psyco.jit()), although nothing in the core uses it.
453      */
454     int tick_counter;
455 
456     int gilstate_counter;
457 
458     PyObject *async_exc; /* Asynchronous exception to raise */
459     long thread_id; /* Thread id where this tstate was created */
460 
461     /* XXX signal handlers should also be here */
IsFor(int majorVersion,int minorVersion)462     static bool IsFor(int majorVersion, int minorVersion) {
463         return majorVersion == 3 && (minorVersion >= 0 && minorVersion <= 3);
464     }
465 
IsFor(PythonVersion version)466     static bool IsFor(PythonVersion version) {
467         return version >= PythonVersion_30 && version <= PythonVersion_33;
468     }
469 };
470 
471 class PyThreadState_34 : public PyThreadState {
472 public:
473     PyThreadState *prev;
474     PyThreadState *next;
475     PyInterpreterState *interp;
476 
477     PyFrameObject *frame;
478     int recursion_depth;
479     char overflowed; /* The stack has overflowed. Allow 50 more calls
480                         to handle the runtime error. */
481     char recursion_critical; /* The current calls must not cause
482                                 a stack overflow. */
483     /* 'tracing' keeps track of the execution depth when tracing/profiling.
484        This is to prevent the actual trace/profile code from being recorded in
485        the trace/profile. */
486     int tracing;
487     int use_tracing;
488 
489     Py_tracefunc c_profilefunc;
490     Py_tracefunc c_tracefunc;
491     PyObject *c_profileobj;
492     PyObject *c_traceobj;
493 
494     PyObject *curexc_type;
495     PyObject *curexc_value;
496     PyObject *curexc_traceback;
497 
498     PyObject *exc_type;
499     PyObject *exc_value;
500     PyObject *exc_traceback;
501 
502     PyObject *dict;  /* Stores per-thread state */
503 
504     int gilstate_counter;
505 
506     PyObject *async_exc; /* Asynchronous exception to raise */
507     long thread_id; /* Thread id where this tstate was created */
508 
509     /* XXX signal handlers should also be here */
IsFor(int majorVersion,int minorVersion)510     static bool IsFor(int majorVersion, int minorVersion) {
511         return majorVersion == 3 && minorVersion == 4;
512     }
513 
IsFor(PythonVersion version)514     static bool IsFor(PythonVersion version) {
515         return version == PythonVersion_34;
516     }
517 };
518 
519 class PyIntObject : public PyObject {
520 public:
521     long ob_ival;
522 };
523 
524 //class Py3kLongObject : public PyVarObject {
525 //public:
526 //    DWORD ob_digit[1];
527 //};
528 
529 class PyOldStyleClassObject : public PyObject {
530 public:
531     PyObject *cl_bases; /* A tuple of class objects */
532     PyObject *cl_dict; /* A dictionary */
533     PyObject *cl_name; /* A string */
534     /* The following three are functions or NULL */
535     PyObject *cl_getattr;
536     PyObject *cl_setattr;
537     PyObject *cl_delattr;
538 };
539 
540 class PyInstanceObject : public PyObject {
541 public:
542     PyOldStyleClassObject *in_class; /* The class object */
543     PyObject *in_dict; /* A dictionary */
544     PyObject *in_weakreflist; /* List of weak references */
545 };
546 
547 typedef const char* (*GetVersionFunc) ();
548 
GetPythonVersion()549 static PythonVersion GetPythonVersion() {
550     GetVersionFunc versionFunc;
551     void *main_hndl = dlopen(NULL, 0x2);
552     *(void**)(&versionFunc) = dlsym(main_hndl, "Py_GetVersion");
553     if(versionFunc != NULL) {
554         const char* version = versionFunc();
555         if(version != NULL && strlen(version) >= 3 && version[1] == '.') {
556             if(version[0] == '2') {
557                 switch(version[2]) {
558                 case '5': return PythonVersion_25;
559                 case '6': return PythonVersion_26;
560                 case '7': return PythonVersion_27;
561                 }
562             } else if(version[0] == '3') {
563                 switch(version[2]) {
564                 case '0': return PythonVersion_30;
565                 case '1': return PythonVersion_31;
566                 case '2': return PythonVersion_32;
567                 case '3': return PythonVersion_33;
568                 case '4': return PythonVersion_34;
569                 }
570             }
571         }
572     }
573     return PythonVersion_Unknown;
574 }
575 
576 #endif
577