📄 erl_db_util.c
字号:
#endif#define FAIL_TERM am_EXIT /* The term to set as return when bif fails and do_catch != 0 */ *return_flags = 0U;restart: ep = &term; esp = mpsp->heap + prog->stack_offset; sp = (Eterm **) esp; hp = mpsp->heap; ehp = mpsp->heap + prog->eheap_offset; ret = am_true; do_catch = 0; fail_label = -1; for (;;) {#ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { erl_exit(1, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*eheap_fence != FENCE_PATTERN) { erl_exit(1, "Eheap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *eheap_fence); } if (*stack_fence != FENCE_PATTERN) { erl_exit(1, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); } save_op = *pc;#endif switch (*pc++) { case matchTryMeElse: n = *pc++; fail_label = prog->labels[n]; break; case matchArray: /* only when DCOMP_TRACE, is always first instruction. */ n = *pc++; if ((int) n != arity) FAIL(); ep = (Eterm *) *ep; break; case matchArrayBind: /* When the array size is unknown. */ n = *pc++; hp[n] = dpm_array_to_list(psp, (Eterm *) term, arity); break; case matchTuple: /* *ep is a tuple of arity n */ if (!is_tuple(*ep)) FAIL(); ep = tuple_val(*ep); n = *pc++; if (arityval(*ep) != n) FAIL(); ++ep; break; case matchPushT: /* *ep is a tuple of arity n, push ptr to first element */ if (!is_tuple(*ep)) FAIL(); tp = tuple_val(*ep); n = *pc++; if (arityval(*tp) != n) FAIL(); *sp++ = tp + 1; ++ep; break; case matchList: if (!is_list(*ep)) FAIL(); ep = list_val(*ep); break; case matchPushL: if (!is_list(*ep)) FAIL(); *sp++ = list_val(*ep); ++ep; break; case matchPop: ep = *(--sp); break; case matchBind: n = *pc++; hp[n] = *ep++; break; case matchCmp: n = *pc++; if (!eq(hp[n],*ep)) FAIL(); ++ep; break; case matchEqBin: t = (Eterm) *pc++; if (!eq(*ep,t)) FAIL(); ++ep; break; case matchEqFloat: if (!is_float(*ep)) FAIL(); if (memcmp(float_val(*ep) + 1, pc, sizeof(double))) FAIL(); pc += 2; ++ep; break; case matchEqRef: if (!is_ref(*ep)) FAIL(); if (!eq(*ep, make_internal_ref(pc))) FAIL(); i = thing_arityval(*pc); pc += i+1; ++ep; break; case matchEqBig: if (!is_big(*ep)) FAIL(); tp = big_val(*ep); if (*tp != *pc) FAIL(); i = BIG_ARITY(pc); while(i--) if (*++tp != *++pc) FAIL(); ++pc; ++ep; break; case matchEq: t = (Eterm) *pc++; if (t != *ep++) FAIL(); break; case matchSkip: ++ep; break; /* * Here comes guard instructions */ case matchPushC: /* Push constant */ *esp++ = *pc++; break; case matchConsA: ehp[1] = *--esp; ehp[0] = esp[-1]; esp[-1] = make_list(ehp); ehp += 2; break; case matchConsB: ehp[0] = *--esp; ehp[1] = esp[-1]; esp[-1] = make_list(ehp); ehp += 2; break; case matchMkTuple: n = *pc++; t = make_tuple(ehp); *ehp++ = make_arityval(n); while (n--) { *ehp++ = *--esp; } *esp++ = t; break; case matchCall0: bif = (Eterm (*)(Process*, ...)) *pc++; t = (*bif)(psp); if (is_non_value(t)) { if (do_catch) t = FAIL_TERM; else FAIL(); } *esp++ = t; break; case matchCall1: bif = (Eterm (*)(Process*, ...)) *pc++; t = (*bif)(psp, esp[-1]); if (is_non_value(t)) { if (do_catch) t = FAIL_TERM; else FAIL(); } esp[-1] = t; break; case matchCall2: bif = (Eterm (*)(Process*, ...)) *pc++; t = (*bif)(psp, esp[-1], esp[-2]); if (is_non_value(t)) { if (do_catch) t = FAIL_TERM; else FAIL(); } --esp; esp[-1] = t; break; case matchCall3: bif = (Eterm (*)(Process*, ...)) *pc++; t = (*bif)(psp, esp[-1], esp[-2], esp[-3]); if (is_non_value(t)) { if (do_catch) t = FAIL_TERM; else FAIL(); } esp -= 2; esp[-1] = t; break; case matchPushV: *esp++ = hp[*pc++]; break; case matchPushExpr: *esp++ = term; break; case matchPushArrayAsList: n = arity; /* Only happens when 'term' is an array */ tp = (Eterm *) term; *esp++ = make_list(ehp); while (n--) { *ehp++ = *tp++; *ehp = make_list(ehp + 1); ehp++; /* As pointed out by Mikael Pettersson the expression (*ehp++ = make_list(ehp + 1)) that I previously had written here has undefined behaviour. */ } ehp[-1] = NIL; break; case matchPushArrayAsListU: /* This instruction is NOT efficient. */ *esp++ = dpm_array_to_list(psp, (Eterm *) term, arity); break; case matchTrue: if (*--esp != am_true) FAIL(); break; case matchOr: n = *pc++; t = am_false; while (n--) { if (*--esp == am_true) { t = am_true; } else if (*esp != am_false) { esp -= n; if (do_catch) { t = FAIL_TERM; break; } else { FAIL(); } } } *esp++ = t; break; case matchAnd: n = *pc++; t = am_true; while (n--) { if (*--esp == am_false) { t = am_false; } else if (*esp != am_true) { esp -= n; if (do_catch) { t = FAIL_TERM; break; } else { FAIL(); } } } *esp++ = t; break; case matchOrElse: n = *pc++; if (*--esp == am_true) { ++esp; pc = (prog->text) + prog->labels[n]; } else if (*esp != am_false) { if (do_catch) { *esp++ = FAIL_TERM; pc = (prog->text) + prog->labels[n];; } else { FAIL(); } } break; case matchAndThen: n = *pc++; if (*--esp == am_false) { esp++; pc = (prog->text) + prog->labels[n]; } else if (*esp != am_true) { if (do_catch) { *esp++ = FAIL_TERM; pc = (prog->text) + prog->labels[n];; } else { FAIL(); } } break; case matchSelf: *esp++ = c_p->id; break; case matchWaste: --esp; break; case matchReturn: ret = *--esp; break; case matchProcessDump: { erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0); print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p); *esp++ = new_binary(psp, (byte *)dsbufp->str, (int)dsbufp->str_len); erts_destroy_tmp_dsbuf(dsbufp); break; } case matchDisplay: /* Debugging, not for production! */ erts_printf("%T\n", esp[-1]); esp[-1] = am_true; break; case matchSetReturnTrace: *return_flags |= MATCH_SET_RETURN_TRACE; *esp++ = am_true; break; case matchSetExceptionTrace: *return_flags |= MATCH_SET_EXCEPTION_TRACE; *esp++ = am_true; break; case matchIsSeqTrace: if (SEQ_TRACE_TOKEN(c_p) != NIL) *esp++ = am_true; else *esp++ = am_false; break; case matchSetSeqToken: t = erts_seq_trace(c_p, esp[-1], esp[-2], 0); if (is_non_value(t)) { esp[-2] = FAIL_TERM; } else { esp[-2] = t; } --esp; break; case matchSetSeqTokenFake: t = seq_trace_fake(c_p, esp[-1]); if (is_non_value(t)) { esp[-2] = FAIL_TERM; } else { esp[-2] = t; } --esp; break; case matchGetSeqToken: if (SEQ_TRACE_TOKEN(c_p) == NIL) *esp++ = NIL; else { *esp++ = make_tuple(ehp); ehp[0] = make_arityval(5); ehp[1] = SEQ_TRACE_TOKEN_FLAGS(c_p); ehp[2] = SEQ_TRACE_TOKEN_LABEL(c_p); ehp[3] = SEQ_TRACE_TOKEN_SERIAL(c_p); ehp[4] = SEQ_TRACE_TOKEN_SENDER(c_p); ehp[5] = SEQ_TRACE_TOKEN_LASTCNT(c_p); ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); ASSERT(is_immed(ehp[1])); ASSERT(is_immed(ehp[2])); ASSERT(is_immed(ehp[3])); ASSERT(is_immed(ehp[5])); if(!is_immed(ehp[4])) { Eterm *sender = &ehp[4]; ehp += 6; *sender = copy_struct(*sender, size_object(*sender), &ehp, &MSO(psp)); } else ehp += 6; } break; case matchEnableTrace: if ( (n = erts_trace_flag2bit(esp[-1]))) { BEGIN_ATOMIC_TRACE(c_p); set_tracee_flags(c_p, c_p->tracer_proc, 0, n); esp[-1] = am_true; } else { esp[-1] = FAIL_TERM; } break; case matchEnableTrace2: n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { BEGIN_ATOMIC_TRACE(c_p); if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) { /* Always take over the tracer of the current process */ set_tracee_flags(tmpp, c_p->tracer_proc, 0, n); esp[-1] = am_true; } } break; case matchDisableTrace: if ( (n = erts_trace_flag2bit(esp[-1]))) { BEGIN_ATOMIC_TRACE(c_p); set_tracee_flags(c_p, c_p->tracer_proc, n, 0); esp[-1] = am_true; } else { esp[-1] = FAIL_TERM; } break; case matchDisableTrace2: n = erts_trace_flag2bit((--esp)[-1]); esp[-1] = FAIL_TERM; if (n) { BEGIN_ATOMIC_TRACE(c_p); if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) { /* Always take over the tracer of the current process */ set_tracee_flags(tmpp, c_p->tracer_proc, n, 0); esp[-1] = am_true; } } break; case matchCaller: if (!(c_p->cp) || !(hp = find_function_from_pc(c_p->cp))) { *esp++ = am_undefined; } else { *esp++ = make_tuple(ehp); ehp[0] = make_arityval(3); ehp[1] = hp[0]; ehp[2] = hp[1]; ehp[3] = make_small(hp[2]); ehp += 4; } break; case matchSilent: --esp; if (*esp == am_true) { erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); c_p->trace_flags |= F_TRACE_SILENT; erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } else if (*esp == am_false) { erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); c_p->trace_flags &= ~F_TRACE_SILENT; erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } break; case matchTrace2: { /* disable enable */ Uint d_flags = 0, e_flags = 0; /* process trace flags */ Eterm tracer = c_p->tracer_proc; /* XXX Atomicity note: Not fully atomic. Default tracer * is sampled from current process but applied to * tracee and tracer later after releasing main * locks on current process, so c_p->tracer_proc * may actually have changed when tracee and tracer * gets updated. I do not think nobody will notice. * It is just the default value that is not fully atomic. * and the real argument settable from match spec * {trace,[],[{{tracer,Tracer}}]} is much, much older. */ int cputs = 0; if (! erts_trace_flags(esp[-1], &d_flags, &tracer, &cputs) || ! erts_trace_flags(esp[-2], &e_flags, &tracer, &cputs) || cputs ) { (--esp)[-1] = FAIL_TERM; break; } erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); (--esp)[-1] = set_match_trace(c_p, FAIL_TERM, tracer, d_flags, e_flags); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } break; case matchTrace3: { /* disable enable */ Uint d_flags = 0, e_flags = 0; /* process trace flags */ Eterm tracer = c_p->tracer_proc; /* XXX Atomicity note. Not fully atomic. See above. * Above it could possibly be solved, but not here. */ int cputs = 0; Eterm tracee = (--esp)[0]; if (! erts_trace_flags(esp[-1], &d_flags, &tracer, &cputs) || ! erts_trace_flags(esp[-2], &e_flags, &tracer, &cputs) || cputs || ! (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN, tracee, ERTS_PROC_LOCKS_ALL))) { (--esp)[-1] = FAIL_TERM; break; } if (tmpp == c_p) { (--esp)[-1] = set_match_trace(c_p, FAIL_TERM, tracer, d_flags, e_flags); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR); } else { erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); (--esp)[-1] = set_match_trace(tmpp, FAIL_TERM, tracer, d_flags, e_flags); erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL); erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); } } break; case matchCatch: do_catch = 1; break; case matchHalt: goto success; default: erl_exit(1, "Internal error: unexpected opcode in match program."); } }fail: *return_flags = 0U; if (fail_label >= 0) { /* We failed during a "TryMeElse", lets restart, with the next match program */ pc = (prog->text) + fail_label; cleanup_match_pseudo_process(mpsp, 1); goto restart; } ret = THE_NON_VALUE;success:#ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { erl_exit(1, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*eheap_fence != FENCE_PATTERN) { erl_exit(1, "Eheap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *eheap_fence); } if (*stack_fence != FENCE_PATTERN) { erl_exit(1, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); }#endif esdp->current_process = current_scheduled; END_ATOMIC_TRACE(c_p); return ret;#undef FAIL#undef FAIL_TERM#undef BEGIN_ATOMIC_TRACE#undef END_ATOMIC_TRACE}/* * Convert a match program to a "magic" binary to return up to erlang
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -