Update of /cvsroot/psyco/psyco/c In directory usw-pr-cvs1:/tmp/cvs-serv21727 Modified Files: codemanager.c dispatcher.c dispatcher.h mergepoints.c mergepoints.h psyco.c psyco.h vcompiler.c vcompiler.h Log Message: removed quadratic dispatcher bottleneck Index: codemanager.c =================================================================== RCS file: /cvsroot/psyco/psyco/c/codemanager.c,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** codemanager.c 2001/12/04 16:12:07 1.1 --- codemanager.c 2001/12/24 17:01:17 1.2 *************** *** 30,34 **** { \ fpo_build(&b->snapshot, po); \ ! register_codebuf(ge, b); \ if (setcodelimit) \ po->codelimit = b->codeptr + BIG_BUFFER_SIZE - \ --- 30,35 ---- { \ fpo_build(&b->snapshot, po); \ ! if (ge != NULL) \ ! register_codebuf(ge, b); \ if (setcodelimit) \ po->codelimit = b->codeptr + BIG_BUFFER_SIZE - \ Index: dispatcher.c =================================================================== RCS file: /cvsroot/psyco/psyco/c/dispatcher.c,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** dispatcher.c 2001/12/12 19:42:59 1.2 --- dispatcher.c 2001/12/24 17:01:17 1.3 *************** *** 1,4 **** --- 1,5 ---- #include "dispatcher.h" #include "codemanager.h" + #include "mergepoints.h" #include "Python/pycompiler.h" /* for pyc_data_xxx() */ #include "pycencoding.h" /* for INC_OB_REFCNT() */ *************** *** 14,18 **** { clear_tmp_marks(&po->vlocals); ! duplicate_array(&fpo->fz_vlocals, &po->vlocals); fpo->fz_stuff.as_int = (po->stack_depth<<8) | ((int) po->last_used_reg); --- 15,20 ---- { clear_tmp_marks(&po->vlocals); ! fpo->fz_vlocals = array_new(po->vlocals.count); ! duplicate_array(fpo->fz_vlocals, &po->vlocals); fpo->fz_stuff.as_int = (po->stack_depth<<8) | ((int) po->last_used_reg); *************** *** 26,30 **** if (fpo->fz_pyc_data != NULL) pyc_data_delete(fpo->fz_pyc_data); ! deallocate_array(&fpo->fz_vlocals, NULL); } --- 28,32 ---- if (fpo->fz_pyc_data != NULL) pyc_data_delete(fpo->fz_pyc_data); ! array_delete(fpo->fz_vlocals, NULL); } *************** *** 52,65 **** { /* rebuild a PsycoObject from 'this' */ ! PsycoObject* po = PsycoObject_New(); po->stack_depth = get_stack_depth(fpo); po->last_used_reg = (reg_t)(fpo->fz_stuff.as_int & 0xFF); po->arguments_count = fpo->fz_arguments_count; ! assert_cleared_tmp_marks(&fpo->fz_vlocals); ! duplicate_array(&po->vlocals, &fpo->fz_vlocals); ! clear_tmp_marks(&fpo->fz_vlocals); find_regs_array(&po->vlocals, po); - pyc_data_build(po); frozen_copy(&po->pr, fpo->fz_pyc_data); return po; } --- 54,67 ---- { /* rebuild a PsycoObject from 'this' */ ! PsycoObject* po = PsycoObject_New(fpo->fz_vlocals->count); po->stack_depth = get_stack_depth(fpo); po->last_used_reg = (reg_t)(fpo->fz_stuff.as_int & 0xFF); po->arguments_count = fpo->fz_arguments_count; ! assert_cleared_tmp_marks(fpo->fz_vlocals); ! duplicate_array(&po->vlocals, fpo->fz_vlocals); ! clear_tmp_marks(fpo->fz_vlocals); find_regs_array(&po->vlocals, po); frozen_copy(&po->pr, fpo->fz_pyc_data); + pyc_data_build(po, psyco_get_merge_points(po->pr.co)); return po; } *************** *** 182,186 **** { /* respawn finished */ ! extra_assert(codebuf->snapshot.fz_vlocals.count == 0); fpo_build(&codebuf->snapshot, po); } --- 184,188 ---- { /* respawn finished */ ! extra_assert(codebuf->snapshot.fz_vlocals == NullArray); fpo_build(&codebuf->snapshot, po); } *************** *** 387,392 **** /* invariant: all snapshot.fz_vlocals in the fatlist have all their 'tmp' fields set to NULL. */ ! assert_cleared_tmp_marks(&codebuf->snapshot.fz_vlocals); ! diff = compatible_array(&po->vlocals, &codebuf->snapshot.fz_vlocals); if (diff != INCOMPATIBLE) { --- 389,394 ---- /* invariant: all snapshot.fz_vlocals in the fatlist have all their 'tmp' fields set to NULL. */ ! assert_cleared_tmp_marks(codebuf->snapshot.fz_vlocals); ! diff = compatible_array(&po->vlocals, codebuf->snapshot.fz_vlocals); if (diff != INCOMPATIBLE) { *************** *** 403,407 **** { /* Partial match, clear 'tmp' fields */ ! clear_tmp_marks(&codebuf->snapshot.fz_vlocals); if (result == INCOMPATIBLE) { --- 405,409 ---- { /* Partial match, clear 'tmp' fields */ ! clear_tmp_marks(codebuf->snapshot.fz_vlocals); if (result == INCOMPATIBLE) { *************** *** 413,417 **** } else /* compatible_array() should have reset all 'tmp' fields */ ! assert_cleared_tmp_marks(&codebuf->snapshot.fz_vlocals); } return result; --- 415,419 ---- } else /* compatible_array() should have reset all 'tmp' fields */ ! assert_cleared_tmp_marks(codebuf->snapshot.fz_vlocals); } return result; *************** *** 421,432 **** void psyco_stabilize(CodeBufferObject* lastmatch) { ! clear_tmp_marks(&lastmatch->snapshot.fz_vlocals); ! } ! ! ! DEFINEFN ! void psyco_dispatcher_init() ! { ! global_entries.fatlist = PyList_New(0); } --- 423,427 ---- void psyco_stabilize(CodeBufferObject* lastmatch) { ! clear_tmp_marks(lastmatch->snapshot.fz_vlocals); } *************** *** 584,588 **** memset(dm.usages, 0, dm.usages_size); /* set to all NULL */ memset(dm.copy_regs, 0, sizeof(dm.copy_regs)); ! data_original_table(&dm, &target_codebuf->snapshot.fz_vlocals); dm.po = po; --- 579,583 ---- memset(dm.usages, 0, dm.usages_size); /* set to all NULL */ memset(dm.copy_regs, 0, sizeof(dm.copy_regs)); ! data_original_table(&dm, target_codebuf->snapshot.fz_vlocals); dm.po = po; *************** *** 592,596 **** /* update the stack */ ! code = data_update_stack(code, &dm, &target_codebuf->snapshot.fz_vlocals); /* update the registers (1): reg-to-reg moves and exchanges */ --- 587,591 ---- /* update the stack */ ! code = data_update_stack(code, &dm, target_codebuf->snapshot.fz_vlocals); /* update the registers (1): reg-to-reg moves and exchanges */ *************** *** 815,819 **** /* compile from this new state, in which 'v' has been promoted to compile-time. */ ! codebuf = psyco_compile_code(po); /* store the new code buffer into the local cache */ --- 810,815 ---- /* compile from this new state, in which 'v' has been promoted to compile-time. */ ! codebuf = psyco_compile_code(po, psyco_exact_merge_point(po->pr.merge_points, ! po->pr.next_instr)); /* store the new code buffer into the local cache */ *************** *** 949,953 **** /* compile from this new state */ ! codebuf = psyco_compile_code(po); /* store the pointer to the new code directly into --- 945,950 ---- /* compile from this new state */ ! codebuf = psyco_compile_code(po, psyco_exact_merge_point(po->pr.merge_points, ! po->pr.next_instr)); /* store the pointer to the new code directly into Index: dispatcher.h =================================================================== RCS file: /cvsroot/psyco/psyco/c/dispatcher.h,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** dispatcher.h 2001/12/12 19:42:59 1.3 --- dispatcher.h 2001/12/24 17:01:18 1.4 *************** *** 12,16 **** ! EXTERNFN void psyco_dispatcher_init(void); --- 12,16 ---- ! inline void psyco_dispatcher_init(void) { } *************** *** 31,35 **** struct respawn_s* respawning; } fz_stuff; ! vinfo_array_t fz_vlocals; short fz_arguments_count; short fz_respawned_cnt; --- 31,35 ---- struct respawn_s* respawning; } fz_stuff; ! vinfo_array_t* fz_vlocals; short fz_arguments_count; short fz_respawned_cnt; *************** *** 43,47 **** } inline void fpo_mark_unused(FrozenPsycoObject* fpo) { ! fpo->fz_vlocals.count = 0; fpo->fz_pyc_data = NULL; } --- 43,47 ---- } inline void fpo_mark_unused(FrozenPsycoObject* fpo) { ! fpo->fz_vlocals = NullArray; fpo->fz_pyc_data = NULL; } *************** *** 93,97 **** The details of this structure are private. XXX implemented as a list object holding CodeBufferObjects in no ! XXX particular order. MUST be optimized for reasonably fast searches. */ struct global_entries_s { --- 93,98 ---- The details of this structure are private. XXX implemented as a list object holding CodeBufferObjects in no ! XXX particular order. Must be optimized for reasonably fast searches ! XXX if the lists become large (more than just a few items). */ struct global_entries_s { *************** *** 99,103 **** }; ! EXTERNVAR global_entries_t global_entries; /* the single global entry point */ /* register the code buffer; it will be found by future calls to --- 100,109 ---- }; ! /* initialize a global_entries_t structure */ ! inline void psyco_ge_init(global_entries_t* ge) { ! ge->fatlist = PyList_New(0); ! if (ge->fatlist == NULL) ! OUT_OF_MEMORY(); ! } /* register the code buffer; it will be found by future calls to Index: mergepoints.c =================================================================== RCS file: /cvsroot/psyco/psyco/c/mergepoints.c,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** mergepoints.c 2001/12/04 16:12:07 1.1 --- mergepoints.c 2001/12/24 17:01:18 1.2 *************** *** 27,31 **** (op) == JUMP_ABSOLUTE || \ (op) == CONTINUE_LOOP || \ ! (op) == RAISE_VARARGS || \ 0) --- 27,31 ---- (op) == JUMP_ABSOLUTE || \ (op) == CONTINUE_LOOP || \ ! /* (op) == RAISE_VARARGS || */ \ 0) *************** *** 34,38 **** (op) == JUMP_IF_FALSE || \ (op) == JUMP_IF_TRUE || \ ! (op) == FOR_LOOP || \ (op) == SETUP_LOOP || \ (op) == SETUP_EXCEPT || \ --- 34,39 ---- (op) == JUMP_IF_FALSE || \ (op) == JUMP_IF_TRUE || \ ! /* (op) == FOR_LOOP || */ \ ! (op) == FOR_ITER || \ (op) == SETUP_LOOP || \ (op) == SETUP_EXCEPT || \ *************** *** 56,141 **** #define MAX_UNINTERRUPTED_RANGE 300 /* bytes of Python bytecode */ ! DEFINEFN ! char* psyco_get_merge_points(PyCodeObject* co) { - static PyObject* CodeMergePoints = NULL; - PyObject* s; if (CodeMergePoints == NULL) { CodeMergePoints = PyDict_New(); if (CodeMergePoints == NULL) OUT_OF_MEMORY(); } /* cache results */ s = PyDict_GetItem(CodeMergePoints, co->co_code); if (s == NULL) { ! int length = PyString_GET_SIZE(co->co_code); ! int bytelength = (length+7)/8; ! unsigned char* source = (unsigned char*) PyString_AS_STRING(co->co_code); ! char* target; ! char* paths = (char*) PyCore_MALLOC(length); ! int i, lasti, oparg = 0; ! if (paths == NULL) ! OUT_OF_MEMORY(); ! memset(paths, 0, length); ! ! for (i=0; i<length; ) ! { ! unsigned char op = source[i++]; ! if (HAS_ARG(op)) ! { ! i += 2; ! oparg = (source[i-1]<<8) + source[i-2]; ! if (op == EXTENDED_ARG) ! { ! op = source[i++]; ! assert(HAS_ARG(op) && op != EXTENDED_ARG); ! i += 2; ! oparg = oparg<<16 | ((source[i-1]<<8) + source[i-2]); ! } ! if (HAS_JREL_INSTR(op) && paths[i+oparg] < 2) ! { ! if (HAS_J_MULTIPLE(op)) ! paths[i+oparg] = 2; ! else ! paths[i+oparg]++; ! } ! if (HAS_JABS_INSTR(op) && paths[oparg] < 2) ! { ! if (HAS_J_MULTIPLE(op)) ! paths[oparg] = 2; ! else ! paths[oparg]++; ! } ! if (IS_CTXDEP_INSTR(op)) ! paths[i] = 2; ! } ! if (!IS_JUMP_INSTR(op)) ! paths[i]++; ! } ! ! s = PyString_FromStringAndSize(NULL, bytelength); ! if (s == NULL) ! OUT_OF_MEMORY(); ! target = PyString_AS_STRING(s); ! memset(target, 0, bytelength); ! ! /* printf("mergepoints.c: "); */ ! lasti = 0; ! for (i=0; i<length; i++) ! if (paths[i] > 1 || (i-lasti > MAX_UNINTERRUPTED_RANGE && paths[i] > 0)) ! { ! lasti = i; ! SET_ARRAY_BIT(target, i); ! /* printf("[%d]", i); */ ! } ! /* printf("\n"); */ ! ! PyCore_FREE(paths); if (PyDict_SetItem(CodeMergePoints, co->co_code, s)) OUT_OF_MEMORY(); } ! return PyString_AS_STRING(s); } --- 57,327 ---- #define MAX_UNINTERRUPTED_RANGE 300 /* bytes of Python bytecode */ ! /* all other supported instructions must be listed here. */ ! static const unsigned char other_opcodes[] = { ! POP_TOP, ! ROT_TWO, ! ROT_THREE, ! ROT_FOUR, ! DUP_TOP, ! DUP_TOPX, ! UNARY_POSITIVE, ! UNARY_NEGATIVE, ! UNARY_NOT, ! UNARY_CONVERT, ! UNARY_INVERT, ! BINARY_POWER, ! BINARY_MULTIPLY, ! BINARY_DIVIDE, ! BINARY_MODULO, ! BINARY_ADD, ! BINARY_SUBTRACT, ! BINARY_SUBSCR, ! BINARY_LSHIFT, ! BINARY_RSHIFT, ! BINARY_AND, ! BINARY_XOR, ! BINARY_OR, ! INPLACE_POWER, ! INPLACE_MULTIPLY, ! INPLACE_DIVIDE, ! INPLACE_MODULO, ! INPLACE_ADD, ! INPLACE_SUBTRACT, ! INPLACE_LSHIFT, ! INPLACE_RSHIFT, ! INPLACE_AND, ! INPLACE_XOR, ! INPLACE_OR, ! SLICE+0, ! SLICE+1, ! SLICE+2, ! SLICE+3, ! STORE_SLICE+0, ! STORE_SLICE+1, ! STORE_SLICE+2, ! STORE_SLICE+3, ! DELETE_SLICE+0, ! DELETE_SLICE+1, ! DELETE_SLICE+2, ! DELETE_SLICE+3, ! STORE_SUBSCR, ! DELETE_SUBSCR, ! PRINT_ITEM, ! PRINT_ITEM_TO, ! PRINT_NEWLINE, ! PRINT_NEWLINE_TO, ! POP_BLOCK, ! END_FINALLY, ! UNPACK_SEQUENCE, ! STORE_ATTR, ! DELETE_ATTR, ! STORE_GLOBAL, ! DELETE_GLOBAL, ! LOAD_CONST, ! LOAD_GLOBAL, ! LOAD_FAST, ! STORE_FAST, ! DELETE_FAST, ! BUILD_TUPLE, ! BUILD_LIST, ! BUILD_MAP, ! LOAD_ATTR, ! /* COMPARE_OP see below */ ! GET_ITER, ! SET_LINENO, ! CALL_FUNCTION, ! 0 }; ! ! #define SUPPORTED_COMPARE_ARG(oparg) ( \ ! (oparg) == Py_LT || \ ! (oparg) == Py_LE || \ ! (oparg) == Py_EQ || \ ! (oparg) == Py_NE || \ ! (oparg) == Py_GT || \ ! (oparg) == Py_GE || \ ! (oparg) == IS || \ ! (oparg) == IS_NOT || \ ! (oparg) == EXC_MATCH || \ ! 0) ! ! static PyObject* CodeMergePoints = NULL; ! static char instr_control_flow[256]; ! ! ! #define MP_SUPPORTED 0x01 ! #define MP_IS_JUMP 0x02 ! #define MP_HAS_JREL 0x04 ! #define MP_HAS_JABS 0x08 ! #define MP_HAS_J_MULTIPLE 0x10 ! #define MP_IS_CTXDEP 0x20 ! ! ! inline void init_merge_points(void) { if (CodeMergePoints == NULL) { + int i; + const unsigned char* p; + for (i=0; i<256; i++) { + char b = 0; + if (IS_JUMP_INSTR(i)) b |= MP_IS_JUMP; + if (HAS_JREL_INSTR(i)) b |= MP_HAS_JREL; + if (HAS_JABS_INSTR(i)) b |= MP_HAS_JABS; + if (HAS_J_MULTIPLE(i)) b |= MP_HAS_J_MULTIPLE; + if (IS_CTXDEP_INSTR(i)) b |= MP_IS_CTXDEP; + instr_control_flow[i] = b; + } + for (p=other_opcodes; *p; p++) + instr_control_flow[(int)(*p)] |= MP_SUPPORTED; + CodeMergePoints = PyDict_New(); if (CodeMergePoints == NULL) OUT_OF_MEMORY(); } + } + + inline PyObject* build_merge_points(PyCodeObject* co) + { + PyObject* s; + mergepoint_t* mp; + int length = PyString_GET_SIZE(co->co_code); + unsigned char* source = (unsigned char*) PyString_AS_STRING(co->co_code); + char* paths = (char*) PyCore_MALLOC(length); + int i, lasti, count, oparg = 0; + if (paths == NULL) + OUT_OF_MEMORY(); + memset(paths, 0, length); + paths[0] = 2; /* always a merge point at the beginning of the bytecode */ + + for (i=0; i<length; ) + { + #ifdef VERBOSE + int i0 = i; + #endif + char flags; + unsigned char op = source[i++]; + if (HAS_ARG(op)) + { + i += 2; + oparg = (source[i-1]<<8) + source[i-2]; + if (op == EXTENDED_ARG) + { + op = source[i++]; + assert(HAS_ARG(op) && op != EXTENDED_ARG); + i += 2; + oparg = oparg<<16 | ((source[i-1]<<8) + source[i-2]); + } + } + flags = instr_control_flow[(int) op]; + if (flags == 0) + if (op != COMPARE_OP || !SUPPORTED_COMPARE_ARG(oparg)) + { + /* unsupported instruction */ + #ifdef VERBOSE + printf("psyco: unsupported instruction: %d at position %d\n", + (int) op, i0); + #endif + PyCore_FREE(paths); + Py_INCREF(Py_None); + return Py_None; + } + if (HAS_JREL_INSTR(op) && paths[i+oparg] < 2) + { + if (HAS_J_MULTIPLE(op)) + paths[i+oparg] = 2; + else + paths[i+oparg]++; + } + if (HAS_JABS_INSTR(op) && paths[oparg] < 2) + { + if (HAS_J_MULTIPLE(op)) + paths[oparg] = 2; + else + paths[oparg]++; + } + if (IS_CTXDEP_INSTR(op)) + paths[i] = 2; + else if (!IS_JUMP_INSTR(op)) + paths[i]++; + } + + /* count the merge points */ + count = 0; + lasti = 0; + for (i=0; i<length; i++) + { + if (i-lasti > MAX_UNINTERRUPTED_RANGE && paths[i] > 0) + paths[i] = 2; /* ensure there are merge points at regular intervals */ + if (paths[i] > 1) + { + lasti = i; + count++; + } + } + /* allocate the string buffer, one mergepoint_t per merge point plus + the room for a final '-1'. */ + count = count * sizeof(mergepoint_t) + sizeof(int); + s = PyString_FromStringAndSize(NULL, count); + if (s == NULL) + OUT_OF_MEMORY(); + mp = (mergepoint_t*) PyString_AS_STRING(s); + + for (i=0; i<length; i++) + if (paths[i] > 1) + { + mp->bytecode_position = i; + psyco_ge_init(&mp->entries); + mp++; + } + mp->bytecode_position = -1; + PyCore_FREE(paths); + return s; + } + + + DEFINEFN + PyObject* psyco_get_merge_points(PyCodeObject* co) + { + PyObject* s; + init_merge_points(); + /* cache results */ s = PyDict_GetItem(CodeMergePoints, co->co_code); if (s == NULL) { ! s = build_merge_points(co); if (PyDict_SetItem(CodeMergePoints, co->co_code, s)) OUT_OF_MEMORY(); + Py_DECREF(s); /* one ref left in the dict */ } ! return s; ! } ! ! DEFINEFN ! mergepoint_t* psyco_next_merge_point(PyObject* mergepoints, ! int position) ! { ! mergepoint_t* array; ! int bufsize; ! extra_assert(PyString_Check(mergepoints)); ! array = (mergepoint_t*) PyString_AS_STRING(mergepoints); ! bufsize = PyString_GET_SIZE(mergepoints); ! extra_assert((bufsize % sizeof(mergepoint_t)) == sizeof(int)); ! bufsize /= sizeof(mergepoint_t); ! extra_assert(bufsize > 0); ! do { ! int test = bufsize/2; ! if (position > array[test].bytecode_position) ! { ! ++test; ! array += test; ! bufsize -= test; ! } ! else ! { ! bufsize = test; ! } ! } while (bufsize > 0); ! return array; } Index: mergepoints.h =================================================================== RCS file: /cvsroot/psyco/psyco/c/mergepoints.h,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** mergepoints.h 2001/12/04 16:12:07 1.1 --- mergepoints.h 2001/12/24 17:01:18 1.2 *************** *** 9,25 **** #include "psyco.h" #include <compile.h> - #define CHECK_ARRAY_BIT(s, n) ((s)[(n)/8] & (1<<((n)&7))) - #define SET_ARRAY_BIT(s, n) ((s)[(n)/8] |= (1<<((n)&7))) - /* A merge point is a point reached by two or more control paths in the bytecode. They are a subset of the targets found by the standard module function dis.findlabels(). It may be a subset because some targets can only be reached by jumping from a single point, e.g. 'else:'. ! ! The following function detects the merge points and set them in a bit array. */ ! EXTERNFN char* psyco_get_merge_points(PyCodeObject* co); --- 9,61 ---- #include "psyco.h" + #include "dispatcher.h" #include <compile.h> /* A merge point is a point reached by two or more control paths in the bytecode. They are a subset of the targets found by the standard module function dis.findlabels(). It may be a subset because some targets can only be reached by jumping from a single point, e.g. 'else:'. ! Such targets are not merge points. */ ! ! struct mergepoint_s { ! int bytecode_position; ! global_entries_t entries; ! }; ! ! /* 'bytecode_ptr' gives the position of the merge point in the bytecode. ! An array of mergepoint_t structures is sorted against this field. ! ! 'entries' is a list of snapshots of the compiler states previously ! encountered at this point. ! */ ! ! /* The following function detects the merge points and builds an array of ! mergepoint_t structures. It returns a buffer object containing the array ! (actually a Python string), or Py_None if the bytecode uses unsupported ! instructions. Does not return a new reference. */ ! EXTERNFN PyObject* psyco_get_merge_points(PyCodeObject* co); ! ! /* Get a pointer to the first mergepoint_t structure in the array whose ! 'bytecode_ptr' is >= position. */ ! EXTERNFN mergepoint_t* psyco_next_merge_point(PyObject* mergepoints, ! int position); ! ! /* Get a pointer to the very first mergepoint_t structure in the array */ ! inline mergepoint_t* psyco_first_merge_point(PyObject* mergepoints) ! { ! extra_assert(PyString_Check(mergepoints)); ! return (mergepoint_t*) PyString_AS_STRING(mergepoints); ! } ! ! /* Same as psyco_next_merge_point() but returns NULL if bytecode_ptr!=position */ ! inline mergepoint_t* psyco_exact_merge_point(PyObject* mergepoints, ! int position) ! { ! mergepoint_t* mp = psyco_next_merge_point(mergepoints, position); ! if (mp->bytecode_position != position) ! mp = NULL; ! return mp; ! } Index: psyco.c =================================================================== RCS file: /cvsroot/psyco/psyco/c/psyco.c,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** psyco.c 2001/12/13 13:16:35 1.5 --- psyco.c 2001/12/24 17:01:18 1.6 *************** *** 4,7 **** --- 4,8 ---- #include "dispatcher.h" #include "processor.h" + #include "mergepoints.h" #include "Python/pycompiler.h" #include "Objects/ptupleobject.h" *************** *** 59,69 **** PyCodeObject* co = (PyCodeObject*) PyFunction_GET_CODE(function); ! PyObject* globals = PyFunction_GET_GLOBALS(function); ! PyObject* defaults = PyFunction_GET_DEFAULTS(function); PsycoObject* po; RunTimeSource* source1; ! int extras, i, minargcnt, inputargs, rtcount; ! int ncells = PyTuple_GET_SIZE(co->co_cellvars); ! int nfrees = PyTuple_GET_SIZE(co->co_freevars); if (co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { --- 60,78 ---- PyCodeObject* co = (PyCodeObject*) PyFunction_GET_CODE(function); ! PyObject* merge_points = psyco_get_merge_points(co); ! PyObject* globals; ! PyObject* defaults; PsycoObject* po; RunTimeSource* source1; ! vinfo_array_t* arraycopy; ! int extras, i, minargcnt, inputargs, rtcount, ncells, nfrees; ! ! if (merge_points == Py_None) ! return BF_UNSUPPORTED; ! ! globals = PyFunction_GET_GLOBALS(function); ! defaults = PyFunction_GET_DEFAULTS(function); ! ncells = PyTuple_GET_SIZE(co->co_cellvars); ! nfrees = PyTuple_GET_SIZE(co->co_freevars); if (co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { *************** *** 105,125 **** extras = co->co_stacksize + co->co_nlocals + ncells + nfrees; ! po = PsycoObject_New(); po->stack_depth = INITIAL_STACK_DEPTH; ! po->vlocals.count = NB_LOCALS; po->last_used_reg = REG_LOOP_START; po->pr.auto_recursion = recursion; - /* make an array of size 'extra' for the locals and the stack */ - LOC_LOCALS_PLUS = vinfo_new(SOURCE_NOT_IMPORTANT); - LOC_LOCALS_PLUS->array = array_new(extras); - /* duplicate the array of arguments. If two arguments share some common part, they will also share it in the copy. */ ! clear_tmp_marks(arginfo); ! duplicate_array(LOC_LOCALS_PLUS->array, arginfo); ! /* simplify LOC_LOCALS_PLUS->array in the sense of psyco_simplify_array() */ ! rtcount = psyco_simplify_array(LOC_LOCALS_PLUS->array); /* all run-time arguments or argument parts must be corrected: in arginfo --- 114,136 ---- extras = co->co_stacksize + co->co_nlocals + ncells + nfrees; ! po = PsycoObject_New(INDEX_LOC_LOCALS_PLUS + extras); po->stack_depth = INITIAL_STACK_DEPTH; ! po->vlocals.count = INDEX_LOC_LOCALS_PLUS + extras; po->last_used_reg = REG_LOOP_START; po->pr.auto_recursion = recursion; /* duplicate the array of arguments. If two arguments share some common part, they will also share it in the copy. */ ! if (arginfo->count == 0) ! arraycopy = NullArray; ! else ! { ! clear_tmp_marks(arginfo); ! arraycopy = array_new(arginfo->count); ! duplicate_array(arraycopy, arginfo); ! } ! /* simplify arraycopy in the sense of psyco_simplify_array() */ ! rtcount = psyco_simplify_array(arraycopy); /* all run-time arguments or argument parts must be corrected: in arginfo *************** *** 136,166 **** else source1 = NULL; ! fix_run_time_args(po, LOC_LOCALS_PLUS->array, arginfo, source1); ! /* restore the count, which was overwritten by duplicate_array() */ ! LOC_LOCALS_PLUS->array->count = extras; /* the rest of locals is uninitialized */ ! for (i=arginfo->count; i<co->co_nlocals; i++) { vinfo_incref(psyco_viZero); ! LOC_LOCALS_PLUS->array->items[i] = psyco_viZero; } /* the rest of the array is the currently empty stack, set to NULL by array_new(). */ - - array_delete(arginfo, NULL); ! /* store the code and globals objects */ ! LOC_CODE = vinfo_new(CompileTime_NewSk(sk_new((long) co, ! SkFlagFixed | SkFlagPyObj))); ! Py_INCREF(co); /* reference in LOC_CODE */ ! LOC_GLOBALS = vinfo_new(CompileTime_NewSk(sk_new((long) globals, ! SkFlagFixed | SkFlagPyObj))); ! Py_INCREF(globals); /* reference in LOC_GLOBALS */ ! ! /* initialize the remaining variables */ ! LOC_NEXT_INSTR = vinfo_new(CompileTime_NewSk(sk_new(0, SkFlagFixed))); ! pyc_data_build(po); po->stack_depth += sizeof(long); /* count the CALL return address */ --- 147,175 ---- else source1 = NULL; ! fix_run_time_args(po, arraycopy, arginfo, source1); ! /* initialize po->vlocals */ ! LOC_GLOBALS = vinfo_new(CompileTime_NewSk(sk_new((long) globals, ! SkFlagFixed | SkFlagPyObj))); ! Py_INCREF(globals); /* reference in LOC_GLOBALS */ + /* copy the arguments */ + for (i=0; i<arraycopy->count; i++) + LOC_LOCALS_PLUS[i] = arraycopy->items[i]; + array_release(arraycopy); + /* the rest of locals is uninitialized */ ! for (; i<co->co_nlocals; i++) { vinfo_incref(psyco_viZero); ! LOC_LOCALS_PLUS[i] = psyco_viZero; } /* the rest of the array is the currently empty stack, set to NULL by array_new(). */ ! /* store the code object */ ! po->pr.co = co; ! Py_INCREF(co); /* XXX never freed */ ! pyc_data_build(po, merge_points); po->stack_depth += sizeof(long); /* count the CALL return address */ *************** *** 182,192 **** int tuple_size = PsycoTuple_Load(arg_tuple); if (tuple_size == -1) ! { /* XXX calling with an unknown-at-compile-time number of arguments is not implemented, revert to the default behaviour */ - return psyco_generic_call(po, PyFunction_Type.tp_call, - CfReturnRef|CfPyErrIfNull, - "vvl", function, arg_tuple, NULL); - } /* prepare a frame */ --- 191,197 ---- int tuple_size = PsycoTuple_Load(arg_tuple); if (tuple_size == -1) ! goto fail_to_default; /* XXX calling with an unknown-at-compile-time number of arguments is not implemented, revert to the default behaviour */ /* prepare a frame */ *************** *** 199,202 **** --- 204,210 ---- } mypo = psyco_build_frame(function, arginfo, recursion, &sources); + array_delete(arginfo, NULL); + if (mypo == BF_UNSUPPORTED) + goto fail_to_default; if (mypo == NULL) { *************** *** 206,210 **** /* compile the function (this frees mypo) */ ! codebuf = psyco_compile_code(mypo); /* get the run-time argument sources and push them on the stack --- 214,219 ---- /* compile the function (this frees mypo) */ ! codebuf = psyco_compile_code(mypo, ! psyco_first_merge_point(mypo->pr.merge_points)); /* get the run-time argument sources and push them on the stack *************** *** 213,216 **** --- 222,230 ---- PyCore_FREE(sources); return result; + + fail_to_default: + return psyco_generic_call(po, PyFunction_Type.tp_call, + CfReturnRef|CfPyErrIfNull, + "vvl", function, arg_tuple, NULL); } *************** *** 279,287 **** /* make a "frame" */ po = psyco_build_frame(function, arginfo, self->psy_recursion, NULL); if (po == NULL) return NULL; /* compile the function */ ! codebuf = psyco_compile_code(po); /* get the actual arguments */ --- 293,306 ---- /* make a "frame" */ po = psyco_build_frame(function, arginfo, self->psy_recursion, NULL); + array_delete(arginfo, NULL); + if (po == BF_UNSUPPORTED) { + return PyObject_Call((PyObject*) self->psy_func, arg, kw); + } if (po == NULL) return NULL; /* compile the function */ ! codebuf = psyco_compile_code(po, ! psyco_first_merge_point(po->pr.merge_points)); /* get the actual arguments */ *************** *** 430,439 **** PyObject* d; int nsize = obj->codeend - obj->codeptr; ! PyCodeObject* co; ! if (obj->snapshot.fz_vlocals.count > INDEX_LOC_CODE) ! co = (PyCodeObject*)(CompileTime_Get( ! obj->snapshot.fz_vlocals.items[INDEX_LOC_CODE]->source)->value); ! else ! co = NULL; fprintf(f, "CodeBufferObject %p %d %d '%s' '%s' '%s'\n", obj->codeptr, nsize, get_stack_depth(&obj->snapshot), --- 449,454 ---- PyObject* d; int nsize = obj->codeend - obj->codeptr; ! PyCodeObject* co = obj->snapshot.fz_pyc_data ? ! obj->snapshot.fz_pyc_data->co : NULL; fprintf(f, "CodeBufferObject %p %d %d '%s' '%s' '%s'\n", obj->codeptr, nsize, get_stack_depth(&obj->snapshot), *************** *** 443,447 **** d = PyDict_New(); assert(d); ! vinfo_array_dump(&obj->snapshot.fz_vlocals, f, d); Py_DECREF(d); fwrite(obj->codeptr, 1, nsize, f); --- 458,462 ---- d = PyDict_New(); assert(d); ! vinfo_array_dump(obj->snapshot.fz_vlocals, f, d); Py_DECREF(d); fwrite(obj->codeptr, 1, nsize, f); Index: psyco.h =================================================================== RCS file: /cvsroot/psyco/psyco/c/psyco.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** psyco.h 2001/12/12 19:42:59 1.2 --- psyco.h 2001/12/24 17:01:18 1.3 *************** *** 124,127 **** --- 124,128 ---- typedef struct CodeBufferObject_s CodeBufferObject; /* def in codemanager.h */ typedef struct global_entries_s global_entries_t; /* def in dispatcher.h */ + typedef struct mergepoint_s mergepoint_t; /* defined in mergepoint.h */ EXTERNVAR PyObject* PyExc_PsycoError; *************** *** 143,146 **** --- 144,148 ---- /* Build a PsycoObject "frame" corresponding to the call of a Python function. Raise a Python exception and return NULL in case of failure. + Return BF_UNSUPPORTED if the bytecode contains unsupported instructions. The 'arginfo' array gives the number of arguments as well as additional information about them. It will be expanded with the *************** *** 152,155 **** --- 154,158 ---- long** sources); /* 'sources' is actually of type 'RunTimeSource**' */ + #define BF_UNSUPPORTED ((PsycoObject*) -1) /* Encode a call to the given Python function, compiling it as needed. */ Index: vcompiler.c =================================================================== RCS file: /cvsroot/psyco/psyco/c/vcompiler.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** vcompiler.c 2001/12/12 19:42:59 1.3 --- vcompiler.c 2001/12/24 17:01:18 1.4 *************** *** 2,5 **** --- 2,6 ---- #include "dispatcher.h" #include "codemanager.h" + #include "mergepoints.h" #include "Python/pycompiler.h" #include "pycencoding.h" *************** *** 328,332 **** { /* make a depth copy of an array. ! Same requirements as psyco_duplicate(). */ int i; for (i=0; i<source->count; i++) --- 329,334 ---- { /* make a depth copy of an array. ! Same requirements as psyco_duplicate(). ! Do not use for arrays of length 0. */ int i; for (i=0; i<source->count; i++) *************** *** 368,372 **** int i; ! PsycoObject* result = PsycoObject_New(); psyco_assert_coherent(po); assert_cleared_tmp_marks(&po->vlocals); --- 370,374 ---- int i; ! PsycoObject* result = PsycoObject_New(po->vlocals.count); psyco_assert_coherent(po); assert_cleared_tmp_marks(&po->vlocals); *************** *** 490,494 **** static code_t* psyco_resume_compile(PsycoObject* po, void* extra) { ! return psyco_compile_code(po)->codeptr; /* XXX don't know what to do with the reference returned by XXX po->compile_code() */ --- 492,498 ---- static code_t* psyco_resume_compile(PsycoObject* po, void* extra) { ! mergepoint_t* mp = psyco_exact_merge_point(po->pr.merge_points, ! po->pr.next_instr); ! return psyco_compile_code(po, mp)->codeptr; /* XXX don't know what to do with the reference returned by XXX po->compile_code() */ *************** *** 496,508 **** ! /* Main compiling function. Emit code corresponding to 'this' state. ! The compiler produces its code into 'this->code' and the return value is ! the end of the written code. */ DEFINEFN ! code_t* psyco_compile(PsycoObject* po, bool continue_compilation) { - CodeBufferObject* codebuf; CodeBufferObject* oldcodebuf; ! vinfo_t* diff = psyco_compatible(po, &global_entries, &oldcodebuf); /*psyco_assert_cleared_tmp_marks(&po->vlocals); -- not needed -- */ --- 500,513 ---- ! /* Main compiling function. Emit machine code corresponding to the state ! 'po'. The compiler produces its code into 'code' and the return value is ! the end of the written code. 'po' is freed. */ DEFINEFN ! code_t* psyco_compile(PsycoObject* po, mergepoint_t* mp, ! bool continue_compilation) { CodeBufferObject* oldcodebuf; ! vinfo_t* diff = mp==NULL ? INCOMPATIBLE : ! psyco_compatible(po, &mp->entries, &oldcodebuf); /*psyco_assert_cleared_tmp_marks(&po->vlocals); -- not needed -- */ *************** *** 533,544 **** /* Enough space left, continue in the same buffer. */ ! codebuf = psyco_proxy_code_buffer(po, &global_entries); ! if (codebuf == NULL) ! OUT_OF_MEMORY(); #ifdef CODE_DUMP_FILE ! codebuf->chained_list = psyco_codebuf_chained_list; ! psyco_codebuf_chained_list = codebuf; #endif ! Py_DECREF(codebuf); if (diff != INCOMPATIBLE) --- 538,552 ---- /* Enough space left, continue in the same buffer. */ ! if (mp != NULL) ! { ! CodeBufferObject* codebuf = psyco_proxy_code_buffer(po, &mp->entries); ! if (codebuf == NULL) ! OUT_OF_MEMORY(); #ifdef CODE_DUMP_FILE ! codebuf->chained_list = psyco_codebuf_chained_list; ! psyco_codebuf_chained_list = codebuf; #endif ! Py_DECREF(codebuf); ! } if (diff != INCOMPATIBLE) *************** *** 547,551 **** psyco_unfix(po, diff); /* start over (maybe we have already seen this new state) */ ! return psyco_compile(po, continue_compilation); } --- 555,559 ---- psyco_unfix(po, diff); /* start over (maybe we have already seen this new state) */ ! return psyco_compile(po, mp, continue_compilation); } *************** *** 559,566 **** DEFINEFN ! void psyco_compile_cond(PsycoObject* po, condition_code_t condition) { CodeBufferObject* oldcodebuf; ! vinfo_t* diff = psyco_compatible(po, &global_entries, &oldcodebuf); PsycoObject* po2 = PsycoObject_Duplicate(po); --- 567,576 ---- DEFINEFN ! void psyco_compile_cond(PsycoObject* po, mergepoint_t* mp, ! condition_code_t condition) { CodeBufferObject* oldcodebuf; ! vinfo_t* diff = mp==NULL ? INCOMPATIBLE : ! psyco_compatible(po, &mp->entries, &oldcodebuf); PsycoObject* po2 = PsycoObject_Duplicate(po); *************** *** 609,618 **** existing code buffer. Return a new code buffer. */ DEFINEFN ! CodeBufferObject* psyco_compile_code(PsycoObject* po) { code_t* code1; CodeBufferObject* codebuf; CodeBufferObject* oldcodebuf; ! vinfo_t* diff = psyco_compatible(po, &global_entries, &oldcodebuf); /*psyco_assert_cleared_tmp_marks(&po->vlocals); -- not needed -- */ --- 619,629 ---- existing code buffer. Return a new code buffer. */ DEFINEFN ! CodeBufferObject* psyco_compile_code(PsycoObject* po, mergepoint_t* mp) { code_t* code1; CodeBufferObject* codebuf; CodeBufferObject* oldcodebuf; ! vinfo_t* diff = mp==NULL ? INCOMPATIBLE : ! psyco_compatible(po, &mp->entries, &oldcodebuf); /*psyco_assert_cleared_tmp_marks(&po->vlocals); -- not needed -- */ *************** *** 621,625 **** return psyco_unify_code(po, oldcodebuf); ! codebuf = psyco_new_code_buffer(po, &global_entries); /* start a new buffer */ if (codebuf == NULL) OUT_OF_MEMORY(); --- 632,637 ---- return psyco_unify_code(po, oldcodebuf); ! /* start a new buffer */ ! codebuf = psyco_new_code_buffer(po, mp==NULL ? NULL : &mp->entries); if (codebuf == NULL) OUT_OF_MEMORY(); *************** *** 630,634 **** psyco_unfix(po, diff); /* start over (maybe we have already seen this new state) */ ! code1 = psyco_compile(po, false); } else --- 642,646 ---- psyco_unfix(po, diff); /* start over (maybe we have already seen this new state) */ ! code1 = psyco_compile(po, mp, false); } else Index: vcompiler.h =================================================================== RCS file: /cvsroot/psyco/psyco/c/vcompiler.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** vcompiler.h 2001/12/06 15:46:25 1.2 --- vcompiler.h 2001/12/24 17:01:18 1.3 *************** *** 223,227 **** struct vinfo_array_s { int count; ! vinfo_t* items[NB_LOCALS]; /* variable-sized when not in a PsycoObject */ }; --- 223,227 ---- struct vinfo_array_s { int count; ! vinfo_t* items[7]; /* always variable-sized */ }; *************** *** 351,371 **** /* used to be a Python object, hence the name */ ! /* first, the description of variable stages. This is the data against ! which state matches and synchronizations are performed. */ int stack_depth; /* the size of data currently pushed in the stack */ - vinfo_array_t vlocals; /* all the 'vinfo_t' variables */ vinfo_t* reg_array[REG_TOTAL]; /* the 'vinfo_t' currently stored in regs */ vinfo_t* ccreg; /* processor condition codes (aka flags) */ ! /* next, compiler private variables for producing and optimizing code. */ ! reg_t last_used_reg; /* the most recently used register */ ! int arguments_count; /* # run-time arguments given to the function */ int respawn_cnt; /* see psyco_prepare_respawn() */ CodeBufferObject* respawn_proxy; /* see psyco_prepare_respawn() */ - code_t* code; /* where the emitted code goes */ - code_t* codelimit; /* do not write code past this limit */ pyc_data_t pr; /* private language-dependent data */ }; /* run-time vinfo_t creation */ inline vinfo_t* new_rtvinfo(PsycoObject* po, reg_t reg, bool ref) { --- 351,380 ---- /* used to be a Python object, hence the name */ ! /* assembly code */ ! code_t* code; /* where the emitted code goes */ ! code_t* codelimit; /* do not write code past this limit */ ! ! /* processor state */ int stack_depth; /* the size of data currently pushed in the stack */ vinfo_t* reg_array[REG_TOTAL]; /* the 'vinfo_t' currently stored in regs */ vinfo_t* ccreg; /* processor condition codes (aka flags) */ ! /* compiler private variables for producing and optimizing code */ ! reg_t last_used_reg; /* the most recently used register */ ! int arguments_count; /* # run-time arguments given to the function */ int respawn_cnt; /* see psyco_prepare_respawn() */ CodeBufferObject* respawn_proxy; /* see psyco_prepare_respawn() */ pyc_data_t pr; /* private language-dependent data */ + + /* least, the description of variable stages. This is the data against + which state matches and synchronizations are performed. */ + vinfo_array_t vlocals; /* all the 'vinfo_t' variables */ + /* variable-sized array! */ }; + #define PSYCOOBJECT_SIZE(arraycnt) \ + (sizeof(PsycoObject)-sizeof(vinfo_array_t) + sizeof(int) + \ + (arraycnt)*sizeof(vinfo_t*)) + /* run-time vinfo_t creation */ inline vinfo_t* new_rtvinfo(PsycoObject* po, reg_t reg, bool ref) { *************** *** 395,401 **** /* Main compiling function. Emit machine code corresponding to the state 'po'. The compiler produces its code into 'code' and the return value is ! the end of the written code. 'po' is freed. ! Be sure to call po->vlocals.clear_tmp_marks() before this function. 'continue_compilation' is normally false. When compile() is called --- 404,411 ---- /* Main compiling function. Emit machine code corresponding to the state 'po'. The compiler produces its code into 'code' and the return value is ! the end of the written code. 'po' is freed. 'mp' is the current mergepoint ! position or NULL if there is no mergepoint here. ! Be sure to call clear_tmp_marks(&po->vlocals) before this function. 'continue_compilation' is normally false. When compile() is called *************** *** 405,409 **** depth of recursion of the C stack. */ ! EXTERNFN code_t* psyco_compile(PsycoObject* po, bool continue_compilation); /* Conditional compilation: the state 'po' is compiled to be executed only if --- 415,420 ---- depth of recursion of the C stack. */ ! EXTERNFN code_t* psyco_compile(PsycoObject* po, mergepoint_t* mp, ! bool continue_compilation); /* Conditional compilation: the state 'po' is compiled to be executed only if *************** *** 411,425 **** compiled later. It always makes a copy of 'po' so that the original can be used to compile the other case ('not condition'). 'condition' must not be ! CC_ALWAYS_xxx here. */ ! EXTERNFN void psyco_compile_cond(PsycoObject* po, condition_code_t condition); /* Simplified interface to compile() without using a previously existing code buffer. Return a new code buffer. */ ! EXTERNFN CodeBufferObject* psyco_compile_code(PsycoObject* po); /* Prepare a 'coding pause', i.e. a short amount of code (proxy) that will be called only if the execution actually reaches it to go on with compilation. ! 'this' is the PsycoObject corresponding to the proxy. 'condition' may not be CC_ALWAYS_FALSE. The (possibly conditional) jump to the proxy is encoded in 'calling_code'. --- 422,438 ---- compiled later. It always makes a copy of 'po' so that the original can be used to compile the other case ('not condition'). 'condition' must not be ! CC_ALWAYS_xxx here. 'mp' is the current mergepoint position or NULL if there ! is no mergepoint here. */ ! EXTERNFN void psyco_compile_cond(PsycoObject* po, mergepoint_t* mp, ! condition_code_t condition); /* Simplified interface to compile() without using a previously existing code buffer. Return a new code buffer. */ ! EXTERNFN CodeBufferObject* psyco_compile_code(PsycoObject* po, mergepoint_t* mp); /* Prepare a 'coding pause', i.e. a short amount of code (proxy) that will be called only if the execution actually reaches it to go on with compilation. ! 'po' is the PsycoObject corresponding to the proxy. 'condition' may not be CC_ALWAYS_FALSE. The (possibly conditional) jump to the proxy is encoded in 'calling_code'. *************** *** 440,448 **** /* construction */ ! inline PsycoObject* PsycoObject_New(void) { ! PsycoObject* po = (PsycoObject*) PyCore_MALLOC(sizeof(PsycoObject)); ! if (po == NULL) OUT_OF_MEMORY(); ! memset(po, 0, sizeof(PsycoObject)); return po; } --- 453,462 ---- /* construction */ ! inline PsycoObject* PsycoObject_New(int vlocalscnt) { ! int psize = PSYCOOBJECT_SIZE(vlocalscnt); ! PsycoObject* po = (PsycoObject*) PyCore_MALLOC(psize); ! if (po == NULL) OUT_OF_MEMORY(); ! memset(po, 0, psize); return po; } |