static PyObject* do_fullcompile(PyFrameObject* frame, PyObject* arg) { PyCodeStats* cs; cs = PyCodeStats_Get(frame->f_code); if (cs->st_codebuf == NULL) { /* not already compiled, compile it now */ PyObject* g = frame->f_globals; int rec, module; stats_printf(("stats: full compile code: %s\n", PyCodeObject_NAME(frame->f_code))); if (cs->st_globals && PyInt_Check(cs->st_globals)) rec = PyInt_AS_LONG(cs->st_globals); else rec = DEFAULT_RECURSION; module = frame->f_globals == frame->f_locals; cs->st_codebuf = PsycoCode_CompileCode(frame->f_code, g, rec, module); if (cs->st_codebuf == Py_None) g = NULL; /* failed */ else { Py_INCREF(g); extra_assert(CodeBuffer_Check(cs->st_codebuf)); } Py_XDECREF(cs->st_globals); cs->st_globals = g; } /* already compiled a Psyco version, run it if the globals match */ extra_assert(frame->f_globals != NULL); if (cs->st_globals == frame->f_globals) { Py_INCREF(cs->st_codebuf); return cs->st_codebuf; } return NULL; }
static void stats_dump(void) { float top[STATLINES]; char* top_names[STATLINES]; int i, j, k=0; PyObject *key, *value; for (i=0; i<STATLINES; i++) top[i] = -1.0f; while (PyDict_Next(codestats_dict, &k, &key, &value)) { PyCodeStats* cs = (PyCodeStats*) key; PyCodeObject* co; extra_assert(PyCStruct_Check(key)); extra_assert(PyCode_Check(cs->cs_key)); co = (PyCodeObject*) cs->cs_key; for (i=0; i<STATLINES; i++) { if (cs->st_charge > top[i]) { for (j=STATLINES-1; j>i; j--) { top [j] = top [j-1]; top_names[j] = top_names[j-1]; } top [i] = cs->st_charge; top_names[i] = PyCodeObject_NAME(co); break; } } } for (i=0; i<STATLINES; i++) { if (top[i] < 0.0f) break; stats_printf(("stats: #%d %18g %s\n", i, top[i], top_names[i])); } }
DEFINEFN PyObject* psyco_stats_top(int n) { PyObject* l; PyObject* l2 = NULL; int i, k=0, full=0; PyObject *key, *value; float charge_min = (float)(charge_total * 0.001); extra_assert(n>0); l = PyList_New(n); if (l == NULL) goto fail; while (PyDict_Next(codestats_dict, &k, &key, &value)) { PyCodeStats* cs = (PyCodeStats*) key; extra_assert(PyCStruct_Check(key)); extra_assert(PyCode_Check(cs->cs_key)); if (cs->st_charge <= charge_min) continue; if (full < n) full++; i = full; while (--i > 0) { PyObject* o = PyList_GetItem(l, i-1); PyCodeStats* current = (PyCodeStats*) o; if (cs->st_charge <= current->st_charge) break; Py_INCREF(o); if (PyList_SetItem(l, i, o)) goto fail; } Py_INCREF(cs); if (PyList_SetItem(l, i, (PyObject*) cs)) goto fail; cs = (PyCodeStats*) PyList_GetItem(l, full-1); charge_min = cs->st_charge; } l2 = PyList_New(full); if (l2 == NULL) goto fail; for (i=0; i<full; i++) { PyCodeStats* cs = (PyCodeStats*) PyList_GetItem(l, i); PyObject* x = Py_BuildValue("Od", cs->cs_key, (double)(cs->st_charge / charge_total)); if (!x || PyList_SetItem(l2, i, x)) goto fail; } Py_DECREF(l); return l2; fail: Py_XDECREF(l2); Py_XDECREF(l); return NULL; }
static PyObject* profile_call(PyFrameObject* frame, PyObject* arg) { PyCodeStats* cs; psyco_stats_append(frame->f_tstate, frame->f_back); cs = PyCodeStats_Get(frame->f_code); if (cs->st_globals != NULL) { /* we want to accelerate this code object */ if (cs->st_codebuf == NULL) { /* not already compiled, compile it now */ PyObject* codebuf; PyObject* g = frame->f_globals; int rec, module; stats_printf(("stats: compile code: %s\n", PyCodeObject_NAME(frame->f_code))); if (PyInt_Check(cs->st_globals)) rec = PyInt_AS_LONG(cs->st_globals); else rec = DEFAULT_RECURSION; module = frame->f_globals == frame->f_locals; codebuf = PsycoCode_CompileCode(frame->f_code, g, rec, module); /* rare race condition: 'cs' might have been mutated during the call to PsycoCode_CompileCode(), so cs->st_codebuf might no longer be NULL, or cs->st_globals might be NULL again */ Py_XDECREF(cs->st_codebuf); cs->st_codebuf = codebuf; if (cs->st_codebuf == Py_None) g = NULL; /* failed */ else { Py_INCREF(g); extra_assert (CodeBuffer_Check(cs->st_codebuf)); } Py_XDECREF(cs->st_globals); cs->st_globals = g; } /* already compiled a Psyco version, run it if the globals match */ extra_assert(frame->f_globals != NULL); if (cs->st_globals == frame->f_globals) { Py_INCREF(cs->st_codebuf); return cs->st_codebuf; } } return NULL; }
PSY_INLINE bool call_ceval_hooks(ceval_events_t* cev, int what, PyFrameObject* f) { bool r = true; int n; struct cevents_s* events; PyObject* codebuf; PyObject* obj; extra_assert(what >= 0); if (what >= PyTrace_TOTAL) return true; /* Python >= 2.4 defines PyTrace_C_xxx */ #if VERBOSE_LEVEL >= 3 stats_printf(("hook: %d %s\n", what, PyCodeObject_NAME(f->f_code))); #endif events = cev->events + what; n = events->count; do { if (n == 0) return true; /* done */ n--; extra_assert(n < events->count); codebuf = events->items[n].fn(f, events->items[n].arg); if (events->items[n].fn == &deleted_ceval_hook) { events->items[n] = events->items[--events->count]; } } while (codebuf == NULL); /* call the other hooks, if any */ while (n != 0) { n--; extra_assert(n < events->count); obj = events->items[n].fn(f, events->items[n].arg); Py_XDECREF(obj); if (events->items[n].fn == &deleted_ceval_hook) { events->items[n] = events->items[--events->count]; } } /* enable recursive calls to call_ceval_hooks() */ f->f_tstate->use_tracing = 1; f->f_tstate->tracing--; /* run the compiled code */ r = PsycoCode_Run(codebuf, f, what == PyTrace_CALL); f->f_tstate->tracing++; Py_DECREF(codebuf); #if (PY_VERSION_HEX >= 0x02030000) && (PY_VERSION_HEX < 0x020300f0) if (!r) f->f_stacktop = NULL; /* work around a bug in Python 2.3b1 */ #endif return r; }
static void set_ceval_hook(ceval_events_t* cev, int when, ceval_event_fn fn, PyObject* arg) { int n, i, allow; struct cevents_s* events; extra_assert(0 <= when && when < PyTrace_TOTAL); events = cev->events + when; n = events->count++; PyMem_RESIZE(events->items, struct cevent_s, events->count); if (events->items == NULL) OUT_OF_MEMORY(); events->items[n].fn = fn; events->items[n].arg = arg; cev->events_total++; if (arg != NULL) { /* bound the total number of hooks by checking if there are too many other hooks with the same 'fn' */ allow = 8; for (i=n; --i >= 0; ) { if (events->items[i].fn == fn && !--allow) { /* too many! remove an arbitrary one */ events->items[i].fn = &deleted_ceval_hook; cev->events_total--; break; } } } }
DEFINEFN void psyco_flog(char* msg, ...) { va_list vargs; PyObject* s; PyObject* r; PyObject *etype, *evalue, *etb; extra_assert(psyco_logger != NULL); PyErr_Fetch(&etype, &evalue, &etb); #ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, msg); #else va_start(vargs); #endif s = PyString_FromFormatV(msg, vargs); va_end(vargs); if (s == NULL) OUT_OF_MEMORY(); r = PyObject_CallFunction(psyco_logger, "O", s); if (r == NULL) PyErr_WriteUnraisable(psyco_logger); else Py_DECREF(r); Py_DECREF(s); PyErr_Restore(etype, evalue, etb); }
PSY_INLINE ceval_events_t* get_cevents(PyThreadState* tstate) { PyObject* dict = tstate->dict; if (dict != NULL) { PyObject* o = PyDict_GetItem(dict, ceval_events_key); if (o != NULL) { extra_assert(PyCStruct_Check(o)); return (ceval_events_t*) o; } } return new_cevents(tstate); }
DEFINEFN PyObject* psyco_stats_dump(void) { PyObject* d = PyDict_New(); int i = 0; PyObject *key, *value; if (d == NULL) return NULL; while (PyDict_Next(codestats_dict, &i, &key, &value)) { PyCodeStats* cs = (PyCodeStats*) key; PyObject* o = PyFloat_FromDouble(cs->st_charge); extra_assert(PyCStruct_Check(key)); extra_assert(PyCode_Check(cs->cs_key)); if (o == NULL || PyDict_SetItem(d, cs->cs_key, o)) { Py_DECREF(d); return NULL; } } stats_dump(); return d; }
static PyObject* do_nocompile(PyFrameObject* frame, PyObject* arg) { PyCodeStats* cs; cs = PyCodeStats_MaybeGet(frame->f_code); /* if already compiled a Psyco version, run it if the globals match */ if (cs != NULL && cs->st_codebuf != NULL && cs->st_globals == frame->f_globals) { extra_assert(frame->f_globals != NULL); Py_INCREF(cs->st_codebuf); return cs->st_codebuf; } return NULL; }
DEFINEFN bool psyco_generic_ass_subscript(PsycoObject* po, vinfo_t* o, vinfo_t* key, vinfo_t* value) { /* see psyco_generic_subscript() for comments */ /* TypeSwitch */ PyTypeObject* ktp = Psyco_NeedType(po, key); if (ktp == NULL) return false; if (PyType_TypeCheck(ktp, &PyInt_Type)) { return PsycoSequence_SetItem(po, o, PsycoInt_AS_LONG(po, key), value); } else if (PyType_TypeCheck(ktp, &PyLong_Type)) { bool result; vinfo_t* key_value = PsycoLong_AsLong(po, key); if (key_value == NULL) return false; result = PsycoSequence_SetItem(po, o, key_value, value); vinfo_decref(key_value, po); return result; } else { char* vargs = (value!=NULL) ? "vvv" : "vvl"; PyTypeObject* tp = Psyco_NeedType(po, o); if (tp == NULL) return false; extra_assert(tp->tp_as_mapping != NULL); extra_assert(tp->tp_as_mapping->mp_ass_subscript != NULL); return psyco_generic_call(po, tp->tp_as_mapping->mp_ass_subscript, CfNoReturnValue|CfPyErrIfNonNull, vargs, o, key, value) != NULL; } }
DEFINEFN vinfo_t* psyco_generic_subscript(PsycoObject* po, vinfo_t* o, vinfo_t* key) { /* This is the meta-implementation of the mapping item assignment for sequences in Python >= 2.3, which is called for any expression of the form a[n]. It expects n to be an integer or an extended slice object. Regular slicing a[n:m] does not come here. */ /* TypeSwitch */ PyTypeObject* ktp = Psyco_NeedType(po, key); if (ktp == NULL) return NULL; if (PyType_TypeCheck(ktp, &PyInt_Type)) { return PsycoSequence_GetItem(po, o, PsycoInt_AS_LONG(po, key)); } else if (PyType_TypeCheck(ktp, &PyLong_Type)) { vinfo_t* result; vinfo_t* key_value = PsycoLong_AsLong(po, key); if (key_value == NULL) return NULL; result = PsycoSequence_GetItem(po, o, key_value); vinfo_decref(key_value, po); return result; } else { PyTypeObject* tp = Psyco_NeedType(po, o); if (tp == NULL) return NULL; extra_assert(tp->tp_as_mapping != NULL); extra_assert(tp->tp_as_mapping->mp_subscript != NULL); return psyco_generic_call(po, tp->tp_as_mapping->mp_subscript, CfReturnRef|CfPyErrIfNull, "vv", o, key); } }
DEFINEFN vinfo_array_t* array_grow1(vinfo_array_t* array, int ncount) { int i = array->count; extra_assert(ncount > i); if (i == 0) array = PyMem_MALLOC(sizeof(int) + ncount * sizeof(vinfo_t*)); else array = PyMem_REALLOC(array, sizeof(int) + ncount * sizeof(vinfo_t*)); if (array == NULL) OUT_OF_MEMORY(); array->count = ncount; while (i<ncount) array->items[i++] = NULL; return array; }
static void unset_ceval_hook(ceval_events_t* cev, int when, ceval_event_fn fn, PyObject* arg) { /* warning: do not shuffle values in the events->items array to compact it, because this might be called while the array is being enumerated by call_ceval_hooks() */ int n; struct cevents_s* events; extra_assert(0 <= when && when < PyTrace_TOTAL); events = cev->events + when; n = events->count; while (n--) { if (events->items[n].fn == fn && events->items[n].arg == arg) { events->items[n].fn = &deleted_ceval_hook; cev->events_total--; } } }