📄 erl_db_util.c
字号:
buff = erts_alloc(ERTS_ALC_T_DB_TMP, sizeof(Eterm) * num_heads * 3); } matches = buff; guards = buff + num_heads; bodies = buff + (num_heads * 2); i = 0; for (l = matchexpr; is_list(l); l = CDR(list_val(l))) { t = CAR(list_val(l)); if (!is_tuple(t) || arityval((tp = tuple_val(t))[0]) != 3) { add_dmc_err(err_info, "Match program part is not a tuple of " "arity 3.", -1, 0UL, dmcError); goto done; } if (!(flags & DCOMP_TRACE) || (!is_list(tp[1]) && !is_nil(tp[1]))) { t = tp[1]; } else { n = 0; for (l2 = tp[1]; is_list(l2); l2 = CDR(list_val(l2))) { ++n; } if (l2 != NIL) { add_dmc_err(err_info, "Match expression part %T is not a " "proper list.", -1, tp[1], dmcError); goto done; } hp = HAlloc(p, n + 1); t = make_tuple(hp); *hp++ = make_arityval((Uint) n); l2 = tp[1]; while (n--) { *hp++ = CAR(list_val(l2)); l2 = CDR(list_val(l2)); } } matches[i] = t; guards[i] = tp[2]; bodies[i] = tp[3]; ++i; } mp = db_match_compile(matches, guards, bodies, num_heads, flags, err_info); if (mp != NULL) { erts_match_set_free(mp); }done: ret = db_format_dmc_err_info(p, err_info); db_free_dmc_err_info(err_info); if (buff != sbuff) { erts_free(ERTS_ALC_T_DB_TMP, buff); } return ret;} Eterm erts_match_set_run(Process *p, Binary *mpsp, Eterm *args, int num_args, Uint32 *return_flags) { Eterm ret; ret = db_prog_match(p, mpsp, (Eterm) args, num_args, return_flags);#if defined(HARDDEBUG) if (is_non_value(ret)) { erts_fprintf(stderr, "Failed\n"); } else { erts_fprintf(stderr, "Returning : %T\n", ret); }#endif return ret; /* Returns * THE_NON_VALUE if no match * am_false if {message,false} has been called, * am_true if {message,_} has not been called or * if {message,true} has been called, * Msg if {message,Msg} has been called. */}/*** API Used by other erl_db modules.*/void db_initialize_util(void){ qsort(guard_tab, sizeof(guard_tab) / sizeof(DMCGuardBif), sizeof(DMCGuardBif), (int (*)(const void *, const void *)) &cmp_guard_bif); match_pseudo_process_init(); erts_smp_atomic_init(&trace_control_word, 0);}Eterm db_getkey(int keypos, Eterm obj){ if (is_tuple(obj)) { Eterm *tptr = tuple_val(obj); if (arityval(*tptr) >= keypos) return *(tptr + keypos); } return THE_NON_VALUE;}/*** Matching compiled (executed by "Pam" :-)*//*** The actual compiling of the match expression and the guards*/Binary *db_match_compile(Eterm *matchexpr, Eterm *guards, Eterm *body, int num_progs, Uint flags, DMCErrInfo *err_info){ DMCHeap heap; DMC_STACK_TYPE(Eterm) stack; DMC_STACK_TYPE(Uint) text; DMC_STACK_TYPE(Uint) labels; DMCContext context; MatchProg *ret = NULL; Eterm t; Uint i; Uint num_iters; int structure_checked; DMCRet res; int current_try_label; Uint max_eheap_need; Binary *bp = NULL; unsigned clause_start; DMC_INIT_STACK(stack); DMC_INIT_STACK(text); DMC_INIT_STACK(labels); context.stack_need = context.stack_used = 0; context.save = context.copy = NULL; context.num_match = num_progs; context.matchexpr = matchexpr; context.guardexpr = guards; context.bodyexpr = body; context.eheap_need = 0; context.err_info = err_info; context.cflags = flags; context.labels = &labels; heap.size = DMC_DEFAULT_SIZE; heap.data = heap.def; /* ** Compile the match expression */restart: heap.used = 0; max_eheap_need = 0; for (context.current_match = 0; context.current_match < num_progs; ++context.current_match) { /* This loop is long, too long */ memset(heap.data, 0, heap.size * sizeof(*heap.data)); t = context.matchexpr[context.current_match]; context.stack_used = 0; context.eheap_need = 0; structure_checked = 0; if (context.current_match < num_progs - 1) { DMC_PUSH(text,matchTryMeElse); DMC_PUSH(text,current_try_label = DMC_STACK_NUM(*(context.labels))); DMC_PUSH(*(context.labels), 0); } else { current_try_label = -1; } clause_start = DMC_STACK_NUM(text); /* the "special" test needs it */ DMC_PUSH(stack,NIL); for (;;) { switch (t & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_BOXED: if (!BOXED_IS_TUPLE(t)) { goto simple_term; } num_iters = arityval(*tuple_val(t)); if (!structure_checked) { /* i.e. we did not pop it */ DMC_PUSH(text,matchTuple); DMC_PUSH(text,num_iters); } structure_checked = 0; for (i = 1; i <= num_iters; ++i) { if ((res = dmc_one_term(&context, &heap, &stack, &text, tuple_val(t)[i])) != retOk) { if (res == retRestart) { goto restart; /* restart the surrounding loop */ } else goto error; } } break; case TAG_PRIMARY_LIST: if (!structure_checked) { DMC_PUSH(text, matchList); } structure_checked = 0; /* Whatever it is, we did not pop it */ if ((res = dmc_one_term(&context, &heap, &stack, &text, CAR(list_val(t)))) != retOk) { if (res == retRestart) { goto restart; } else goto error; } t = CDR(list_val(t)); continue; default: /* Nil and non proper tail end's or single terms as match expressions */ simple_term: structure_checked = 0; if ((res = dmc_one_term(&context, &heap, &stack, &text, t)) != retOk) { if (res == retRestart) { goto restart; } else goto error; } break; } /* The *program's* stack just *grows* while we are traversing one composite data structure, we can check the stack usage here */ if (context.stack_used > context.stack_need) context.stack_need = context.stack_used; /* We are at the end of one composite data structure, pop sub structures and emit a matchPop instruction (or break) */ if ((t = DMC_POP(stack)) == NIL) { break; } else { DMC_PUSH(text, matchPop); structure_checked = 1; /* * Checked with matchPushT * or matchPushL */ --(context.stack_used); } } /* ** There is one single top variable in the match expression ** iff the text is tho Uint's and the single instruction ** is 'matchBind' or it is only a skip. */ context.special = (DMC_STACK_NUM(text) == 2 + clause_start && DMC_PEEK(text,clause_start) == matchBind) || (DMC_STACK_NUM(text) == 1 + clause_start && DMC_PEEK(text, clause_start) == matchSkip); if (flags & DCOMP_TRACE) { if (context.special) { if (DMC_PEEK(text, clause_start) == matchBind) { DMC_POKE(text, clause_start, matchArrayBind); } } else { ASSERT(DMC_STACK_NUM(text) >= 1); if (DMC_PEEK(text, clause_start) != matchTuple) { /* If it isn't "special" and the argument is not a tuple, the expression is not valid when matching an array*/ if (context.err_info) { add_dmc_err(context.err_info, "Match head is invalid in " "this context.", -1, 0UL, dmcError); } goto error; } DMC_POKE(text, clause_start, matchArray); } } /* ** ... and the guards */ context.is_guard = 1; if (compile_guard_expr (&context, &heap, &text, context.guardexpr[context.current_match]) != retOk) goto error; context.is_guard = 0; if ((context.cflags & DCOMP_TABLE) && !is_list(context.bodyexpr[context.current_match])) { if (context.err_info) { add_dmc_err(context.err_info, "Body clause does not return " "anything.", -1, 0UL, dmcError); } goto error; } if (compile_guard_expr (&context, &heap, &text, context.bodyexpr[context.current_match]) != retOk) goto error; /* * The compilation does not bail out when error information * is requested, so we need to detect that here... */ if (context.err_info != NULL && (context.err_info)->error_added) { goto error; } /* If the matchprogram comes here, the match is successfull */ DMC_PUSH(text,matchHalt); /* Fill in try-me-else label if there is one. */ if (current_try_label >= 0) { DMC_POKE(*(context.labels), current_try_label, DMC_STACK_NUM(text)); } /* So, how much eheap did this part of the match program need? */ if (context.eheap_need > max_eheap_need) { max_eheap_need = context.eheap_need; } } /* for (context.current_match = 0 ...) */ /* ** Done compiling ** Allocate enough space for the program, ** heap size is in 'heap_used', stack size is in 'stack_need' ** and text size is simply DMC_STACK_NUM(text). ** The "program memory" is allocated like this: ** text ----> +-------------+ ** | | ** .......... ** labels --> + + (labels are offset's from text) ** .......... ** +-------------+ ** ** The heap-eheap-stack block of a MatchProg is nowadays allocated ** when the match program is run (see db_prog_match()). ** ** heap ----> +-------------+ ** .......... ** eheap ---> + + ** .......... ** stack ---> + + ** .......... ** +-------------+ ** The stack is expected to grow towards *higher* adresses. ** A special case is when the match expression is a single binding ** (i.e '$1'), then the field single_variable is set to 1. */ bp = allocate_magic_binary ((sizeof(MatchProg) - sizeof(Uint)) + (DMC_STACK_NUM(text) * sizeof(Uint)) + (DMC_STACK_NUM(labels) * sizeof(Uint))); ret = Binary2MatchProg(bp); ret->saved_program_buf = NULL; ret->saved_program = NIL; ret->term_save = context.save; ret->num_bindings = heap.used; ret->labels = (Uint *) (ret->text + DMC_STACK_NUM(text)); ret->single_variable = context.special;#ifdef DMC_DEBUG ret->label_size = DMC_STACK_NUM(labels);#endif sys_memcpy(ret->text, DMC_STACK_DATA(text), DMC_STACK_NUM(text) * sizeof(Uint)); sys_memcpy(ret->labels, DMC_STACK_DATA(labels), DMC_STACK_NUM(labels) * sizeof(Uint)); ret->heap_size = ((heap.used * sizeof(Eterm)) + (max_eheap_need * sizeof(Eterm)) + (context.stack_need * sizeof(Eterm *)) + (3 * (FENCE_PATTERN_SIZE * sizeof(Eterm *)))); ret->eheap_offset = heap.used + FENCE_PATTERN_SIZE; ret->stack_offset = ret->eheap_offset + max_eheap_need + FENCE_PATTERN_SIZE; /* * Fall through to cleanup code, but context.save should not be free'd */ context.save = NULL;error: /* Here is were we land when compilation failed. */ while (context.save != NULL) { ErlHeapFragment *ll = context.save->next; free_message_buffer(context.save); context.save = ll; } DMC_FREE(stack); DMC_FREE(text); DMC_FREE(labels); if (context.copy != NULL) free_message_buffer(context.copy); if (heap.data != heap.def) erts_free(ERTS_ALC_T_DB_MS_CMPL_HEAP, (void *) heap.data); return bp;}/*** Free a match program (in a binary)*/void erts_match_set_free(Binary *bprog){ MatchProg *prog; ErlHeapFragment *tmp, *ll; if (bprog == NULL) return; prog = Binary2MatchProg(bprog); tmp = prog->term_save; while (tmp != NULL) { ll = tmp->next; free_message_buffer(tmp); tmp = ll; } if (prog->saved_program_buf != NULL) free_message_buffer(prog->saved_program_buf); erts_bin_free(bprog);}voiderts_match_prog_foreach_offheap(Binary *bprog, void (*func)(ErlOffHeap *, void *), void *arg){ MatchProg *prog; ErlHeapFragment *tmp; if (bprog == NULL) return; prog = Binary2MatchProg(bprog); tmp = prog->term_save; while (tmp) { (*func)(&(tmp->off_heap), arg); tmp = tmp->next; } if (prog->saved_program_buf) (*func)(&(prog->saved_program_buf->off_heap), arg);}/*** This is not the most efficient way to do it, but it's a rare** and not especially nice case when this is used.*/static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity){ Eterm *hp = HAlloc(psp, arity * 2); Eterm ret = NIL; while (--arity >= 0) { ret = CONS(hp, arr[arity], ret); hp += 2; } return ret;}/*** Execution of the match program, this is Pam.** May return THE_NON_VALUE, which is a bailout.** the para meter 'arity' is only used if 'term' is actually an array,** i.e. 'DCOMP_TRACE' was specified */Eterm db_prog_match(Process *c_p, Binary *bprog, Eterm term, int arity, Uint32 *return_flags){ MatchProg *prog = Binary2MatchProg(bprog); Eterm *ep; Eterm *tp; Eterm t; Eterm **sp; Eterm *esp; Eterm *hp; Uint *pc = prog->text; Eterm *ehp; Eterm ret; Uint n = 0; /* To avoid warning. */ int i; unsigned do_catch; ErtsMatchPseudoProcess *mpsp; Process *psp; Process *tmpp; Process *current_scheduled; ErtsSchedulerData *esdp; Eterm (*bif)(Process*, ...); int fail_label; int atomic_trace;#ifdef DMC_DEBUG unsigned long *heap_fence; unsigned long *eheap_fence; unsigned long *stack_fence; Uint save_op;#endif /* DMC_DEBUG */ mpsp = get_match_pseudo_process(c_p, prog->heap_size); psp = &mpsp->process; /* We need to lure the scheduler into believing in the pseudo process, because of floating point exceptions. Do *after* mpsp is set!!! */ esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(c_p); ASSERT(esdp != NULL); current_scheduled = esdp->current_process; esdp->current_process = psp; /* SMP: psp->scheduler_data is set by get_match_pseudo_process */ atomic_trace = 0;#define BEGIN_ATOMIC_TRACE(p) \ do { \ if (! atomic_trace) { \ erts_smp_proc_unlock((p), ERTS_PROC_LOCK_MAIN); \ erts_smp_block_system(0); \ atomic_trace = !0; \ } \ } while (0)#define END_ATOMIC_TRACE(p) \ do { \ if (atomic_trace) { \ erts_smp_release_system(); \ erts_smp_proc_lock((p), ERTS_PROC_LOCK_MAIN); \ atomic_trace = 0; \ } \ } while (0)#ifdef DMC_DEBUG save_op = 0; heap_fence = (unsigned long *) mpsp->heap + prog->eheap_offset - 1; eheap_fence = (unsigned long *) mpsp->heap + prog->stack_offset - 1; stack_fence = (unsigned long *) mpsp->heap + prog->heap_size - 1; *heap_fence = FENCE_PATTERN; *eheap_fence = FENCE_PATTERN; *stack_fence = FENCE_PATTERN;#endif /* DMC_DEBUG */#ifdef HARDDEBUG#define FAIL() {erts_printf("Fail line %d\n",__LINE__); goto fail;}#else#define FAIL() goto fail
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -