1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
|
/***************************************************************/
/*** Language-dependent part of the compiler ***/
/***************************************************************/
#ifndef _PYCOMPILER_H
#define _PYCOMPILER_H
#include "pycheader.h"
#include "pyver.h"
#include "../vcompiler.h"
#include "../processor.h"
#include "../dispatcher.h"
/*#define MAX3(a,b,c) ((a)>(b)?((a)>(c)?(a):(c)):(b)>(c)?(b):(c))*/
/*****************************************************************/
/*** Common constants ***/
/* the following known values have the SkFlagFixed set */
#define DEF_SK_AND_VI(name) \
EXTERNVAR source_known_t psyco_sk##name; \
PSY_INLINE vinfo_t* psyco_vi_##name(void) { \
sk_incref(&psyco_sk##name); \
return vinfo_new(CompileTime_NewSk(&psyco_sk##name)); \
}
DEF_SK_AND_VI(Zero) /* known value 0 */
DEF_SK_AND_VI(One) /* known value 1 */
DEF_SK_AND_VI(None) /* known value 'Py_None' */
DEF_SK_AND_VI(Py_False) /* known value 'Py_False' */
DEF_SK_AND_VI(Py_True) /* known value 'Py_True' */
DEF_SK_AND_VI(NotImplemented) /* 'Py_NotImplemented' */
/* the macro defines psyco_vi_None(), psyco_vi_Zero(),
psyco_vi_One() and psyco_vi_NotImplemented(). */
#undef DEF_SK_AND_VI
/*****************************************************************/
/*** Compile-time Pseudo exceptions ***/
/*****
* A pseudo-exception is the compile-time equivalent of a Python exception.
* They are encoded in the fields 'exc' and 'val' of pyc_data_t. For real
* Python the translation is immediate: 'exc' describes the PyObject*
* pointing to the Python exception class, and 'val' is the associated value.
*
* For the other pseudo-exceptions, like special events breaking the Python
* main loop (returns, break, continue), 'exc' is a virtual value using
* one of the following non-computable virtual sources.
*
* 'ERtPython' is particular: it is the virtual equivalent of "the exception
* currently set at run-time". Use PycException_Fetch() to emit the actual
* call to PyErr_Fetch().
*/
EXTERNVAR source_virtual_t ERtPython; /* Exception raised by Python */
EXTERNVAR source_virtual_t EReturn; /* 'return' statement */
EXTERNVAR source_virtual_t EBreak; /* 'break' statement */
EXTERNVAR source_virtual_t EContinue; /* 'continue' statement */
EXTERNVAR source_virtual_t EInline; /* inline a frame inside a parent frame */
/* Check whether a pseudo-exception is currently set */
PSY_INLINE bool PycException_Occurred(PsycoObject* po) {
return po->pr.exc != NULL;
}
/* raise an arbitrary pseudo-exception (consumes the references) */
EXTERNFN void PycException_Clear(PsycoObject* po);
PSY_INLINE void PycException_Raise(PsycoObject* po, vinfo_t* exc, vinfo_t* val) {
if (PycException_Occurred(po))
PycException_Clear(po);
po->pr.exc = exc;
po->pr.val = val;
}
PSY_INLINE void PycException_Restore(PsycoObject* po, vinfo_t* exc,
vinfo_t* val, vinfo_t* tb) {
PycException_Raise(po, exc, val);
po->pr.tb = tb;
}
/* for Python exceptions detected at compile-time */
EXTERNFN void PycException_SetString(PsycoObject* po,
PyObject* e, const char* text);
EXTERNFN void PycException_SetFormat(PsycoObject* po,
PyObject* e, const char* fmt, ...);
/* consumes a reference on 'v': */
EXTERNFN void PycException_SetObject(PsycoObject* po, PyObject* e, PyObject* v);
/* consumes a reference on 'v': */
EXTERNFN void PycException_SetVInfo(PsycoObject* po, PyObject* e, vinfo_t* v);
/* checking for the Python class of an exception */
EXTERNFN vinfo_t* PycException_Matches(PsycoObject* po, PyObject* e);
PSY_INLINE bool PycException_Is(PsycoObject* po, source_virtual_t* sv) {
return po->pr.exc->source == VirtualTime_New(sv);
}
PSY_INLINE bool PycException_IsPython(PsycoObject* po) {
Source src = po->pr.exc->source;
if (is_virtualtime(src)) {
return !(src == VirtualTime_New(&EReturn) ||
src == VirtualTime_New(&EBreak) ||
src == VirtualTime_New(&EContinue) ||
psyco_vsource_is_promotion(src));
}
else
return true;
};
/* fetch a Python exception set at compile-time (that is, now) and turn into
a pseudo-exception (typically to be re-raised at run-time). */
EXTERNFN void psyco_virtualize_exception(PsycoObject* po);
/* fetch a Python exception set at run-time (that is, a ERtPython) and turn into
a pseudo-exception. This is a no-op if !PycException_Is(po, &ERtPython). */
EXTERNFN void PycException_Fetch(PsycoObject* po);
/*****************************************************************/
/*** Promotion ***/
/* Raise a pseudo-exception meaning "promote 'vi' from run-time to
compile-time". If 'promotion->fs' is not NULL, only promote if the
run-time value turns out to be in the given set.
*/
EXTERNFN void PycException_Promote(PsycoObject* po,
vinfo_t* vi, c_promotion_t* promotion);
/* A powerful function: it appears to return the value of the
variable 'vi', even if it is a run-time variable. Implemented
by raising a EPromotion exception if needed. Returns -1 in
this case; use PycException_Occurred() to know if it is really
an exception or a plain normal -1. */
PSY_INLINE long psyco_atcompiletime(PsycoObject* po, vinfo_t *vi) {
if (!compute_vinfo(vi, po))
return -1;
if (is_runtime(vi->source)) {
PycException_Promote(po, vi, &psyco_nonfixed_promotion);
return -1;
}
else {
source_known_t* sk = CompileTime_Get(vi->source);
sk->refcount1_flags |= SkFlagFixed;
return sk->value;
}
}
/* the same if the value to promote is itself a PyObject* which can be
used as key in the look-up dictionary */
PSY_INLINE PyObject* psyco_pyobj_atcompiletime(PsycoObject* po, vinfo_t* vi) {
if (!compute_vinfo(vi, po))
return NULL;
if (is_runtime(vi->source)) {
PycException_Promote(po, vi, &psyco_nonfixed_pyobj_promotion);
return NULL;
}
else {
source_known_t* sk = CompileTime_Get(vi->source);
sk->refcount1_flags |= SkFlagFixed;
return (PyObject*) sk->value;
}
}
/* the same again, detecting megamorphic sites: if many different run-time
values keep showing up, return 0. If successfully promoted, return 1.
In case of exception, return -1. */
/*EXTERNFN int psyco_atcompiletime_mega(PsycoObject* po, vinfo_t *vi,
long *out);*/
EXTERNFN int psyco_pyobj_atcompiletime_mega(PsycoObject* po, vinfo_t* vi,
PyObject** out);
#if USE_RUNTIME_SWITCHES
/* same as above, when the return value is used in a switch.
In this case we must only promote the known values. So instead
of writing 'switch (psyco_atcompiletime(po, vi))' you
must write 'switch (psyco_switch_index(po, vi, fs))' */
PSY_INLINE int psyco_switch_index(PsycoObject* po, vinfo_t* vi, fixed_switch_t* fs) {
if (!compute_vinfo(vi, po))
return -1;
if (is_runtime(vi->source)) {
if (!known_to_be_default(vi, fs))
PycException_Promote(po, vi, &fs->fixed_promotion);
return -1;
}
else
return psyco_switch_lookup(fs, CompileTime_Get(vi->source)->value);
}
#endif
/* lazy comparison. Returns true if 'vi' is non-NULL, compile-time, and has the
given value, and false otherwise. */
PSY_INLINE bool psyco_knowntobe(vinfo_t* vi, long value) {
return vi != NULL && is_compiletime(vi->source) &&
CompileTime_Get(vi->source)->value == value;
}
/* comparison with a special PyObject* value, e.g. Py_NotImplemented; assume
that virtual sources are never one of these special objects. The _f version
assumes a generally false outcome, and the _t version a generally true one. */
/* --- disabled, use CfPyErrNotImplemented instead --- */
/* inline bool psyco_is_special_f(PsycoObject* po, vinfo_t* vi, */
/* PyObject* value) { */
/* return !is_virtualtime(vi->source) && */
/* runtime_condition_f(po, * integer_cmp_i does not fail here * */
/* integer_cmp_i(po, vi, (long) value, Py_EQ)); */
/* } */
/* inline bool psyco_is_special_t(PsycoObject* po, vinfo_t* vi, PyObject* */
/* value) { */
/* return !is_virtualtime(vi->source) && */
/* runtime_condition_t(po, * integer_cmp_i does not fail here * */
/* integer_cmp_i(po, vi, (long) value, Py_EQ)); */
/* } */
/*****************************************************************/
/*** Exception utilities ***/
/* Psyco meta-equivalent of PyErr_Occurred(). Not to be confused with
PycException_Occurred(), which tells whether a Psyco-level exception
is currently set. */
PSY_INLINE vinfo_t* psyco_PyErr_Occurred(PsycoObject* po) {
if (PycException_Occurred(po) && PycException_IsPython(po)) {
return psyco_vi_One();
}
else {
/* normal call would be:
return psyco_generic_call(po, PyErr_Occurred,
CfReturnNormal, "");
but we inline the check done in PyErr_Occurred(). */
vinfo_t* vaddr;
vinfo_t* vtstate;
vinfo_t* vcurexc;
vaddr = vinfo_new(CompileTime_New(
(long)(&_PyThreadState_Current)));
vtstate = psyco_memory_read(po, vaddr, 0, NULL, 2, false);
vinfo_decref(vaddr, po);
vcurexc = psyco_memory_read(po, vtstate,
offsetof(PyThreadState, curexc_type),
NULL, 2, false);
vinfo_decref(vtstate, po);
return vcurexc;
}
}
/*****************************************************************/
/*** Meta functions ***/
/* Each C function of the Python interpreter might be associated to a
"meta" function from Psyco with the same signature but 'vinfo_t*' for
the arguments and return value. The idea is that when such a meta
function exists, Psyco can invoke it at compile-time to do (a part of)
what the Python interpreter would do at run-time only. The code of the
meta function typically ressembles that of the original function enough
that we might dream about a language in which we never have to write
the two versions (where Psyco's version could be derived automatically
from the standard version).
*/
EXTERNVAR PyObject* Psyco_Meta_Dict; /* key is a PyIntObject holding the
address of the C function, value is
a PyIntObject holding the address
of the corresponding Psyco function. */
EXTERNFN void Psyco_DefineMeta(void* c_function, void* psyco_function);
PSY_INLINE void* Psyco_Lookup(void* c_function) {
PyObject* value;
PyObject* key = PyInt_FromLong((long) c_function);
if (key == NULL) OUT_OF_MEMORY();
value = PyDict_GetItem(Psyco_Meta_Dict, key);
Py_DECREF(key);
if (value != NULL)
return (void*) PyInt_AS_LONG(value);
else
return NULL;
}
/*** To map the content of a Python module to meta-implementations. ***/
/* Returns the module object (refcount *incremented*) or NULL if
not found. It also prints some infos in verbose mode. */
EXTERNFN PyObject* Psyco_DefineMetaModule(char* modulename);
/* Returns an object from a module (refcount *incremented*) or NULL
if not found. In verbose mode, 'not found' errors are printed. */
EXTERNFN PyObject* Psyco_GetModuleObject(PyObject* module, char* name,
PyTypeObject* expected_type);
/* Maps a built-in function object from a module to a meta-implementation.
Returns a pointer to the C function itself. */
EXTERNFN PyCFunction Psyco_DefineModuleFn(PyObject* module, char* meth_name,
int meth_flags, void* meta_fn);
/* Same as above, but also alternatively accepts a callable type object
and maps it to meta_type_new. Returns NULL in this case. */
#if NEW_STYLE_TYPES /* Python >= 2.2b1 */
EXTERNFN PyCFunction Psyco_DefineModuleC(PyObject* module, char* meth_name,
int meth_flags, void* meta_fn,
void* meta_type_new);
#else
# define Psyco_DefineModuleC(mo, na, fl, fn, tn) \
Psyco_DefineModuleFn(mo, na, fl, fn)
#endif
/* the general-purpose calling routine: it looks for a meta implementation of
'c_function' and call it if found; if not found, it encode a run-time call
to 'c_function'. The 'flags' and 'arguments' are as in psyco_generic_call().
The remaining arguments are given to the meta function or encoded in the
run-time call; they should be compatible with the description given in
'arguments'.
This is a bit tricky, with one version of the macro per number of arguments,
because the C processor is too limited and we want to avoid handling
functions with '...' arguments all around
*/
#define Psyco_META1(po, c_function, flags, arguments, a1) \
Psyco_Meta1x(po, c_function, flags, arguments, \
(long)(a1))
#define Psyco_META2(po, c_function, flags, arguments, a1, a2) \
Psyco_Meta2x(po, c_function, flags, arguments, \
(long)(a1), (long)(a2))
#define Psyco_META3(po, c_function, flags, arguments, a1, a2, a3) \
Psyco_Meta3x(po, c_function, flags, arguments, \
(long)(a1), (long)(a2), (long)(a3))
#define Psyco_flag_META1 (condition_code_t) Psyco_META1
#define Psyco_flag_META2 (condition_code_t) Psyco_META2
#define Psyco_flag_META3 (condition_code_t) Psyco_META3
EXTERNFN vinfo_t* Psyco_Meta1x(PsycoObject* po, void* c_function, int flags,
const char* arguments, long a1);
EXTERNFN vinfo_t* Psyco_Meta2x(PsycoObject* po, void* c_function, int flags,
const char* arguments, long a1, long a2);
EXTERNFN vinfo_t* Psyco_Meta3x(PsycoObject* po, void* c_function, int flags,
const char* arguments, long a1, long a2, long a3);
/******************************************************************/
/*** pyc_data_t implementation and snapshots for the dispatcher ***/
/* construction for non-frozen snapshots */
EXTERNFN void pyc_data_build(PsycoObject* po, PyObject* merge_points);
PSY_INLINE void pyc_data_release(pyc_data_t* pyc) {
vinfo_xdecref(pyc->val, NULL);
vinfo_xdecref(pyc->exc, NULL);
vinfo_xdecref(pyc->tb, NULL);
Py_XDECREF(pyc->changing_globals);
}
PSY_INLINE void pyc_data_duplicate(pyc_data_t* target, pyc_data_t* source) {
memcpy(target, source, sizeof(pyc_data_t));
target->exc = NULL;
target->val = NULL;
target->tb = NULL;
Py_XINCREF(target->changing_globals);
}
/* construction for frozen snapshots */
PSY_INLINE size_t frozen_size(pyc_data_t* pyc) {
return offsetof(pyc_data_t, blockstack) + pyc->iblock*sizeof(PyTryBlock);
}
PSY_INLINE void frozen_copy(pyc_data_t* target, pyc_data_t* source) {
memcpy(target, source, frozen_size(source));
}
PSY_INLINE pyc_data_t* pyc_data_new(pyc_data_t* original) {
pyc_data_t* pyc = (pyc_data_t*) PyMem_MALLOC(frozen_size(original));
if (pyc == NULL) OUT_OF_MEMORY();
frozen_copy(pyc, original);
return pyc;
}
PSY_INLINE void pyc_data_delete(pyc_data_t* pyc) {
PyMem_FREE(pyc);
}
#endif /* _PYCOMPILER_H */
|