⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 erl_db_util.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -