protected void ct_conv_buff_resize(ct_buffer_t *conv, size_t mincsize, size_t minwsize) { void *p; if (mincsize > conv->csize) { conv->csize = mincsize; p = el_realloc(conv->cbuff, conv->csize * sizeof(char)); if (p == NULL) { conv->csize = 0; el_free(conv->cbuff); conv->cbuff = NULL; } else conv->cbuff = p; } if (minwsize > conv->wsize) { conv->wsize = minwsize; p = el_realloc(conv->wbuff, conv->wsize * sizeof(Char)); if (p == NULL) { conv->wsize = 0; el_free(conv->wbuff); conv->wbuff = NULL; } else conv->wbuff = p; } }
/* el_read_end(): * Free the data structures used by the read stuff. */ libedit_private void read_end(struct el_read_t *el_read) { read_clearmacros(&el_read->macros); el_free(el_read->macros.macro); el_read->macros.macro = NULL; el_free(el_read); }
/* hist_end(): * clean up history; */ libedit_private void hist_end(EditLine *el) { el_free(el->el_history.buf); el->el_history.buf = NULL; }
/* sig_end(): * Clear all signal stuff */ libedit_private void sig_end(EditLine *el) { el_free(el->el_signal); el->el_signal = NULL; }
static void ch__clearmacro(EditLine *el) { c_macro_t *ma = &el->el_chared.c_macro; while (ma->level >= 0) el_free(ma->macro[ma->level--]); }
void param_free(param_t **pparamlst) { param_t *p,*pn; #if !TX86 debug_assert(PARSER); #endif for (p = *pparamlst; p; p = pn) { param_debug(p); pn = p->Pnext; type_free(p->Ptype); #if TX86 mem_free(p->Pident); #else MEM_PH_FREE(p->Pident); #endif el_free(p->Pelem); type_free(p->Pdeftype); if (p->Pptpl) param_free(&p->Pptpl); #ifdef DEBUG p->id = 0; #endif p->Pnext = param_list; param_list = p; } *pparamlst = NULL; }
/** * Destroy all elements in queue and queue itself. Also notifies squeue_pop * Doesn't deallocate squeue_t * * @param sq synchronized queue to destroy * @param free helper to destroy element's data * * @note squeue_destroy() will notify consumer but doesn't guarantee that it \ * will leave squeue_pop(). You need to check this on your own. \ * It could be easily done by joining consumer thread. * */ void squeue_destroy(squeue_t* sq, void (*el_free)(void* obj)) { squeue_el_t* el; squeue_el_t* next; mutex_lock(&sq->sq_mutex); el = sq->sq_head; while(el != NULL) { next = el->s_next; el_free(el->s_data); mp_free(el); el = next; } sq->sq_is_destroyed = B_TRUE; cv_notify_all(&sq->sq_cv); mutex_unlock(&sq->sq_mutex); mutex_destroy(&sq->sq_mutex); cv_destroy(&sq->sq_cv); }
static void read_clearmacros(struct macros *ma) { while (ma->level >= 0) el_free(ma->macro[ma->level--]); ma->offset = 0; }
/* el_init(): * Initialize editline and set default parameters. */ public EditLine * el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr) { EditLine *el = (EditLine *) el_malloc(sizeof(EditLine)); if (el == NULL) return (NULL); memset(el, 0, sizeof(EditLine)); el->el_infile = fin; el->el_outfile = fout; el->el_errfile = ferr; el->el_infd = fileno(fin); if ((el->el_prog = el_strdup(prog)) == NULL) { el_free(el); return NULL; } /* * Initialize all the modules. Order is important!!! */ el->el_flags = 0; if (term_init(el) == -1) { el_free(el->el_prog); el_free(el); return NULL; } (void) key_init(el); (void) map_init(el); if (tty_init(el) == -1) el->el_flags |= NO_TTY; (void) ch_init(el); (void) search_init(el); (void) hist_init(el); (void) prompt_init(el); (void) sig_init(el); (void) read_init(el); return (el); }
/* ch_end(): * Free the data structures used by the editor */ libedit_private void ch_end(EditLine *el) { el_free(el->el_line.buffer); el->el_line.buffer = NULL; el->el_line.limit = NULL; el_free(el->el_chared.c_undo.buf); el->el_chared.c_undo.buf = NULL; el_free(el->el_chared.c_redo.buf); el->el_chared.c_redo.buf = NULL; el->el_chared.c_redo.pos = NULL; el->el_chared.c_redo.lim = NULL; el->el_chared.c_redo.cmd = ED_UNASSIGNED; el_free(el->el_chared.c_kill.buf); el->el_chared.c_kill.buf = NULL; ch_reset(el, 1); el_free(el->el_chared.c_macro.macro); el->el_chared.c_macro.macro = NULL; }
/* read_pop(): * Pop a macro from the stack */ static void read_pop(struct macros *ma) { int i; el_free(ma->macro[0]); for (i = 0; i < ma->level; i++) ma->macro[i] = ma->macro[i + 1]; ma->level--; ma->offset = 0; }
static const char * append_char_function(const char *name) { struct stat stbuf; char *expname = *name == '~' ? fn_tilde_expand(name) : NULL; const char *rs = " "; if (stat(expname ? expname : name, &stbuf) == -1) goto out; if (S_ISDIR(stbuf.st_mode)) rs = "/"; out: if (expname) el_free(expname); return rs; }
void type_free(type *t) { type *tn; tym_t ty; while (t) { //dbg_printf("type_free(%p, Tcount = %d)\n", t, t->Tcount); type_debug(t); assert((int)t->Tcount != -1); if (--t->Tcount) /* if usage count doesn't go to 0 */ break; ty = tybasic(t->Tty); if (tyfunc(ty)) { param_free(&t->Tparamtypes); list_free(&t->Texcspec, (list_free_fp)type_free); } #if !MARS else if (ty == TYtemplate) param_free(&t->Tparamtypes); else if (ty == TYident) MEM_PH_FREE(t->Tident); #endif else if (t->Tflags & TFvla && t->Tel) el_free(t->Tel); #if SCPP else if (t->Talternate && typtr(ty)) type_free(t->Talternate); #endif #if MARS else if (t->Tkey && typtr(ty)) type_free(t->Tkey); #endif #ifdef DEBUG type_num--; //dbg_printf("Free'ing type %p ",t); WRTYxx(t->Tty); dbg_printf("\n"); t->id = 0; /* no longer a valid type */ #endif tn = t->Tnext; t->Tnext = type_list; type_list = t; /* link into free list */ t = tn; } }
static int ct_conv_wbuff_resize(ct_buffer_t *conv, size_t wsize) { void *p; if (wsize <= conv->wsize) return 0; conv->wsize = wsize; p = el_realloc(conv->wbuff, conv->wsize * sizeof(*conv->wbuff)); if (p == NULL) { conv->wsize = 0; el_free(conv->wbuff); conv->wbuff = NULL; return -1; } conv->wbuff = p; return 0; }
/* * does tilde expansion of strings of type ``~user/foo'' * if ``user'' isn't valid user name or ``txt'' doesn't start * w/ '~', returns pointer to strdup()ed copy of ``txt'' * * it's callers's responsibility to free() returned string */ char * fn_tilde_expand(const char *txt) { #if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) struct passwd pwres; char pwbuf[1024]; #endif struct passwd *pass; char *temp; size_t len = 0; if (txt[0] != '~') return strdup(txt); temp = strchr(txt + 1, '/'); if (temp == NULL) { temp = strdup(txt + 1); if (temp == NULL) return NULL; } else { /* text until string after slash */ len = (size_t)(temp - txt + 1); temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } if (temp[0] == 0) { #ifdef HAVE_GETPW_R_POSIX if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) pass = NULL; #elif HAVE_GETPW_R_DRAFT pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); #else pass = getpwuid(getuid()); #endif } else { #ifdef HAVE_GETPW_R_POSIX if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) pass = NULL; #elif HAVE_GETPW_R_DRAFT pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); #else pass = getpwnam(temp); #endif } el_free(temp); /* value no more needed */ if (pass == NULL) return strdup(txt); /* update pointer txt to point at string immedially following */ /* first slash */ txt += len; len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); return temp; }
/* * Complete the word at or before point, * 'what_to_do' says what to do with the completion. * \t means do standard completion. * `?' means list the possible completions. * `*' means insert all of the possible completions. * `!' means to do standard completion, and list all possible completions if * there is more than one. * * Note: '*' support is not implemented * '!' could never be invoked */ int fn_complete(EditLine *el, char *(*complet_func)(const char *, int), char **(*attempted_completion_function)(const char *, int, int), const Char *word_break, const Char *special_prefixes, const char *(*app_func)(const char *), size_t query_items, int *completion_type, int *over, int *point, int *end) { const TYPE(LineInfo) *li; Char *temp; char **matches; const Char *ctemp; size_t len; int what_to_do = '\t'; int retval = CC_NORM; if (el->el_state.lastcmd == el->el_state.thiscmd) what_to_do = '?'; /* readline's rl_complete() has to be told what we did... */ if (completion_type != NULL) *completion_type = what_to_do; if (!complet_func) complet_func = fn_filename_completion_function; if (!app_func) app_func = append_char_function; /* We now look backwards for the start of a filename/variable word */ li = FUN(el,line)(el); ctemp = li->cursor; while (ctemp > li->buffer && !Strchr(word_break, ctemp[-1]) && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) ctemp--; len = (size_t)(li->cursor - ctemp); temp = el_malloc((len + 1) * sizeof(*temp)); (void)Strncpy(temp, ctemp, len); temp[len] = '\0'; /* these can be used by function called in completion_matches() */ /* or (*attempted_completion_function)() */ if (point != NULL) *point = (int)(li->cursor - li->buffer); if (end != NULL) *end = (int)(li->lastchar - li->buffer); if (attempted_completion_function) { int cur_off = (int)(li->cursor - li->buffer); matches = (*attempted_completion_function)( ct_encode_string(temp, &el->el_scratch), cur_off - (int)len, cur_off); } else matches = NULL; if (!attempted_completion_function || (over != NULL && !*over && !matches)) matches = completion_matches( ct_encode_string(temp, &el->el_scratch), complet_func); if (over != NULL) *over = 0; if (matches) { int i; size_t matches_num, maxlen, match_len, match_display=1; retval = CC_REFRESH; /* * Only replace the completed string with common part of * possible matches if there is possible completion. */ if (matches[0][0] != '\0') { el_deletestr(el, (int) len); FUN(el,insertstr)(el, ct_decode_string(matches[0], &el->el_scratch)); } if (what_to_do == '?') goto display_matches; if (matches[2] == NULL && (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) { /* * We found exact match. Add a space after * it, unless we do filename completion and the * object is a directory. */ FUN(el,insertstr)(el, ct_decode_string((*app_func)(matches[0]), &el->el_scratch)); } else if (what_to_do == '!') { display_matches: /* * More than one match and requested to list possible * matches. */ for(i = 1, maxlen = 0; matches[i]; i++) { match_len = strlen(matches[i]); if (match_len > maxlen) maxlen = match_len; } /* matches[1] through matches[i-1] are available */ matches_num = (size_t)(i - 1); /* newline to get on next line from command line */ (void)fprintf(el->el_outfile, "\n"); /* * If there are too many items, ask user for display * confirmation. */ if (matches_num > query_items) { (void)fprintf(el->el_outfile, "Display all %zu possibilities? (y or n) ", matches_num); (void)fflush(el->el_outfile); if (getc(stdin) != 'y') match_display = 0; (void)fprintf(el->el_outfile, "\n"); } if (match_display) { /* * Interface of this function requires the * strings be matches[1..num-1] for compat. * We have matches_num strings not counting * the prefix in matches[0], so we need to * add 1 to matches_num for the call. */ fn_display_match_list(el, matches, matches_num+1, maxlen); } retval = CC_REDISPLAY; } else if (matches[0][0]) { /* * There was some common match, but the name was * not complete enough. Next tab will print possible * completions. */ el_beep(el); } else { /* lcd is not a valid object - further specification */ /* is needed */ el_beep(el); retval = CC_NORM; } /* free elements of array and the array itself */ for (i = 0; matches[i]; i++) el_free(matches[i]); el_free(matches); matches = NULL; } el_free(temp); return retval; }
/* * return first found file name starting by the ``text'' or NULL if no * such file can be found * value of ``state'' is ignored * * it's caller's responsibility to free returned string */ char * fn_filename_completion_function(const char *text, int state) { static DIR *dir = NULL; static char *filename = NULL, *dirname = NULL, *dirpath = NULL; static size_t filename_len = 0; struct dirent *entry; char *temp; size_t len; if (state == 0 || dir == NULL) { temp = strrchr(text, '/'); if (temp) { char *nptr; temp++; nptr = el_realloc(filename, (strlen(temp) + 1) * sizeof(*nptr)); if (nptr == NULL) { el_free(filename); filename = NULL; return NULL; } filename = nptr; (void)strcpy(filename, temp); len = (size_t)(temp - text); /* including last slash */ nptr = el_realloc(dirname, (len + 1) * sizeof(*nptr)); if (nptr == NULL) { el_free(dirname); dirname = NULL; return NULL; } dirname = nptr; (void)strncpy(dirname, text, len); dirname[len] = '\0'; } else { el_free(filename); if (*text == 0) filename = NULL; else { filename = strdup(text); if (filename == NULL) return NULL; } el_free(dirname); dirname = NULL; } if (dir != NULL) { (void)closedir(dir); dir = NULL; } /* support for ``~user'' syntax */ el_free(dirpath); dirpath = NULL; if (dirname == NULL) { if ((dirname = strdup("")) == NULL) return NULL; dirpath = strdup("./"); } else if (*dirname == '~') dirpath = fn_tilde_expand(dirname); else dirpath = strdup(dirname); if (dirpath == NULL) return NULL; dir = opendir(dirpath); if (!dir) return NULL; /* cannot open the directory */ /* will be used in cycle */ filename_len = filename ? strlen(filename) : 0; } /* find the match */ while ((entry = readdir(dir)) != NULL) { /* skip . and .. */ if (entry->d_name[0] == '.' && (!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2]))) continue; if (filename_len == 0) break; /* otherwise, get first entry where first */ /* filename_len characters are equal */ if (entry->d_name[0] == filename[0] /* Some dirents have d_namlen, but it is not portable. */ && strlen(entry->d_name) >= filename_len && strncmp(entry->d_name, filename, filename_len) == 0) break; } if (entry) { /* match found */ /* Some dirents have d_namlen, but it is not portable. */ len = strlen(entry->d_name); len = strlen(dirname) + len + 1; temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); } else { (void)closedir(dir); dir = NULL; temp = NULL; } return temp; }
/* vi_histedit(): * Vi edit history line with vi * [v] */ libedit_private el_action_t /*ARGSUSED*/ vi_histedit(EditLine *el, wint_t c __attribute__((__unused__))) { int fd; pid_t pid; ssize_t st; int status; char tempfile[] = "/tmp/histedit.XXXXXXXXXX"; char *cp = NULL; size_t len; wchar_t *line = NULL; if (el->el_state.doingarg) { if (vi_to_history_line(el, 0) == CC_ERROR) return CC_ERROR; } fd = mkstemp(tempfile); if (fd < 0) return CC_ERROR; len = (size_t)(el->el_line.lastchar - el->el_line.buffer); #define TMP_BUFSIZ (EL_BUFSIZ * MB_LEN_MAX) cp = el_malloc(TMP_BUFSIZ * sizeof(*cp)); if (cp == NULL) goto error; line = el_malloc(len * sizeof(*line) + 1); if (line == NULL) goto error; wcsncpy(line, el->el_line.buffer, len); line[len] = '\0'; wcstombs(cp, line, TMP_BUFSIZ - 1); cp[TMP_BUFSIZ - 1] = '\0'; len = strlen(cp); write(fd, cp, len); write(fd, "\n", (size_t)1); pid = fork(); switch (pid) { case -1: goto error; case 0: close(fd); execlp("vi", "vi", tempfile, (char *)NULL); exit(0); /*NOTREACHED*/ default: while (waitpid(pid, &status, 0) != pid) continue; lseek(fd, (off_t)0, SEEK_SET); st = read(fd, cp, TMP_BUFSIZ - 1); if (st > 0) { cp[st] = '\0'; len = (size_t)(el->el_line.limit - el->el_line.buffer); len = mbstowcs(el->el_line.buffer, cp, len); if (len > 0 && el->el_line.buffer[len - 1] == '\n') --len; } else len = 0; el->el_line.cursor = el->el_line.buffer; el->el_line.lastchar = el->el_line.buffer + len; el_free(cp); el_free(line); break; } close(fd); unlink(tempfile); /* return CC_REFRESH; */ return ed_newline(el, 0); error: el_free(line); el_free(cp); close(fd); unlink(tempfile); return CC_ERROR; }
STATIC void ecom(elem **pe) { int i,op,hcstopsave; unsigned hash; elem *e,*ehash; tym_t tym; e = *pe; assert(e); elem_debug(e); #ifdef DEBUG assert(e->Ecount == 0); //assert(e->Ecomsub == 0); #endif tym = tybasic(e->Ety); op = e->Eoper; switch (op) { case OPconst: case OPvar: case OPrelconst: break; case OPstreq: case OPpostinc: case OPpostdec: case OPeq: case OPaddass: case OPminass: case OPmulass: case OPdivass: case OPmodass: case OPshrass: case OPashrass: case OPshlass: case OPandass: case OPxorass: case OPorass: #if TX86 /* Reverse order of evaluation for double op=. This is so that */ /* the pushing of the address of the second operand is easier. */ /* However, with the 8087 we don't need the kludge. */ if (op != OPeq && tym == TYdouble && !config.inline8087) { if (EOP(e->E1)) ecom(&e->E1->E1); ecom(&e->E2); } else #endif { /* Don't mark the increment of an i++ or i-- as a CSE, if it */ /* can be done with an INC or DEC instruction. */ if (!(OTpost(op) && elemisone(e->E2))) ecom(&e->E2); /* evaluate 2nd operand first */ case OPnegass: if (EOP(e->E1)) /* if lvalue is an operator */ { #ifdef DEBUG if (e->E1->Eoper != OPind) elem_print(e); #endif assert(e->E1->Eoper == OPind); ecom(&(e->E1->E1)); } } touchlvalue(e->E1); if (!OTpost(op)) /* lvalue of i++ or i-- is not a cse*/ { hash = cs_comphash(e->E1); vec_setbit(hash % CSVECDIM,csvec); addhcstab(e->E1,hash); // add lvalue to hcstab[] } return; case OPbtc: case OPbts: case OPbtr: ecom(&e->E1); ecom(&e->E2); touchfunc(0); // indirect assignment return; case OPandand: case OPoror: ecom(&e->E1); hcstopsave = hcstop; ecom(&e->E2); hcstop = hcstopsave; /* no common subs by E2 */ return; /* if comsub then logexp() will */ /* break */ case OPcond: ecom(&e->E1); hcstopsave = hcstop; ecom(&e->E2->E1); /* left condition */ hcstop = hcstopsave; /* no common subs by E2 */ ecom(&e->E2->E2); /* right condition */ hcstop = hcstopsave; /* no common subs by E2 */ return; /* can't be a common sub */ case OPcall: case OPcallns: ecom(&e->E2); /* eval right first */ /* FALL-THROUGH */ case OPucall: case OPucallns: ecom(&e->E1); touchfunc(1); return; case OPstrpar: /* so we don't break logexp() */ #if TX86 case OPinp: /* never CSE the I/O instruction itself */ #endif case OPdctor: ecom(&e->E1); /* FALL-THROUGH */ case OPasm: case OPstrthis: // don't CSE these case OPframeptr: case OPgot: case OPctor: case OPdtor: case OPmark: return; case OPddtor: return; case OPparam: #if TX86 case OPoutp: #endif ecom(&e->E1); case OPinfo: ecom(&e->E2); return; case OPcomma: case OPremquo: ecom(&e->E1); ecom(&e->E2); break; #if TARGET_SEGMENTED case OPvp_fp: case OPcvp_fp: ecom(&e->E1); touchaccess(e); break; #endif case OPind: ecom(&e->E1); /* Generally, CSEing a *(double *) results in worse code */ if (tyfloating(tym)) return; break; #if TX86 case OPstrcpy: case OPstrcat: case OPmemcpy: case OPmemset: ecom(&e->E2); case OPsetjmp: ecom(&e->E1); touchfunc(0); return; #endif default: /* other operators */ #if TX86 #ifdef DEBUG if (!EBIN(e)) WROP(e->Eoper); #endif assert(EBIN(e)); case OPadd: case OPmin: case OPmul: case OPdiv: case OPor: case OPxor: case OPand: case OPeqeq: case OPne: case OPscale: case OPyl2x: case OPyl2xp1: ecom(&e->E1); ecom(&e->E2); break; #else #ifdef DEBUG if (!EOP(e)) WROP(e->Eoper); #endif assert(EOP(e)); ecom(&e->E1); if (EBIN(e)) ecom(&e->E2); /* eval left first */ break; #endif case OPstring: case OPaddr: case OPbit: #ifdef DEBUG WROP(e->Eoper); elem_print(e); #endif assert(0); /* optelem() should have removed these */ /* NOTREACHED */ // Explicitly list all the unary ops for speed case OPnot: case OPcom: case OPneg: case OPuadd: case OPabs: case OPsqrt: case OPrndtol: case OPsin: case OPcos: case OPrint: case OPpreinc: case OPpredec: case OPbool: case OPstrlen: case OPs16_32: case OPu16_32: case OPd_s32: case OPd_u32: case OPs32_d: case OPu32_d: case OPd_s16: case OPs16_d: case OP32_16: case OPd_f: case OPf_d: case OPd_ld: case OPld_d: case OPc_r: case OPc_i: case OPu8_16: case OPs8_16: case OP16_8: case OPu32_64: case OPs32_64: case OP64_32: case OPmsw: case OPu64_128: case OPs64_128: case OP128_64: case OPd_s64: case OPs64_d: case OPd_u64: case OPu64_d: case OPstrctor: case OPu16_d: case OPd_u16: case OParrow: case OPvoid: case OPnullcheck: case OPbsf: case OPbsr: case OPbswap: case OPld_u64: #if TARGET_SEGMENTED case OPoffset: case OPnp_fp: case OPnp_f16p: case OPf16p_np: #endif ecom(&e->E1); break; case OPhalt: return; } /* don't CSE structures or unions or volatile stuff */ if (tym == TYstruct || tym == TYvoid || e->Ety & mTYvolatile #if TX86 // don't CSE doubles if inline 8087 code (code generator can't handle it) || (tyfloating(tym) && config.inline8087) #endif ) return; hash = cs_comphash(e); /* must be AFTER leaves are done */ /* Search for a match in hcstab[]. * Search backwards, as most likely matches will be towards the end * of the list. */ #ifdef DEBUG if (debugx) dbg_printf("elem: %p hash: %6d\n",e,hash); #endif int csveci = hash % CSVECDIM; if (vec_testbit(csveci,csvec)) { for (i = hcstop; i--;) { #ifdef DEBUG if (debugx) dbg_printf("i: %2d Hhash: %6d Helem: %p\n", i,hcstab[i].Hhash,hcstab[i].Helem); #endif if (hash == hcstab[i].Hhash && (ehash = hcstab[i].Helem) != NULL) { /* if elems are the same and we still have room for more */ if (el_match(e,ehash) && ehash->Ecount < 0xFF) { /* Make sure leaves are also common subexpressions * to avoid false matches. */ if (!OTleaf(op)) { if (!e->E1->Ecount) continue; if (OTbinary(op) && !e->E2->Ecount) continue; } ehash->Ecount++; *pe = ehash; #ifdef DEBUG if (debugx) dbg_printf("**MATCH** %p with %p\n",e,*pe); #endif el_free(e); return; } } } } else vec_setbit(csveci,csvec); addhcstab(e,hash); // add this elem to hcstab[] }
void FuncDeclaration::toObjFile(int multiobj) { Symbol *s; func_t *f; Symbol *senter; Symbol *sexit; FuncDeclaration *func = this; ClassDeclaration *cd = func->parent->isClassDeclaration(); int reverse; int i; int has_arguments; //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars()); #if 0 //printf("line = %d\n",func->getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (func->getWhere() / LINEINC) || ee->EElinnum > (func->endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = func->toSymbol(); } #endif if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) { obj_append(this); return; } if (semanticRun >= 5) // if toObjFile() already run return; semanticRun = 5; if (!func->fbody) { return; } if (func->isUnitTestDeclaration() && !global.params.useUnitTests) return; if (global.params.verbose) printf("function %s\n",func->toChars()); s = func->toSymbol(); f = s->Sfunc; #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (isVirtual() && (fensure || frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } if (isNested()) { // if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code if (func->isMain()) { objextdef("_main"); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS obj_ehsections(); // initialize exception handling sections #else objextdef("__acrtused_con"); #endif obj_includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc) s->Sclass = SCglobal; else if (func->isWinMain()) { objextdef("__acrtused"); obj_includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (func->isDllMain()) { objextdef("__acrtused_dll"); obj_includelib(libname); s->Sclass = SCglobal; } } cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, func); Array deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; TypeFunction *tf; enum RET retmethod; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf; tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); reverse = tyrevfunc(s->Stype->Tty); assert(func->type->ty == Tfunction); tf = (TypeFunction *)(func->type); has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1); retmethod = tf->retStyle(); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = tf->next->pointerTo()->toCtype(); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; #if DMDV1 if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref) #else if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim) #endif type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; this->shidden = shidden; } if (vthis) { assert(!vthis->csym); sthis = vthis->toSymbol(); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } Symbol **params; unsigned pi; // Estimate number of parameters, pi pi = (v_arguments != NULL); if (parameters) pi += parameters->dim; // Allow extra 2 for sthis and shidden params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *)); // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (v_arguments) { params[pi] = v_arguments->toSymbol(); pi += 1; } if (parameters) { for (i = 0; i < parameters->dim; i++) { VarDeclaration *v = (VarDeclaration *)parameters->data[i]; if (v->csym) { error("compiler error, parameter '%s', bugzilla 2962?", v->toChars()); assert(0); } params[pi + i] = v->toSymbol(); } pi += i; } if (reverse) { // Reverse params[] entries for (i = 0; i < pi/2; i++) { Symbol *sptmp; sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // First parameter goes in register if (pi) { Symbol *sp = params[0]; if ((tyf == TYjfunc || tyf == TYmfunc) && type_jparam(sp->Stype)) { sp->Sclass = SCfastpar; sp->Spreg = (tyf == TYjfunc) ? AX : CX; sp->Sfl = FLauto; //printf("'%s' is SCfastpar\n",sp->Sident); } } if (func->fbody) { block *b; Blockx bx; Statement *sbody; localgot = NULL; sbody = func->fbody; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = func; bx.module = getModule(); irs.blx = &bx; buildClosure(&irs); #if 0 if (func->isSynchronized()) { if (cd) { elem *esync; if (func->isStatic()) { // monitor is in ClassInfo esync = el_ptr(cd->toSymbol()); } else { // 'this' is the monitor esync = el_var(sthis); } if (func->isStatic() || sbody->usesEH() || !(config.flags2 & CFG2seh)) { // BUG: what if frequire or fensure uses EH? sbody = new SynchronizedStatement(func->loc, esync, sbody); } else { #if TARGET_WINDOS if (config.flags2 & CFG2seh) { /* The "jmonitor" uses an optimized exception handling frame * which is a little shorter than the more general EH frame. * It isn't strictly necessary. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif el_free(esync); } } else { error("synchronized function %s must be a member of a class", func->toChars()); } } #elif TARGET_WINDOS if (func->isSynchronized() && cd && config.flags2 & CFG2seh && !func->isStatic() && !sbody->usesEH()) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif sbody->toIR(&irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (isCtorDeclaration()) { assert(sthis); for (b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor if (isStaticConstructor()) { elem *e = el_una(OPucall, TYvoid, el_var(s)); ector = el_combine(ector, e); } // If static destructor if (isStaticDestructor()) { elem *e; #if STATICCTOR e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_FATEXIT]), el_ptr(s)); ector = el_combine(ector, e); dtorcount++; #else StaticDtorDeclaration *f = isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } e = el_una(OPucall, TYvoid, el_var(s)); edtor = el_combine(e, edtor); #endif } // If unit test if (isUnitTestDeclaration()) { elem *e = el_una(OPucall, TYvoid, el_var(s)); etest = el_combine(etest, e); } if (global.errors) return; writefunc(s); if (isExport()) obj_export(s, Poffset); for (i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (Dsymbol *)irs.deferToObj->data[i]; s->toObjFile(0); } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (ident && memcmp(ident->toChars(), "_STD", 4) == 0) obj_staticdtor(s); #endif #if DMDV2 if (irs.startaddress) { printf("Setting start address\n"); obj_startaddress(irs.startaddress); } #endif }
void FuncDeclaration::toObjFile(int multiobj) { FuncDeclaration *func = this; ClassDeclaration *cd = func->parent->isClassDeclaration(); int reverse; int has_arguments; //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars()); //if (type) printf("type = %s\n", func->type->toChars()); #if 0 //printf("line = %d\n",func->getWhere() / LINEINC); EEcontext *ee = env->getEEcontext(); if (ee->EEcompile == 2) { if (ee->EElinnum < (func->getWhere() / LINEINC) || ee->EElinnum > (func->endwhere / LINEINC) ) return; // don't compile this function ee->EEfunc = func->toSymbol(); } #endif if (semanticRun >= PASSobj) // if toObjFile() already run return; // If errors occurred compiling it, such as bugzilla 6118 if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror) return; if (!func->fbody) { return; } if (func->isUnitTestDeclaration() && !global.params.useUnitTests) return; if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration()) { obj_append(this); return; } assert(semanticRun == PASSsemantic3done); semanticRun = PASSobj; if (global.params.verbose) printf("function %s\n",func->toChars()); Symbol *s = func->toSymbol(); func_t *f = s->Sfunc; #if TARGET_WINDOS /* This is done so that the 'this' pointer on the stack is the same * distance away from the function parameters, so that an overriding * function can call the nested fdensure or fdrequire of its overridden function * and the stack offsets are the same. */ if (isVirtual() && (fensure || frequire)) f->Fflags3 |= Ffakeeh; #endif #if TARGET_OSX s->Sclass = SCcomdat; #else s->Sclass = SCglobal; #endif for (Dsymbol *p = parent; p; p = p->parent) { if (p->isTemplateInstance()) { s->Sclass = SCcomdat; break; } } /* Vector operations should be comdat's */ if (isArrayOp) s->Sclass = SCcomdat; if (isNested()) { // if (!(config.flags3 & CFG3pic)) // s->Sclass = SCstatic; f->Fflags3 |= Fnested; } else { const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; // Pull in RTL startup code if (func->isMain()) { objextdef("_main"); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS obj_ehsections(); // initialize exception handling sections #endif #if TARGET_WINDOS objextdef("__acrtused_con"); #endif obj_includelib(libname); s->Sclass = SCglobal; } else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc) { #if TARGET_WINDOS objextdef("__acrtused_con"); // bring in C startup code obj_includelib("snn.lib"); // bring in C runtime library #endif s->Sclass = SCglobal; } else if (func->isWinMain()) { objextdef("__acrtused"); obj_includelib(libname); s->Sclass = SCglobal; } // Pull in RTL startup code else if (func->isDllMain()) { objextdef("__acrtused_dll"); obj_includelib(libname); s->Sclass = SCglobal; } } cstate.CSpsymtab = &f->Flocsym; // Find module m for this function Module *m = NULL; for (Dsymbol *p = parent; p; p = p->parent) { m = p->isModule(); if (m) break; } IRState irs(m, func); Dsymbols deferToObj; // write these to OBJ file later irs.deferToObj = &deferToObj; TypeFunction *tf; enum RET retmethod; symbol *shidden = NULL; Symbol *sthis = NULL; tym_t tyf; tyf = tybasic(s->Stype->Tty); //printf("linkage = %d, tyf = x%x\n", linkage, tyf); reverse = tyrevfunc(s->Stype->Tty); assert(func->type->ty == Tfunction); tf = (TypeFunction *)(func->type); has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1); retmethod = tf->retStyle(); if (retmethod == RETstack) { // If function returns a struct, put a pointer to that // as the first argument ::type *thidden = tf->next->pointerTo()->toCtype(); char hiddenparam[5+4+1]; static int hiddenparami; // how many we've generated so far sprintf(hiddenparam,"__HID%d",++hiddenparami); shidden = symbol_name(hiddenparam,SCparameter,thidden); shidden->Sflags |= SFLtrue | SFLfree; #if DMDV1 if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref) #else if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim) #endif type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile); irs.shidden = shidden; this->shidden = shidden; } else { // Register return style cannot make nrvo. // Auto functions keep the nrvo_can flag up to here, // so we should eliminate it before entering backend. nrvo_can = 0; } if (vthis) { assert(!vthis->csym); sthis = vthis->toSymbol(); irs.sthis = sthis; if (!(f->Fflags3 & Fnested)) f->Fflags3 |= Fmember; } Symbol **params; unsigned pi; // Estimate number of parameters, pi pi = (v_arguments != NULL); if (parameters) pi += parameters->dim; // Allow extra 2 for sthis and shidden params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *)); // Get the actual number of parameters, pi, and fill in the params[] pi = 0; if (v_arguments) { params[pi] = v_arguments->toSymbol(); pi += 1; } if (parameters) { for (size_t i = 0; i < parameters->dim; i++) { VarDeclaration *v = (*parameters)[i]; if (v->csym) { error("compiler error, parameter '%s', bugzilla 2962?", v->toChars()); assert(0); } params[pi + i] = v->toSymbol(); } pi += parameters->dim; } if (reverse) { // Reverse params[] entries for (size_t i = 0; i < pi/2; i++) { Symbol *sptmp = params[i]; params[i] = params[pi - 1 - i]; params[pi - 1 - i] = sptmp; } } if (shidden) { #if 0 // shidden becomes last parameter params[pi] = shidden; #else // shidden becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = shidden; #endif pi++; } if (sthis) { #if 0 // sthis becomes last parameter params[pi] = sthis; #else // sthis becomes first parameter memmove(params + 1, params, pi * sizeof(params[0])); params[0] = sthis; #endif pi++; } if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) && linkage != LINKd && shidden && sthis) { /* swap shidden and sthis */ Symbol *sp = params[0]; params[0] = params[1]; params[1] = sp; } for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; sp->Sclass = SCparameter; sp->Sflags &= ~SFLspill; sp->Sfl = FLpara; symbol_add(sp); } // Determine register assignments if (pi) { size_t numintegerregs = 0, numfloatregs = 0; const unsigned char* argregs = getintegerparamsreglist(tyf, &numintegerregs); const unsigned char* floatregs = getfloatparamsreglist(tyf, &numfloatregs); // Order of assignment of pointer or integer parameters int r = 0; int xmmcnt = 0; for (size_t i = 0; i < pi; i++) { Symbol *sp = params[i]; tym_t ty = tybasic(sp->Stype->Tty); // BUG: doesn't work for structs if (r < numintegerregs) { if ((I64 || (i == 0 && (tyf == TYjfunc || tyf == TYmfunc))) && type_jparam(sp->Stype)) { sp->Sclass = SCfastpar; sp->Spreg = argregs[r]; sp->Sfl = FLauto; ++r; } } if (xmmcnt < numfloatregs) { if (tyxmmreg(ty)) { sp->Sclass = SCfastpar; sp->Spreg = floatregs[xmmcnt]; sp->Sfl = FLauto; ++xmmcnt; } } } } if (func->fbody) { block *b; Blockx bx; Statement *sbody; localgot = NULL; sbody = func->fbody; memset(&bx,0,sizeof(bx)); bx.startblock = block_calloc(); bx.curblock = bx.startblock; bx.funcsym = s; bx.scope_index = -1; bx.classdec = cd; bx.member = func; bx.module = getModule(); irs.blx = &bx; #if DMDV2 buildClosure(&irs); #endif #if 0 if (func->isSynchronized()) { if (cd) { elem *esync; if (func->isStatic()) { // monitor is in ClassInfo esync = el_ptr(cd->toSymbol()); } else { // 'this' is the monitor esync = el_var(sthis); } if (func->isStatic() || sbody->usesEH() || !(config.flags2 & CFG2seh)) { // BUG: what if frequire or fensure uses EH? sbody = new SynchronizedStatement(func->loc, esync, sbody); } else { #if TARGET_WINDOS if (config.flags2 & CFG2seh) { /* The "jmonitor" uses an optimized exception handling frame * which is a little shorter than the more general EH frame. * It isn't strictly necessary. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif el_free(esync); } } else { error("synchronized function %s must be a member of a class", func->toChars()); } } #elif TARGET_WINDOS if (func->isSynchronized() && cd && config.flags2 & CFG2seh && !func->isStatic() && !sbody->usesEH()) { /* The "jmonitor" hack uses an optimized exception handling frame * which is a little shorter than the more general EH frame. */ s->Sfunc->Fflags3 |= Fjmonitor; } #endif sbody->toIR(&irs); bx.curblock->BC = BCret; f->Fstartblock = bx.startblock; // einit = el_combine(einit,bx.init); if (isCtorDeclaration()) { assert(sthis); for (b = f->Fstartblock; b; b = b->Bnext) { if (b->BC == BCret) { b->BC = BCretexp; b->Belem = el_combine(b->Belem, el_var(sthis)); } } } } // If static constructor #if DMDV2 if (isSharedStaticCtorDeclaration()) // must come first because it derives from StaticCtorDeclaration { ssharedctors.push(s); } else #endif if (isStaticCtorDeclaration()) { sctors.push(s); } // If static destructor #if DMDV2 if (isSharedStaticDtorDeclaration()) // must come first because it derives from StaticDtorDeclaration { SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ esharedctorgates.push(f); } sshareddtors.shift(s); } else #endif if (isStaticDtorDeclaration()) { StaticDtorDeclaration *f = isStaticDtorDeclaration(); assert(f); if (f->vgate) { /* Increment destructor's vgate at construction time */ ectorgates.push(f); } sdtors.shift(s); } // If unit test if (isUnitTestDeclaration()) { stests.push(s); } if (global.errors) return; writefunc(s); if (isExport()) obj_export(s, Poffset); for (size_t i = 0; i < irs.deferToObj->dim; i++) { Dsymbol *s = (*irs.deferToObj)[i]; FuncDeclaration *fd = s->isFuncDeclaration(); if (fd) { FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration(); if (fdp && fdp->semanticRun < PASSobj) { /* Bugzilla 7595 * FuncDeclaration::buildClosure() relies on nested functions * being toObjFile'd after the outer function. Otherwise, the * v->offset's for the closure variables are wrong. * So, defer fd until after fdp is done. */ fdp->deferred.push(fd); continue; } } s->toObjFile(0); } for (size_t i = 0; i < deferred.dim; i++) { FuncDeclaration *fd = deferred[i]; fd->toObjFile(0); } #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS // A hack to get a pointer to this function put in the .dtors segment if (ident && memcmp(ident->toChars(), "_STD", 4) == 0) obj_staticdtor(s); #endif #if DMDV2 if (irs.startaddress) { printf("Setting start address\n"); obj_startaddress(irs.startaddress); } #endif }