const char * interpreter::get_running_call_stack() const { m_fk->rn.curcallstack.clear(); int deps = 0; for (int i = ARRAY_SIZE(m_stack_list) - 1; i >= 0; i--) { m_fk->rn.curcallstack += "#"; m_fk->rn.curcallstack += fkitoa(deps); m_fk->rn.curcallstack += " "; stack & s = ARRAY_GET(m_stack_list, i); m_fk->rn.curcallstack += s.m_fb->m_name; m_fk->rn.curcallstack += " at "; m_fk->rn.curcallstack += s.m_fb->m_filename; m_fk->rn.curcallstack += ":"; m_fk->rn.curcallstack += fkitoa(GET_CMD_LINENO((*s.m_fb), s.m_pos)); m_fk->rn.curcallstack += "\n"; for (int j = 0; j < s.m_fb->m_maxstack && j < (int)ARRAY_MAX_SIZE(s.m_stack_variant_list); j++) { m_fk->rn.curcallstack += " ["; m_fk->rn.curcallstack += fkitoa(j); m_fk->rn.curcallstack += "]\t"; m_fk->rn.curcallstack += vartostring(&ARRAY_GET(s.m_stack_variant_list, j)); m_fk->rn.curcallstack += "\n"; } deps++; } return m_fk->rn.curcallstack.c_str(); }
/* * BIF implementations */ static void pd_hash_erase(Process *p, Eterm id, Eterm *ret) { unsigned int hval; Eterm old; Eterm tmp; unsigned int range; *ret = am_undefined; if (p->dictionary == NULL) { return; } hval = pd_hash_value(p->dictionary, id); old = ARRAY_GET(p->dictionary, hval); if (is_boxed(old)) { /* Tuple */ ASSERT(is_tuple(old)); if (EQ(tuple_val(old)[1], id)) { array_put(&(p->dictionary), hval, NIL); --(p->dictionary->numElements); *ret = tuple_val(old)[2]; } } else if (is_list(old)) { /* Find cons cell for identical value */ Eterm* prev = &p->dictionary->data[hval]; for (tmp = *prev; tmp != NIL; prev = &TCDR(tmp), tmp = *prev) { if (EQ(tuple_val(TCAR(tmp))[1], id)) { *prev = TCDR(tmp); *ret = tuple_val(TCAR(tmp))[2]; --(p->dictionary->numElements); } } /* If there is only one element left in the list we must remove the list. */ old = ARRAY_GET(p->dictionary, hval); ASSERT(is_list(old)); if (is_nil(TCDR(old))) { array_put(&p->dictionary, hval, TCAR(old)); } } else if (is_not_nil(old)) { #ifdef DEBUG erts_fprintf(stderr, "Process dictionary for process %T is broken, trying to " "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, old); #endif erl_exit(1, "Damaged process dictionary found during erase/1."); } if ((range = HASH_RANGE(p->dictionary)) > INITIAL_SIZE && range / 2 > (p->dictionary->numElements)) { shrink(p, ret); } }
Eterm erts_pd_hash_get(Process *p, Eterm id) { unsigned int hval; Eterm tmp; ProcDict *pd = p->dictionary; if (pd == NULL) return am_undefined; hval = pd_hash_value(pd, id); tmp = ARRAY_GET(pd, hval); if (is_boxed(tmp)) { /* Tuple */ ASSERT(is_tuple(tmp)); if (EQ(tuple_val(tmp)[1], id)) { return tuple_val(tmp)[2]; } } else if (is_list(tmp)) { for (; tmp != NIL && !EQ(tuple_val(TCAR(tmp))[1], id); tmp = TCDR(tmp)) { ; } if (tmp != NIL) { return tuple_val(TCAR(tmp))[2]; } } else if (is_not_nil(tmp)) { #ifdef DEBUG erts_fprintf(stderr, "Process dictionary for process %T is broken, trying to " "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, tmp); #endif erl_exit(1, "Damaged process dictionary found during get/1."); } return am_undefined; }
void stringheap::clear() { ARRAY_CLEAR(m_todelete); for (const fkhashmap<const char *, stringele>::ele * p = m_shh.first(); p != 0; p = m_shh.next()) { stringele * e = p->t; if (!e->sysref) { safe_fkfree(m_fk, e->s); if (ARRAY_SIZE(m_todelete) >= ARRAY_MAX_SIZE(m_todelete)) { size_t newsize = ARRAY_MAX_SIZE(m_todelete) + 1 + ARRAY_MAX_SIZE(m_todelete) * (m_fk->cfg.array_grow_speed) / 100; ARRAY_GROW(m_todelete, newsize, const char *); } ARRAY_PUSH_BACK(m_todelete); ARRAY_BACK(m_todelete) = p->k; } } for (int i = 0; i < (int)ARRAY_SIZE(m_todelete); i++) { const char * str = ARRAY_GET(m_todelete, i); m_shh.del(str); } ARRAY_CLEAR(m_todelete); }
static Eterm pd_hash_get_keys(Process *p, Eterm value) { Eterm *hp; Eterm res = NIL; ProcDict *pd = p->dictionary; unsigned int i, num; Eterm tmp, tmp2; if (pd == NULL) { return res; } num = HASH_RANGE(pd); for (i = 0; i < num; ++i) { tmp = ARRAY_GET(pd, i); if (is_boxed(tmp)) { ASSERT(is_tuple(tmp)); if (EQ(tuple_val(tmp)[2], value)) { hp = HAlloc(p, 2); res = CONS(hp, tuple_val(tmp)[1], res); } } else if (is_list(tmp)) { while (tmp != NIL) { tmp2 = TCAR(tmp); if (EQ(tuple_val(tmp2)[2], value)) { hp = HAlloc(p, 2); res = CONS(hp, tuple_val(tmp2)[1], res); } tmp = TCDR(tmp); } } } return res; }
static Eterm pd_hash_get_all(Process *p, ProcDict *pd) { Eterm* hp; Eterm res = NIL; Eterm tmp, tmp2; unsigned int i; unsigned int num; if (pd == NULL) { return res; } num = HASH_RANGE(pd); hp = HAlloc(p, pd->numElements * 2); for (i = 0; i < num; ++i) { tmp = ARRAY_GET(pd, i); if (is_boxed(tmp)) { ASSERT(is_tuple(tmp)); res = CONS(hp, tmp, res); hp += 2; } else if (is_list(tmp)) { while (tmp != NIL) { tmp2 = TCAR(tmp); res = CONS(hp, tmp2, res); hp += 2; tmp = TCDR(tmp); } } } return res; }
/* * Called from process_info/1,2. */ Eterm erts_dictionary_copy(Process *p, ProcDict *pd) { Eterm* hp; Eterm* heap_start; Eterm res = NIL; Eterm tmp, tmp2; unsigned int i, num; if (pd == NULL) { return res; } PD_CHECK(pd); num = HASH_RANGE(pd); heap_start = hp = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, sizeof(Eterm) * pd->numElements * 2); for (i = 0; i < num; ++i) { tmp = ARRAY_GET(pd, i); if (is_boxed(tmp)) { ASSERT(is_tuple(tmp)); res = CONS(hp, tmp, res); hp += 2; } else if (is_list(tmp)) { while (tmp != NIL) { tmp2 = TCAR(tmp); res = CONS(hp, tmp2, res); hp += 2; tmp = TCDR(tmp); } } } res = copy_object(res, p); erts_free(ERTS_ALC_T_TMP, (void *) heap_start); return res; }
/* state_machine_transition takes the state of the current state_machine to the next state as dictated by the state transition matrix. It sets the current state to this new state. */ int state_machine_transition(state_machine_t machine, transition_e t){ transitioning_t transitioning = ARRAY_GET(machine->transition_matrix, machine->current_state, t); machine->current_state = transitioning->next_state; if(transitioning->action) return transitioning->action(machine->argument); return NO_TRANSITION; }
static void async_free_handles (array_cmd_async * async_handles) { command_async *cmd_async; int i; for (i = 0; i < ARRAY_N (async_handles); i++) { cmd_async = ARRAY_GET (async_handles, i); cmd_free_async (cmd_async); } }
/* * Called from break handler */ void erts_dictionary_dump(int to, void *to_arg, ProcDict *pd) { unsigned int i; #ifdef DEBUG /*PD_CHECK(pd);*/ if (pd == NULL) return; erts_print(to, to_arg, "(size = %d, used = %d, homeSize = %d, " "splitPosition = %d, numElements = %d)\n", pd->size, pd->used, pd->homeSize, pd->splitPosition, (unsigned int) pd->numElements); for (i = 0; i < HASH_RANGE(pd); ++i) { erts_print(to, to_arg, "%d: %T\n", i, ARRAY_GET(pd, i)); } #else /* !DEBUG */ int written = 0; Eterm t; erts_print(to, to_arg, "["); if (pd != NULL) { for (i = 0; i < HASH_RANGE(pd); ++i) { t = ARRAY_GET(pd, i); if (is_list(t)) { for (; t != NIL; t = TCDR(t)) { erts_print(to, to_arg, written++ ? ",%T" : "%T", TCAR(t)); } } else if (is_tuple(t)) { erts_print(to, to_arg, written++ ? ",%T" : "%T", t); } } } erts_print(to, to_arg, "]"); #endif /* DEBUG (else) */ }
void processor::run() { while (m_routine_num > 0) { for (int i = 0; i < (int)ARRAY_SIZE(m_pl.l); i++) { pool<routine>::node * n = ARRAY_GET(m_pl.l, i); if (UNLIKE(!n)) { continue; } // 注意:此函数内部可能会调用到add接口 ROUTINE_RUN(n->t, m_fk->cfg.per_frame_cmd_num); if (UNLIKE(ROUTINE_ISEND(n->t))) { POOL_PUSH(m_pl.p, n); ARRAY_GET(m_pl.l, i) = 0; m_routine_num--; } } } ARRAY_CLEAR(m_pl.l); }
void erts_deep_dictionary_dump(int to, void *to_arg, ProcDict* pd, void (*cb)(int, void *, Eterm)) { unsigned int i; Eterm t; if (pd != NULL) { for (i = 0; i < HASH_RANGE(pd); ++i) { t = ARRAY_GET(pd, i); if (is_list(t)) { for (; t != NIL; t = TCDR(t)) { (*cb)(to, to_arg, TCAR(t)); } } else if (is_tuple(t)) { (*cb)(to, to_arg, t); } } } }
static struct RequestData send_nodes(uint8_t type, Array ip4array) { assert(ip4array); assert(Array_checkType(ip4array, sizeof(uint32_t))); size_t count = Array_length(ip4array); if (count == 0) { struct RequestData result = {0, NULL}; return result; } int len = count * (ITEM_SIZE) + 5; uint8_t *buffer = malloc(len); uint8_t *ptr = buffer; AddToBuffer8(&ptr, type); AddToBuffer32(&ptr, count); for (int i = 0; i < count; i++) { AddToBuffer32NoOrder(&ptr, ARRAY_GET(ip4array, uint32_t, i)); } struct RequestData result = {len, buffer}; return result; }
static void grow(Process *p) { unsigned int i,j; unsigned int steps = p->dictionary->homeSize / 5; Eterm l1,l2; Eterm l; Eterm *hp; unsigned int pos; unsigned int homeSize; int needed = 0; ProcDict *pd; #ifdef DEBUG Eterm *hp_limit; #endif HDEBUGF(("grow: steps = %d", steps)); if (steps == 0) steps = 1; /* Dont grow over MAX_HASH */ if ((MAX_HASH - steps) <= HASH_RANGE(p->dictionary)) { return; } /* * Calculate total number of heap words needed, and garbage collect * if necessary. */ pd = p->dictionary; pos = pd->splitPosition; homeSize = pd->homeSize; for (i = 0; i < steps; ++i) { if (pos == homeSize) { homeSize *= 2; pos = 0; } l = ARRAY_GET(pd, pos); pos++; if (is_not_tuple(l)) { while (l != NIL) { needed += 2; l = TCDR(l); } } } if (HeapWordsLeft(p) < needed) { BUMP_REDS(p, erts_garbage_collect(p, needed, 0, 0)); } #ifdef DEBUG hp_limit = p->htop + needed; #endif /* * Now grow. */ for (i = 0; i < steps; ++i) { ProcDict *pd = p->dictionary; if (pd->splitPosition == pd->homeSize) { pd->homeSize *= 2; pd->splitPosition = 0; } pos = pd->splitPosition; ++pd->splitPosition; /* For the hashes */ l = ARRAY_GET(pd, pos); if (is_tuple(l)) { if (pd_hash_value(pd, tuple_val(l)[1]) != pos) { array_put(&(p->dictionary), pos + p->dictionary->homeSize, l); array_put(&(p->dictionary), pos, NIL); } } else { l2 = NIL; l1 = l; for (j = 0; l1 != NIL; l1 = TCDR(l1)) j += 2; hp = HeapOnlyAlloc(p, j); while (l != NIL) { if (pd_hash_value(pd, tuple_val(TCAR(l))[1]) == pos) l1 = CONS(hp, TCAR(l), l1); else l2 = CONS(hp, TCAR(l), l2); hp += 2; l = TCDR(l); } if (l1 != NIL && TCDR(l1) == NIL) l1 = TCAR(l1); if (l2 != NIL && TCDR(l2) == NIL) l2 = TCAR(l2); ASSERT(hp <= hp_limit); /* After array_put pd is no longer valid */ array_put(&(p->dictionary), pos, l1); array_put(&(p->dictionary), pos + p->dictionary->homeSize, l2); } } #ifdef HARDDEBUG dictionary_dump(p->dictionary,CERR); #endif }
static void shrink(Process *p, Eterm* ret) { unsigned int range = HASH_RANGE(p->dictionary); unsigned int steps = (range*3) / 10; Eterm hi, lo, tmp; unsigned int i; Eterm *hp; #ifdef DEBUG Eterm *hp_limit; #endif if (range - steps < INITIAL_SIZE) { steps = range - INITIAL_SIZE; } for (i = 0; i < steps; ++i) { ProcDict *pd = p->dictionary; if (pd->splitPosition == 0) { pd->homeSize /= 2; pd->splitPosition = pd->homeSize; } --(pd->splitPosition); hi = ARRAY_GET(pd, (pd->splitPosition + pd->homeSize)); lo = ARRAY_GET(pd, pd->splitPosition); if (hi != NIL) { if (lo == NIL) { array_put(&(p->dictionary), pd->splitPosition, hi); } else { int needed = 4; if (is_list(hi) && is_list(lo)) { needed = 2*erts_list_length(hi); } if (HeapWordsLeft(p) < needed) { BUMP_REDS(p, erts_garbage_collect(p, needed, ret, 1)); hi = pd->data[(pd->splitPosition + pd->homeSize)]; lo = pd->data[pd->splitPosition]; } #ifdef DEBUG hp_limit = p->htop + needed; #endif if (is_tuple(lo)) { if (is_tuple(hi)) { hp = HeapOnlyAlloc(p, 4); tmp = CONS(hp, hi, NIL); hp += 2; array_put(&(p->dictionary), pd->splitPosition, CONS(hp,lo,tmp)); hp += 2; ASSERT(hp <= hp_limit); } else { /* hi is a list */ hp = HeapOnlyAlloc(p, 2); array_put(&(p->dictionary), pd->splitPosition, CONS(hp, lo, hi)); hp += 2; ASSERT(hp <= hp_limit); } } else { /* lo is a list */ if (is_tuple(hi)) { hp = HeapOnlyAlloc(p, 2); array_put(&(p->dictionary), pd->splitPosition, CONS(hp, hi, lo)); hp += 2; ASSERT(hp <= hp_limit); } else { /* Two lists */ hp = HeapOnlyAlloc(p, needed); for (tmp = hi; tmp != NIL; tmp = TCDR(tmp)) { lo = CONS(hp, TCAR(tmp), lo); hp += 2; } ASSERT(hp <= hp_limit); array_put(&(p->dictionary), pd->splitPosition, lo); } } } } array_put(&(p->dictionary), (pd->splitPosition + pd->homeSize), NIL); } if (HASH_RANGE(p->dictionary) <= (p->dictionary->size / 4)) { array_shrink(&(p->dictionary), (HASH_RANGE(p->dictionary) * 3) / 2); } }
static Eterm pd_hash_put(Process *p, Eterm id, Eterm value) { unsigned int hval; Eterm *hp; Eterm tpl; Eterm old; Eterm tmp; int needed; int i = 0; #ifdef DEBUG Eterm *hp_limit; #endif if (p->dictionary == NULL) { /* Create it */ array_put(&(p->dictionary), INITIAL_SIZE - 1, NIL); p->dictionary->homeSize = INITIAL_SIZE; } hval = pd_hash_value(p->dictionary, id); old = ARRAY_GET(p->dictionary, hval); /* * Calculate the number of heap words needed and garbage * collect if necessary. (Might be a slight overestimation.) */ needed = 3; /* {Key,Value} tuple */ if (is_boxed(old)) { /* * We don't want to compare keys twice, so we'll always * reserve the space for two CONS cells. */ needed += 2+2; } else if (is_list(old)) { i = 0; for (tmp = old; tmp != NIL && !EQ(tuple_val(TCAR(tmp))[1], id); tmp = TCDR(tmp)) { ++i; } if (is_nil(tmp)) { i = -1; needed += 2; } else { needed += 2*(i+1); } } if (HeapWordsLeft(p) < needed) { Eterm root[3]; root[0] = id; root[1] = value; root[2] = old; BUMP_REDS(p, erts_garbage_collect(p, needed, root, 3)); id = root[0]; value = root[1]; old = root[2]; } #ifdef DEBUG hp_limit = p->htop + needed; #endif /* * Create the {Key,Value} tuple. */ hp = HeapOnlyAlloc(p, 3); tpl = TUPLE2(hp, id, value); /* * Update the dictionary. */ if (is_nil(old)) { array_put(&(p->dictionary), hval, tpl); ++(p->dictionary->numElements); } else if (is_boxed(old)) { ASSERT(is_tuple(old)); if (EQ(tuple_val(old)[1],id)) { array_put(&(p->dictionary), hval, tpl); return tuple_val(old)[2]; } else { hp = HeapOnlyAlloc(p, 4); tmp = CONS(hp, old, NIL); hp += 2; ++(p->dictionary->numElements); array_put(&(p->dictionary), hval, CONS(hp, tpl, tmp)); hp += 2; ASSERT(hp <= hp_limit); } } else if (is_list(old)) { if (i == -1) { /* * New key. Simply prepend the tuple to the beginning of the list. */ hp = HeapOnlyAlloc(p, 2); array_put(&(p->dictionary), hval, CONS(hp, tpl, old)); hp += 2; ASSERT(hp <= hp_limit); ++(p->dictionary->numElements); } else { /* * i = Number of CDRs to skip to reach the changed element in the list. * * Replace old value in list. To avoid pointers from the old generation * to the new, we must rebuild the list from the beginning up to and * including the changed element. */ Eterm nlist; int j; hp = HeapOnlyAlloc(p, (i+1)*2); /* Find the list element to change. */ for (j = 0, nlist = old; j < i; j++, nlist = TCDR(nlist)) { ; } ASSERT(EQ(tuple_val(TCAR(nlist))[1], id)); nlist = TCDR(nlist); /* Unchanged part of list. */ /* Rebuild list before the updated element. */ for (tmp = old; i-- > 0; tmp = TCDR(tmp)) { nlist = CONS(hp, TCAR(tmp), nlist); hp += 2; } ASSERT(EQ(tuple_val(TCAR(tmp))[1], id)); /* Put the updated element first in the new list. */ nlist = CONS(hp, tpl, nlist); hp += 2; ASSERT(hp <= hp_limit); array_put(&(p->dictionary), hval, nlist); return tuple_val(TCAR(tmp))[2]; } } else { #ifdef DEBUG erts_fprintf(stderr, "Process dictionary for process %T is broken, trying to " "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, old); #endif erl_exit(1, "Damaged process dictionary found during put/2."); } if (HASH_RANGE(p->dictionary) <= p->dictionary->numElements) { grow(p); } return am_undefined; }
// range void buildin_range(fake * fk, interpreter * inter) { BIF_CHECK_ARG_NUM(2); // pos int pos = fkpspop<int>(fk); // container bool err = false; variant * v = 0; PS_POP_AND_GET(fk->ps, v); if (v->type == variant::STRING) { if (pos >= 0 && pos < (int)v->data.str->sz) { char data[2]; data[0] = v->data.str->s[pos]; data[1] = 0; fkpspush<const char *>(fk, data); } else { fkpspush<const char *>(fk, ""); } } else if (v->type == variant::ARRAY) { if (pos >= 0 && pos < (int)ARRAY_SIZE(v->data.va->va) && ARRAY_GET(v->data.va->va, pos)) { variant * ret = 0; PS_PUSH_AND_GET(fk->ps, ret); if (ARRAY_GET(v->data.va->va, pos)) { *ret = *(ARRAY_GET(v->data.va->va, pos)); } else { *ret = NILV; } } else { fkpspush<bool>(fk, false); } } else if (v->type == variant::MAP) { if (pos >= 0 && pos < (int)v->data.vm->vm.size()) { variant * key = 0; PS_PUSH_AND_GET(fk->ps, key); variant * value = 0; PS_PUSH_AND_GET(fk->ps, value); const fkhashmap<variant, variant *>::ele * e = v->data.vm->vm.at(pos); *key = e->k; *value = *(*e->t); } else { fkpspush<bool>(fk, false); fkpspush<bool>(fk, false); } } else { fkpspush<bool>(fk, false); } }
static void read_file (struct buffer *buffer) { int fd; void *map = MAP_FAILED; struct line line_buffer; size_t line_length; const char *line_begin, *line_end, *end; char newline[8]; size_t newline_length = 0; off_t size = 0; uint32_t digest = 0; if (-1 == (fd = open (buffer->path + 7, O_RDONLY))) { if (errno != ENOENT) { set_error (_("Failed to open '%s' for reading: %s"), buffer->path, strerror (errno)); goto failed; } buffer->charset = CHARSET_UTF8; buffer->line_ending = LINE_ENDING_LF; buffer->log = log_open (buffer->undo_path, buffer, 0); if (!buffer->log) goto failed; return; } if (-1 == (size = lseek (fd, 0, SEEK_END))) { static const size_t readbuf_size = 65536; char *readbuf; const char *begin, *end; int ret; struct line encoded_buffer; readbuf = malloc (readbuf_size); ARRAY_INIT (&encoded_buffer); while (0 < (ret = read (fd, readbuf, readbuf_size))) { digest = crc32 (digest, readbuf, ret); if (!buffer->charset) { charset_detect (&buffer->charset, &buffer->line_ending, readbuf, ret); newline_length = charset_encode_line_ending (newline, buffer->charset, buffer->line_ending); } begin = readbuf; end = readbuf + ret; while (begin != end) { line_end = memmem (begin, end - begin, newline, newline_length); if (!line_end) { ARRAY_ADD_SEVERAL (&encoded_buffer, begin, end - begin); break; } ARRAY_ADD_SEVERAL (&encoded_buffer, begin, line_end - begin); begin = line_end + newline_length; line_length = charset_decode (0, buffer->charset, &ARRAY_GET (&encoded_buffer, 0), ARRAY_COUNT (&encoded_buffer)); ARRAY_INIT (&line_buffer); ARRAY_RESERVE (&line_buffer, line_length); charset_decode (&ARRAY_GET (&line_buffer, 0), buffer->charset, &ARRAY_GET (&encoded_buffer, 0), ARRAY_COUNT (&encoded_buffer)); ARRAY_COUNT (&line_buffer) = line_length; pthread_mutex_lock (&buffer->lock); ARRAY_ADD (&buffer->lines, line_buffer); pthread_mutex_unlock (&buffer->lock); ARRAY_RESET (&encoded_buffer); } } } else if (size > 0) { if (MAP_FAILED == (map = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0))) { set_error (_("Failed to mmap '%s': %s"), buffer->path, strerror (errno)); goto failed; } digest = crc32 (0, map, size); charset_detect (&buffer->charset, &buffer->line_ending, map, size); newline_length = charset_encode_line_ending (newline, buffer->charset, buffer->line_ending); end = (char *) map + size; for (line_begin = map; line_begin < end; line_begin = line_end + newline_length) { line_end = memmem (line_begin, end - line_begin, newline, newline_length); if (!line_end) line_end = end; line_length = charset_decode (0, buffer->charset, line_begin, line_end - line_begin); ARRAY_INIT (&line_buffer); ARRAY_RESERVE (&line_buffer, line_length); charset_decode (&ARRAY_GET (&line_buffer, 0), buffer->charset, line_begin, line_end - line_begin); ARRAY_COUNT (&line_buffer) = line_length; pthread_mutex_lock (&buffer->lock); ARRAY_ADD (&buffer->lines, line_buffer); pthread_mutex_unlock (&buffer->lock); /* XXX: Avoid issuing full repaints when nothing really happens onscreen */ gui_repaint (); } } else { buffer->charset = CHARSET_UTF8; buffer->line_ending = LINE_ENDING_LF; } buffer->log = log_open (buffer->undo_path, buffer, digest); failed: if (fd != -1) close (fd); if (map != MAP_FAILED) munmap (map, size); }
void interpreter::call(const variant & func, int retnum, int * retpos) { fake * fk = m_fk; paramstack * ps = getps(m_fk); const funcunion * f = m_fk->fm.get_func(func); bool & err = m_isend; USE(err); if (UNLIKE(!f)) { FKERR("fkrun no func %s fail", vartostring(&func).c_str()); m_isend = true; seterror(m_fk, efk_run_no_func_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "fkrun no func %s fail", vartostring(&func).c_str()); return; } // 常规函数 if (LIKE(f->havefb)) { const func_binary * fb = &f->fb; variant * v = 0; // 准备栈大小 int needsize = m_sp + BP_SIZE + retnum + FUNC_BINARY_MAX_STACK(*fb); if (UNLIKE(needsize > (int)ARRAY_MAX_SIZE(m_stack))) { int newsize = needsize + needsize * m_fk->cfg.array_grow_speed / 100; ARRAY_GROW(m_stack, newsize, variant); } // 老的bp int oldbp = m_bp; m_bp = m_sp; // 记录返回位置 for (int i = 0; i < retnum; i++) { v = &ARRAY_GET(m_stack, m_bp); v->type = variant::NIL; v->data.buf = retpos[i]; m_bp++; } // 记录返回值数目 v = &ARRAY_GET(m_stack, m_bp); v->type = variant::NIL; v->data.buf = retnum; m_bp++; // 记录老的ip v = &ARRAY_GET(m_stack, m_bp); v->type = variant::NIL; v->data.buf = m_ip; m_bp++; // 记录profile if (UNLIKE(m_fk->pf.isopen())) { v = &ARRAY_GET(m_stack, m_bp); v->data.buf = fkgetmstick(); } v->type = variant::NIL; m_bp++; // 记录老的fb v = &ARRAY_GET(m_stack, m_bp); v->type = variant::NIL; v->data.buf = (uint64_t)m_fb; m_bp++; // 记录老的bp v = &ARRAY_GET(m_stack, m_bp); v->type = variant::NIL; v->data.buf = oldbp; m_bp++; // 设置sp m_sp = m_bp + FUNC_BINARY_MAX_STACK(*fb); if (UNLIKE((int)ps->m_variant_list_num != FUNC_BINARY_PARAMNUM(*fb))) { FKERR("call func %s param not match", vartostring(&func).c_str()); m_isend = true; seterror(m_fk, efk_run_param_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "call func %s param not match", vartostring(&func).c_str()); return; } assert(FUNC_BINARY_PARAMNUM(*fb) <= REAL_MAX_FAKE_PARAM_NUM); assert(m_bp + FUNC_BINARY_PARAMNUM(*fb) <= (int)ARRAY_MAX_SIZE(m_stack)); // 分配入参 memcpy(&ARRAY_GET(m_stack, m_bp), ps->m_variant_list, FUNC_BINARY_PARAMNUM(*fb) * sizeof(variant)); PS_CLEAR(*ps); // 重置ret V_SET_NIL(&m_ret[0]); // 标记 FUNC_BINARY_USE(*fb)++; // 新函数 m_fb = fb; m_ip = 0; return; } // 记录profile uint32_t s = 0; if (UNLIKE(m_fk->pf.isopen())) { s = fkgetmstick(); } // 绑定函数 if (f->haveff) { BIND_FUNC_CALL(f, this); FKLOG("call C func %s", vartostring(&func).c_str()); } // 内置函数 else if (f->havebif) { BUILDIN_FUNC_CALL(f, this); FKLOG("call buildin func %s", vartostring(&func).c_str()); } else { assert(0); FKERR("fkrun no inter func %s fail", vartostring(&func).c_str()); m_isend = true; seterror(m_fk, efk_run_no_func_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "fkrun no inter func %s fail", vartostring(&func).c_str()); return; } // 返回值 // 这种情况是直接跳过脚本调用了C函数 if (UNLIKE(BP_END(m_bp))) { variant * cret; PS_POP_AND_GET(*ps, cret); m_isend = true; // 直接塞返回值 m_ret[0] = *cret; } // 否则塞到当前堆栈上 else { // 检查返回值数目对不对 if (UNLIKE((int)ps->m_variant_list_num != retnum)) { FKERR("native func %s param not match, give %d need %d", vartostring(&func).c_str(), (int)ps->m_variant_list_num, retnum); m_isend = true; seterror(m_fk, efk_run_param_error, fkgetcurfile(fk), fkgetcurline(fk), fkgetcurfunc(fk), "native func %s param not match, give %d need %d", vartostring(&func).c_str(), (int)ps->m_variant_list_num, retnum); return; } // 塞返回值 for (int i = 0; i < retnum; i++) { variant * ret; GET_VARIANT(*m_fb, m_bp, ret, retpos[i]); variant * cret; PS_GET(*ps, cret, i); *ret = *cret; } } if (UNLIKE(m_fk->pf.isopen())) { const char * name = 0; V_GET_STRING(&func, name); m_fk->pf.add_func_sample(name, fkgetmstick() - s); } return; }