void hsh_reorganize( hshtblptr master ) { void* *newtbl = NULL; void* *oldtbl; unsigned long newsize, oldsize; unsigned long oldentries, j; unsigned int i; oldsize = master->currentsz; oldtbl = master->htbl; oldentries = 0; if (master->hstatus.hdeleted > (master->hstatus.hentries / 4)) newsize = oldsize; else { newsize = ithprime(0); for (i = 1; newsize <= oldsize; i+=1) newsize = ithprime(i); } newtbl = maketbl(newsize); master->currentsz = newsize; master->htbl = newtbl; unsigned long hi; void *ho; int_pointer_t hsh_key; for (j = 0; j < oldsize; j++) if (oldtbl[j] && (oldtbl[j] != _DELETED)) { hsh_key = _hget_key( oldtbl[j] ); hsh_lookup( master, hsh_key, hi, ho, _hget_key); tm_assert( ho == NULL ); master->htbl[ hi ] = oldtbl[j]; oldentries++; } /* Sanity check */ tm_assert( oldentries == master->hstatus.hentries - master->hstatus.hdeleted ); master->htbl_end = master->htbl + master->currentsz; master->last_found_key = 0; master->hstatus.hentries = oldentries; master->hstatus.hdeleted = 0; free(oldtbl); }
bool safe_strtoull(const char *str, uint64_t *out) { // [branch 008b] switch to safe asserts tm_assert(out != NULL); errno = 0; *out = 0; char *endptr; // [branch 009b] Switch to safe strtoull unsigned long long ull = tm_strtoull(str, &endptr, 10); if ((errno == ERANGE) || (str == endptr)) { return false; } if (xisspace(*endptr) || (*endptr == '\0' && endptr != str)) { if ((long long) ull < 0) { /* only check for negative signs in the uncommon case when * the unsigned number is so big that it's negative as a * signed number. */ // [branch 009b] Switch to safe strchr if (tm_strchr(str, '-') != NULL) { return false; } } *out = ull; return true; } return false; }
/** * mgr_on_abort comes here * * reason codes: * 0: memory conflict * 1: validation failure in hybrid hardware commit phase * 2: validation failure in hybrid software commit phase */ void mgr_on_abort( int reason ) { tm_assert(__trap_access); read_set_reset( &p_trans.read_set ); write_set_reset( &p_trans.write_set ); __hybrid_aborted = 1; // TODO: reason 1: hw validation abort, 2. sw validation abort longjmp( p_trans.jbuf, 1 ); }
jmp_buf* mgr_on_begin() { tm_assert(__trap_access); read_set_init( &p_trans.read_set ); write_set_init( &p_trans.write_set ); return &(p_trans.jbuf); }
static PREFIX_STATS *stats_prefix_find(const char *key, const size_t nkey) { PREFIX_STATS *pfs; uint32_t hashval; size_t length; bool bailout = true; // [branch 008] Switch to safe assertions tm_assert(key != NULL); for (length = 0; length < nkey && key[length] != '\0'; length++) { if (key[length] == settings.prefix_delimiter) { bailout = false; break; } } if (bailout) { return NULL; } hashval = hash(key, length, 0) % PREFIX_HASH_SIZE; for (pfs = prefix_stats[hashval]; NULL != pfs; pfs = pfs->next) { // [branch 009] Switch to tm-safe strncmp if (tm_strncmp(pfs->prefix, key, length) == 0) return pfs; } pfs = calloc(sizeof(PREFIX_STATS), 1); if (NULL == pfs) { // [branch 012] move perror to oncommit registerOnCommitHandler(spf_perror1, (void*)(uintptr_t)errno); return NULL; } pfs->prefix = malloc(length + 1); if (NULL == pfs->prefix) { // [branch 012] move perror to oncommit registerOnCommitHandler(spf_perror2, (void*)(uintptr_t)errno); free(pfs); return NULL; } // [branch 009] Switch to safe strncpy tm_strncpy(pfs->prefix, key, length); pfs->prefix[length] = '\0'; /* because strncpy() sucks */ pfs->prefix_len = length; pfs->next = prefix_stats[hashval]; prefix_stats[hashval] = pfs; num_prefixes++; total_prefix_size += length; return pfs; }
/*@null@*/ char *stats_prefix_dump(int *length) { const char *format = "PREFIX %s get %llu hit %llu set %llu del %llu\r\n"; PREFIX_STATS *pfs; char *buf; int i, pos; size_t size = 0, written = 0, total_written = 0; /* * Figure out how big the buffer needs to be. This is the sum of the * lengths of the prefixes themselves, plus the size of one copy of * the per-prefix output with 20-digit values for all the counts, * plus space for the "END" at the end. */ // [branch 002] Replaced STATS_LOCK with relaxed transaction // [branch 012] With oncommit, this becomes atomic __transaction_atomic { // [branch 009] Switched to safe strlen functions size = tm_strlen(format) + total_prefix_size + num_prefixes * (tm_strlen(format) - 2 /* %s */ + 4 * (20 - 4)) /* %llu replaced by 20-digit num */ + sizeof("END\r\n"); buf = malloc(size); if (NULL == buf) { // [branch 012] Move perror to oncommit handler registerOnCommitHandler(spd_perror1, (void*)(uintptr_t)errno); return NULL; } pos = 0; for (i = 0; i < PREFIX_HASH_SIZE; i++) { for (pfs = prefix_stats[i]; NULL != pfs; pfs = pfs->next) { // [branch 011] Marhsall pfs->prefix into a local, so we can use // a pure snprintf variant char local[4096]; tm_strncpy_to_local(local, pfs->prefix, 4096); written = tm_snprintf_s_llu_llu_llu_llu(buf + pos, size-pos, format, local, // pfs->prefix, pfs->num_gets, pfs->num_hits, pfs->num_sets, pfs->num_deletes); pos += written; total_written += written; // [branch 008] Switch to safe assertions tm_assert(total_written < size); } } } memcpy(buf + pos, "END\r\n", 6); *length = pos + 5; return buf; }
/* return 0 for i value out of range */ static unsigned long ithprime(size_t i) { tm_assert( (i < (sizeof primetbl / sizeof (int))) && primetbl[i] ); return ((1 << (FIRSTN + i)) - primetbl[i]); }
/** * API: Initialize the tm allocator. * * This should be called from main(): * * <pre> * int main(int argc, char **argv, char **envp) * { * tm_init(&argc, &argv, &envp); * ... * } * </pre> */ void tm_init(int *argcp, char ***argvp, char ***envpp) { int i; tm_assert(sizeof(tm_ptr_word) == sizeof(void *)); /*! Initialize allocation log. */ tm_alloc_log_init(); /*! Initialize colors. */ tm_colors_init(&tm.colors); #if 0 /*! Initialize allocation colors. */ tm.alloc_color = tm_ECRU; /*! Initialize phase data. */ tm_phase_data_init(&tm.p); #endif /*! Initialize time stat names. */ tm.ts_os_alloc.name = "tm_os_alloc"; tm.ts_os_free.name = "tm_os_free"; tm.ts_alloc.name = "tm_alloc"; tm.ts_free.name = "tm_free"; tm.ts_gc.name = "gc"; tm.ts_gc_inner.name = "gc_inner"; tm.ts_barrier.name = "tm_barrier"; tm.ts_barrier_pure.name = "tm_barrier_p"; tm.ts_barrier_root.name = "tm_barrier_r"; tm.ts_barrier_black.name = "tm_barrier B"; /*! Initialize tm_msg(). */ tm_msg_init(); tm_list_assert_layout(); /*! Warn if already initalized. */ if ( tm.inited ) { tm_msg("WARNING: tm_init() called more than once.\nf"); } tm.initing ++; /*! Error if argcp and argvp are not given. */ if ( ! argcp || ! argvp ) { tm_msg("WARNING: tm_init() not called from main().\n"); } /*! Default envpp = &environ, if not given. */ if ( ! envpp ) { extern char **environ; tm_msg("WARNING: tm_init(): not passed &envp.\n"); envpp = (char ***) &environ; } #if 0 #define P(X) tm_msg(" %s = %ld\n", #X, (long) X); P(sizeof(tm_list)); P(sizeof(tm_node)); P(sizeof(tm_block)); P(sizeof(tm_type)); P(sizeof(struct tm_data)); #undef P #endif /*! Initialize possible pointer range. */ tm_ptr_l = (void*) ~0UL; tm_ptr_h = 0; /*! Initialize root sets. */ tm.nroots = 0; tm.data_mutations = tm.stack_mutations = 0; tm.root_datai = -1; /*! Initialize root set for the register set, using a jmpbuf struct. */ /* A C jmpbuf struct contains the saved registers set, hopefully. */ tm_root_add("register", &tm.jb, (&tm.jb) + 1); /*! Initialize roots set for the stack. */ { void *bottom_of_stack, *top_of_stack = (void*) &i; #ifndef tm_ENVIRON_0_ALLOCATED_ON_STACK #define tm_ENVIRON_0_ALLOCATED_ON_STACK 1 #endif #if tm_ENVIRON_0_ALLOCATED_ON_STACK { extern char **environ; bottom_of_stack = (void*) environ[0]; } #else /* argvp contains a caller's auto variable. */ /* Hope that we are being called from somewhere close to the bottom of the stack. */ bottom_of_stack = (void*) argvp; #endif { void *l = top_of_stack; void *h = bottom_of_stack; /* Determine direction of stack growth. */ if ( tm_stack_growth((char*) &l, 5) < 0 ) { tm.stack_grows = -1; } else { void *t = l; l = h; h = t; tm.stack_grows = 1; } /* Attempt to nudge to page boundaries. */ { size_t stack_page_size = 4096; l = (void*) ((tm_ptr_word) (l) - ((tm_ptr_word) (l) % stack_page_size)); h = (void*) ((tm_ptr_word) (h) + (stack_page_size - ((tm_ptr_word) (h) % stack_page_size))); } i = tm_root_add("stack", l, h); } /* Remember where to put the stack pointer. */ if ( tm.stack_grows < 0 ) { tm.stack_ptrp = (void**) &tm.roots[i].l; } else { tm.stack_ptrp = (void**) &tm.roots[i].h; } tm.root_datai = i + 1; /* IMPLEMENT: Support for multithreading stacks. */ } /*! Remove anti-roots: do not scan tm's internal data structures. */ tm_root_remove("tm", &tm, &tm + 1); /*! Initialize root set for initialized and uninitialize (zeroed) data segments. */ #ifdef __win32__ { extern int _data_start__, _data_end__, _bss_start__, _bss_end__; tm_root_add("initialized data", &_data_start__, &_data_end__); tm_root_add("uninitialized data", &_bss_start__, &_bss_end__); } #define tm_roots_data_segs #endif #ifdef __linux__ { extern int __data_start, __bss_start, _end; #if 0 fprintf(stderr, "__data_start = %d\n", __data_start); fprintf(stderr, "__bss_start = %d\n", __bss_start); fprintf(stderr, "_end = %d\n", _end); #endif #if 1 tm_assert(&__data_start < &__bss_start && &__bss_start < &_end); tm_root_add("initialized data", &__data_start, &__bss_start); tm_root_add("uninitialized data", &__bss_start, &_end); #endif } #define tm_roots_data_segs #endif #ifndef tm_roots_data_segs #error must specify how to find the data segment(s) for root marking. #endif /*! IMPLEMENT: Support dynamically-loaded library data segments. */ /*! Dump the tm_root sets. */ tm_msg_enable("R", 1); tm_msg("R ROOTS {\n"); for ( i = 0; tm.roots[i].name; ++ i ) { if ( tm.roots[i].l != tm.roots[i].h ) { tm_msg("R \t [%p,%p] %s %d\n", tm.roots[i].l, tm.roots[i].h, tm.roots[i].name, i); } } tm_msg("R }\n"); tm_msg_enable("R", 0); /*! Validate tm_root sets. */ { extern int _tm_user_bss[], _tm_user_data[]; tm_assert(tm_ptr_is_in_root_set(_tm_user_bss), ": _tm_user_bss = %p", _tm_user_bss); tm_assert(tm_ptr_is_in_root_set(_tm_user_data), ": _tm_user_data = %p", _tm_user_data); _tm_set_stack_ptr(&i); tm_assert(tm_ptr_is_in_root_set(&i), ": &i = %p", &i); } /*! Initialize root marking loop. */ _tm_root_loop_init(); /*! Initialize global tm_type list. */ tm_list_init(&tm.types); tm_list_set_color(&tm.types, tm_LIVE_TYPE); #if 0 /*! Initialize tm_node color iterators. */ #define X(C) \ tm.node_color_iter[C].color = C; \ tm_node_LOOP_INIT(C) X(tm_WHITE); X(tm_ECRU); X(tm_GREY); X(tm_BLACK); #undef X #endif /*! Initialize page managment. */ memset(tm.page_in_use, 0, sizeof(tm.page_in_use)); /*! Initialize tm_block free list. */ tm_list_init(&tm.free_blocks); tm_list_set_color(&tm.free_blocks, tm_FREE_BLOCK); tm.free_blocks_n = 0; /* Types. */ /*! Initialize tm_type free list. */ for ( i = 0; i < sizeof(tm.type_reserve)/sizeof(tm.type_reserve[0]); ++ i ) { tm_type *t = &tm.type_reserve[i]; t->hash_next = (void*) tm.type_free; tm.type_free = t; } /*! Initialize size to tm_type hash table. */ for ( i = 0; i < tm_type_hash_LEN; i ++ ) { tm.type_hash[i] = 0; } /*! Initialize block sweep iterator. */ _tm_block_sweep_init(); #if 0 /*! Initialize phase: start by unmarking. */ _tm_phase_init(tm_UNMARK); #endif /*! Set up write barrier hooks. */ _tm_write_barrier = __tm_write_barrier; _tm_write_barrier_pure = __tm_write_barrier_pure; _tm_write_barrier_root = __tm_write_barrier_root; /*! Mark system as initialized. */ -- tm.initing; ++ tm.inited; tm_msg_enable("WF", 0); }
/** ** evaluate byte code. ** @param f: Frame ** @return evaluated value. */ Object tm_eval(TmFrame* f) { Object* locals = f->locals; Object* top = f->stack; Object cur_fnc = f->fnc; Object globals = get_globals(cur_fnc); // TODO use code cache to replace unsigned char* unsigned char* pc = f->pc; const char* func_name_sz = get_func_name_sz(cur_fnc); Object x, k, v; Object ret = NONE_OBJECT; int i; #if INTERP_DB printf("File \"%s\": enter function %s\n",get_func_file_sz(cur_fnc), get_func_name_sz(cur_fnc)); #endif while (1) { i = (pc[1] << 8) | pc[2]; #if INTERP_DB printf("%30s%2d: %d frame = %d, top = %d\n","", pc[0], i, tm->cur, (int) (top - f->stack)); #endif switch (pc[0]) { case OP_NUMBER: { double d = atof((char*)pc + 3); pc += i; v = tm_number(d); /* obj_append(tm->constants,v);*/ dict_set(tm->constants, v, NONE_OBJECT); break; } case OP_STRING: { v = string_alloc((char*)pc + 3, i); pc += i; /* obj_append(tm->constants,v); */ dict_set(tm->constants, v, NONE_OBJECT); break; } case OP_IMPORT: { // TODO // tm_import(globals) Object import_func = tm_get_global(globals, "_import"); arg_start(); arg_push(globals); Object modname, attr; if (i == 1) { modname = TM_POP(); arg_push(modname); // arg1 } else { attr = TM_POP(); modname = TM_POP(); arg_push(modname); arg_push(attr); } call_function(import_func); break; } case OP_CONSTANT: { TM_PUSH(GET_CONST(i)); break; } case OP_NONE: { TM_PUSH(NONE_OBJECT); break; } case OP_LOAD_LOCAL: { TM_PUSH(locals[i]); break; } case OP_STORE_LOCAL: locals[i] = TM_POP(); break; case OP_LOAD_GLOBAL: { /* tm_printf("load global %o\n", GET_CONST(i)); */ int idx = dict_get_attr(GET_DICT(globals), i); if (idx == -1) { idx = dict_get_attr(GET_DICT(tm->builtins), i); if (idx == -1) { tm_raise("NameError: name %o is not defined", GET_CONST(i)); } else { Object value = GET_DICT(tm->builtins)->nodes[idx].val; // OPTIMIZE // set the builtin to `globals()` obj_set(globals, GET_CONST(i), value); idx = dict_get_attr(GET_DICT(globals), i); pc[0] = OP_FAST_LD_GLO; code16(pc+1, idx); // OPTIMIZE END TM_PUSH(value); } } else { TM_PUSH(GET_DICT(globals)->nodes[idx].val); pc[0] = OP_FAST_LD_GLO; code16(pc+1, idx); } break; } case OP_STORE_GLOBAL: { x = TM_POP(); int idx = dict_set_attr(GET_DICT(globals), i, x); pc[0] = OP_FAST_ST_GLO; code16(pc+1, idx); break; } case OP_FAST_LD_GLO: { TM_PUSH(GET_DICT(globals)->nodes[i].val); break; } case OP_FAST_ST_GLO: { GET_DICT(globals)->nodes[i].val = TM_POP(); break; } case OP_LIST: { TM_PUSH(list_new(2)); FRAME_CHECK_GC(); break; } case OP_APPEND: v = TM_POP(); x = TM_TOP(); tm_assert(IS_LIST(x), "tm_eval: OP_APPEND require list"); list_append(GET_LIST(x), v); break; case OP_DICT_SET: v = TM_POP(); k = TM_POP(); x = TM_TOP(); tm_assert(IS_DICT(x), "tm_eval: OP_DICT_SET require dict"); obj_set(x, k, v); break; case OP_DICT: { TM_PUSH(dict_new()); FRAME_CHECK_GC(); break; } TM_OP(OP_ADD, obj_add) TM_OP(OP_SUB, obj_sub) TM_OP(OP_MUL, obj_mul) TM_OP(OP_DIV, obj_div) TM_OP(OP_MOD, obj_mod) TM_OP(OP_GET, obj_get) case OP_SLICE: { Object second = TM_POP(); Object first = TM_POP(); *top = obj_slice(*top, first, second); break; } case OP_EQEQ: { *(top-1) = tm_number(obj_equals(*(top-1), *top)); top--; break; } case OP_NOTEQ: { *(top-1) = tm_number(!obj_equals(*(top-1), *top)); top--; break; } case OP_LT: { *(top-1) = tm_number(obj_cmp(*(top-1), *top)<0); top--; break; } case OP_LTEQ: { *(top-1) = tm_number(obj_cmp(*(top-1), *top)<=0); top--; break; } case OP_GT: { *(top-1) = tm_number(obj_cmp(*(top-1), *top)>0); top--; break; } case OP_GTEQ: { *(top-1) = tm_number(obj_cmp(*(top-1), *top)>=0); top--; break; } case OP_IN: { *(top-1) = tm_number(obj_in(*(top-1), *top)); top--; break; } case OP_AND: { *(top-1) = tm_number(is_true_obj(*(top-1)) && is_true_obj(*top)); top--; break; } case OP_OR: { *(top-1) = tm_number(is_true_obj(*(top-1)) || is_true_obj(*top)); top--; break; } case OP_NOT:{ *top = tm_number(!is_true_obj(*top)); break; } case OP_SET: k = TM_POP(); x = TM_POP(); v = TM_POP(); #if INTERP_DB tm_printf("Self %o, Key %o, Val %o\n", x, k, v); #endif obj_set(x, k, v); break; case OP_POP: { top--; break; } case OP_NEG: TM_TOP() = obj_neg(TM_TOP()); break; case OP_CALL: { f->top = top; top -= i; arg_set_arguments(top + 1, i); Object func = TM_POP(); TM_PUSH(call_function(func)); // TM_PUSH(call_function(func)); tm->frame = f; FRAME_CHECK_GC(); break; } case OP_APPLY: { f->top = top; Object args = TM_POP(); tm_assert_type(args, TYPE_LIST, "tm_eval: OP_APPLY"); arg_set_arguments(LIST_NODES(args), LIST_LEN(args)); Object func = TM_POP(); x = call_function(func); TM_PUSH(x); tm->frame = f; FRAME_CHECK_GC(); break; } case OP_LOAD_PARAMS: { int parg = pc[1]; int varg = pc[2]; if (tm->arg_cnt < parg || tm->arg_cnt > parg + varg) { tm_raise("ArgError,parg=%d,varg=%d,given=%d", parg, varg, tm->arg_cnt); } for(i = 0; i < tm->arg_cnt; i++){ locals[i] = tm->arguments[i]; } break; } case OP_LOAD_PARG: { int parg = i; for (i = 0; i < parg; i++) { locals[i] = arg_take_obj(func_name_sz); } break; } case OP_LOAD_NARG: { int arg_index = i; Object list = list_new(tm->arg_cnt); while (arg_remains() > 0) { obj_append(list, arg_take_obj(func_name_sz)); } locals[arg_index] = list; break; } case OP_ITER: { *top = iter_new(*top); break; } case OP_NEXT: { Object *next = next_ptr(*top); if (next != NULL) { TM_PUSH(*next); break; } else { pc += i * 3; continue; } break; } case OP_DEF: { Object mod = GET_FUNCTION(cur_fnc)->mod; Object fnc = func_new(mod, NONE_OBJECT, NULL); pc = func_resolve(GET_FUNCTION(fnc), pc); GET_FUNCTION_NAME(fnc) = GET_CONST(i); TM_PUSH(fnc); continue; } case OP_RETURN: { ret = TM_POP(); goto end; } case OP_ROT: { int half = i / 2; int j; for (j = 0; j < half; j++) { Object temp = *(top - j); *(top-j) = *(top - i + j + 1); *(top-i+j+1) = temp; } break; } case OP_UNPACK: { x = TM_POP(); tm_assert_type(x, TYPE_LIST, "tm_eval:UNPACK"); int j; for(j = LIST_LEN(x)-1; j >= 0; j--) { TM_PUSH(LIST_GET(x, j)); } break; } case OP_DEL: { k = TM_POP(); x = TM_POP(); obj_del(x, k); break; } case OP_POP_JUMP_ON_FALSE: { if (!is_true_obj(TM_POP())) { pc += i * 3; continue; } break; } case OP_JUMP_ON_TRUE: { if (is_true_obj(TM_TOP())) { pc += i * 3; continue; } break; } case OP_JUMP_ON_FALSE: { if (!is_true_obj(TM_TOP())) { pc += i * 3; continue; } break; } case OP_UP_JUMP: pc -= i * 3; continue; case OP_JUMP: pc += i * 3; continue; case OP_EOP: case OP_EOF: { ret = NONE_OBJECT; goto end; } case OP_LOAD_EX: { top = f->last_top; TM_PUSH(tm->ex); break; } case OP_SETJUMP: { f->last_top = top; f->jmp = pc + i * 3; break; } case OP_CLR_JUMP: { f->jmp = NULL; break;} case OP_LINE: { f->lineno = i; break;} case OP_DEBUG: { #if 0 Object fdebug = tm_get_global(globals, "__debug__"); f->top = top; tm_call(0, fdebug, 1, tm_number(tm->frame - tm->frames)); break; #endif } case OP_FILE: { // module name here. break; } default: tm_raise("BAD INSTRUCTION, %d\n globals() = \n%o", pc[0], GET_FUNCTION_GLOBALS(f->fnc)); goto end; } pc += 3; } end: /* if (top != f->stack) { tm_raise("tm_eval: operand stack overflow"); }*/ pop_frame(); return ret; }