mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
GH-116017: Get rid of _COLD_EXITs (GH-120960)
This commit is contained in:
parent
294e724964
commit
33903c53db
16 changed files with 246 additions and 337 deletions
|
@ -4618,7 +4618,50 @@ dummy_func(
|
|||
}
|
||||
|
||||
tier2 op(_EXIT_TRACE, (--)) {
|
||||
EXIT_TO_TRACE();
|
||||
_PyExitData *exit = ¤t_executor->exits[oparg];
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
_Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
|
||||
#if defined(Py_DEBUG) && !defined(_Py_JIT)
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||
if (lltrace >= 2) {
|
||||
printf("SIDE EXIT: [UOp ");
|
||||
_PyUOpPrint(&next_uop[-1]);
|
||||
printf(", exit %u, temp %d, target %d -> %s]\n",
|
||||
oparg, exit->temperature.as_counter,
|
||||
(int)(target - _PyCode_CODE(code)),
|
||||
_PyOpcode_OpName[target->op.code]);
|
||||
}
|
||||
#endif
|
||||
if (exit->executor == NULL) {
|
||||
_Py_BackoffCounter temperature = exit->temperature;
|
||||
if (!backoff_counter_triggers(temperature)) {
|
||||
exit->temperature = advance_backoff_counter(temperature);
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
executor = code->co_executors->executors[target->op.arg];
|
||||
Py_INCREF(executor);
|
||||
}
|
||||
else {
|
||||
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
|
||||
if (optimized <= 0) {
|
||||
exit->temperature = restart_backoff_counter(temperature);
|
||||
if (optimized < 0) {
|
||||
Py_DECREF(current_executor);
|
||||
tstate->previous_executor = Py_None;
|
||||
GOTO_UNWIND();
|
||||
}
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
}
|
||||
exit->executor = executor;
|
||||
}
|
||||
Py_INCREF(exit->executor);
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_TWO(exit->executor);
|
||||
}
|
||||
|
||||
tier2 op(_CHECK_VALIDITY, (--)) {
|
||||
|
@ -4659,47 +4702,21 @@ dummy_func(
|
|||
exe->count++;
|
||||
}
|
||||
|
||||
/* Only used for handling cold side exits, should never appear in
|
||||
* a normal trace or as part of an instruction.
|
||||
*/
|
||||
tier2 op(_COLD_EXIT, (--)) {
|
||||
_PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
|
||||
_PyExitData *exit = &previous->exits[oparg];
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
_Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
|
||||
_Py_BackoffCounter temperature = exit->temperature;
|
||||
if (!backoff_counter_triggers(temperature)) {
|
||||
exit->temperature = advance_backoff_counter(temperature);
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
executor = code->co_executors->executors[target->op.arg];
|
||||
Py_INCREF(executor);
|
||||
}
|
||||
else {
|
||||
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
|
||||
if (optimized <= 0) {
|
||||
exit->temperature = restart_backoff_counter(temperature);
|
||||
if (optimized < 0) {
|
||||
Py_DECREF(previous);
|
||||
tstate->previous_executor = Py_None;
|
||||
GOTO_UNWIND();
|
||||
}
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
}
|
||||
/* We need two references. One to store in exit->executor and
|
||||
* one to keep the executor alive when executing. */
|
||||
Py_INCREF(executor);
|
||||
exit->executor = executor;
|
||||
GOTO_TIER_TWO(executor);
|
||||
}
|
||||
|
||||
tier2 op(_DYNAMIC_EXIT, (--)) {
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
_PyExitData *exit = (_PyExitData *)¤t_executor->exits[oparg];
|
||||
_Py_CODEUNIT *target = frame->instr_ptr;
|
||||
#if defined(Py_DEBUG) && !defined(_Py_JIT)
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||
if (lltrace >= 2) {
|
||||
printf("DYNAMIC EXIT: [UOp ");
|
||||
_PyUOpPrint(&next_uop[-1]);
|
||||
printf(", exit %u, temp %d, target %d -> %s]\n",
|
||||
oparg, exit->temperature.as_counter,
|
||||
(int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))),
|
||||
_PyOpcode_OpName[target->op.code]);
|
||||
}
|
||||
#endif
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
PyCodeObject *code = (PyCodeObject *)frame->f_executable;
|
||||
|
|
|
@ -1054,13 +1054,13 @@ enter_tier_two:
|
|||
uint64_t trace_uop_execution_counter = 0;
|
||||
#endif
|
||||
|
||||
assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT);
|
||||
assert(next_uop->opcode == _START_EXECUTOR);
|
||||
tier2_dispatch:
|
||||
for (;;) {
|
||||
uopcode = next_uop->opcode;
|
||||
#ifdef Py_DEBUG
|
||||
if (lltrace >= 3) {
|
||||
if (next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT) {
|
||||
if (next_uop->opcode == _START_EXECUTOR) {
|
||||
printf("%4d uop: ", 0);
|
||||
}
|
||||
else {
|
||||
|
@ -1148,25 +1148,6 @@ goto_to_tier1:
|
|||
tstate->previous_executor = NULL;
|
||||
DISPATCH();
|
||||
|
||||
exit_to_trace:
|
||||
assert(next_uop[-1].format == UOP_FORMAT_EXIT);
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||
uint32_t exit_index = next_uop[-1].exit_index;
|
||||
assert(exit_index < current_executor->exit_count);
|
||||
_PyExitData *exit = ¤t_executor->exits[exit_index];
|
||||
#ifdef Py_DEBUG
|
||||
if (lltrace >= 2) {
|
||||
printf("SIDE EXIT: [UOp ");
|
||||
_PyUOpPrint(&next_uop[-1]);
|
||||
printf(", exit %u, temp %d, target %d -> %s]\n",
|
||||
exit_index, exit->temperature.as_counter, exit->target,
|
||||
_PyOpcode_OpName[_PyCode_CODE(_PyFrame_GetCode(frame))[exit->target].op.code]);
|
||||
}
|
||||
#endif
|
||||
Py_INCREF(exit->executor);
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_TWO(exit->executor);
|
||||
|
||||
#endif // _Py_JIT
|
||||
|
||||
#endif // _Py_TIER2
|
||||
|
|
|
@ -426,7 +426,7 @@ do { \
|
|||
do { \
|
||||
OPT_STAT_INC(traces_executed); \
|
||||
next_uop = (EXECUTOR)->trace; \
|
||||
assert(next_uop->opcode == _START_EXECUTOR || next_uop->opcode == _COLD_EXIT); \
|
||||
assert(next_uop->opcode == _START_EXECUTOR); \
|
||||
goto enter_tier_two; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
@ -446,7 +446,6 @@ do { \
|
|||
#define JUMP_TO_JUMP_TARGET() goto jump_to_jump_target
|
||||
#define JUMP_TO_ERROR() goto jump_to_error_target
|
||||
#define GOTO_UNWIND() goto error_tier_two
|
||||
#define EXIT_TO_TRACE() goto exit_to_trace
|
||||
#define EXIT_TO_TIER1() goto exit_to_tier1
|
||||
#define EXIT_TO_TIER1_DYNAMIC() goto exit_to_tier1_dynamic;
|
||||
|
||||
|
|
93
Python/executor_cases.c.h
generated
93
Python/executor_cases.c.h
generated
|
@ -4824,7 +4824,51 @@
|
|||
}
|
||||
|
||||
case _EXIT_TRACE: {
|
||||
EXIT_TO_TRACE();
|
||||
oparg = CURRENT_OPARG();
|
||||
_PyExitData *exit = ¤t_executor->exits[oparg];
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
_Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
|
||||
#if defined(Py_DEBUG) && !defined(_Py_JIT)
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||
if (lltrace >= 2) {
|
||||
printf("SIDE EXIT: [UOp ");
|
||||
_PyUOpPrint(&next_uop[-1]);
|
||||
printf(", exit %u, temp %d, target %d -> %s]\n",
|
||||
oparg, exit->temperature.as_counter,
|
||||
(int)(target - _PyCode_CODE(code)),
|
||||
_PyOpcode_OpName[target->op.code]);
|
||||
}
|
||||
#endif
|
||||
if (exit->executor == NULL) {
|
||||
_Py_BackoffCounter temperature = exit->temperature;
|
||||
if (!backoff_counter_triggers(temperature)) {
|
||||
exit->temperature = advance_backoff_counter(temperature);
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
executor = code->co_executors->executors[target->op.arg];
|
||||
Py_INCREF(executor);
|
||||
}
|
||||
else {
|
||||
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
|
||||
if (optimized <= 0) {
|
||||
exit->temperature = restart_backoff_counter(temperature);
|
||||
if (optimized < 0) {
|
||||
Py_DECREF(current_executor);
|
||||
tstate->previous_executor = Py_None;
|
||||
GOTO_UNWIND();
|
||||
}
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
}
|
||||
exit->executor = executor;
|
||||
}
|
||||
Py_INCREF(exit->executor);
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
GOTO_TIER_TWO(exit->executor);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4913,47 +4957,22 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _COLD_EXIT: {
|
||||
oparg = CURRENT_OPARG();
|
||||
_PyExecutorObject *previous = (_PyExecutorObject *)tstate->previous_executor;
|
||||
_PyExitData *exit = &previous->exits[oparg];
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
_Py_CODEUNIT *target = _PyCode_CODE(code) + exit->target;
|
||||
_Py_BackoffCounter temperature = exit->temperature;
|
||||
if (!backoff_counter_triggers(temperature)) {
|
||||
exit->temperature = advance_backoff_counter(temperature);
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
executor = code->co_executors->executors[target->op.arg];
|
||||
Py_INCREF(executor);
|
||||
}
|
||||
else {
|
||||
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor);
|
||||
if (optimized <= 0) {
|
||||
exit->temperature = restart_backoff_counter(temperature);
|
||||
if (optimized < 0) {
|
||||
Py_DECREF(previous);
|
||||
tstate->previous_executor = Py_None;
|
||||
GOTO_UNWIND();
|
||||
}
|
||||
GOTO_TIER_ONE(target);
|
||||
}
|
||||
}
|
||||
/* We need two references. One to store in exit->executor and
|
||||
* one to keep the executor alive when executing. */
|
||||
Py_INCREF(executor);
|
||||
exit->executor = executor;
|
||||
GOTO_TIER_TWO(executor);
|
||||
break;
|
||||
}
|
||||
|
||||
case _DYNAMIC_EXIT: {
|
||||
oparg = CURRENT_OPARG();
|
||||
tstate->previous_executor = (PyObject *)current_executor;
|
||||
_PyExitData *exit = (_PyExitData *)¤t_executor->exits[oparg];
|
||||
_Py_CODEUNIT *target = frame->instr_ptr;
|
||||
#if defined(Py_DEBUG) && !defined(_Py_JIT)
|
||||
OPT_HIST(trace_uop_execution_counter, trace_run_length_hist);
|
||||
if (lltrace >= 2) {
|
||||
printf("DYNAMIC EXIT: [UOp ");
|
||||
_PyUOpPrint(&next_uop[-1]);
|
||||
printf(", exit %u, temp %d, target %d -> %s]\n",
|
||||
oparg, exit->temperature.as_counter,
|
||||
(int)(target - _PyCode_CODE(_PyFrame_GetCode(frame))),
|
||||
_PyOpcode_OpName[target->op.code]);
|
||||
}
|
||||
#endif
|
||||
_PyExecutorObject *executor;
|
||||
if (target->op.code == ENTER_EXECUTOR) {
|
||||
PyCodeObject *code = (PyCodeObject *)frame->f_executable;
|
||||
|
|
|
@ -439,7 +439,7 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz
|
|||
group->emit(code, data, executor, NULL, instruction_starts);
|
||||
code += group->code_size;
|
||||
data += group->data_size;
|
||||
assert(trace[0].opcode == _START_EXECUTOR || trace[0].opcode == _COLD_EXIT);
|
||||
assert(trace[0].opcode == _START_EXECUTOR);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
const _PyUOpInstruction *instruction = &trace[i];
|
||||
group = &stencil_groups[instruction->opcode];
|
||||
|
|
|
@ -144,18 +144,6 @@ _Py_GetOptimizer(void)
|
|||
static _PyExecutorObject *
|
||||
make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFilter *dependencies);
|
||||
|
||||
static int
|
||||
init_cold_exit_executor(_PyExecutorObject *executor, int oparg);
|
||||
|
||||
/* It is impossible for the number of exits to reach 1/4 of the total length,
|
||||
* as the number of exits cannot reach 1/3 of the number of non-exits, due to
|
||||
* the presence of CHECK_VALIDITY checks and instructions to produce the values
|
||||
* being checked in exits. */
|
||||
#define COLD_EXIT_COUNT (UOP_MAX_TRACE_LENGTH/4)
|
||||
|
||||
static int cold_exits_initialized = 0;
|
||||
static _PyExecutorObject COLD_EXITS[COLD_EXIT_COUNT] = { 0 };
|
||||
|
||||
static const _PyBloomFilter EMPTY_FILTER = { 0 };
|
||||
|
||||
_PyOptimizerObject *
|
||||
|
@ -164,14 +152,6 @@ _Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject *optimizer)
|
|||
if (optimizer == NULL) {
|
||||
optimizer = &_PyOptimizer_Default;
|
||||
}
|
||||
else if (cold_exits_initialized == 0) {
|
||||
cold_exits_initialized = 1;
|
||||
for (int i = 0; i < COLD_EXIT_COUNT; i++) {
|
||||
if (init_cold_exit_executor(&COLD_EXITS[i], i)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
_PyOptimizerObject *old = interp->optimizer;
|
||||
if (old == NULL) {
|
||||
old = &_PyOptimizer_Default;
|
||||
|
@ -317,12 +297,6 @@ _PyUOpPrint(const _PyUOpInstruction *uop)
|
|||
uop->jump_target,
|
||||
(uint64_t)uop->operand);
|
||||
break;
|
||||
case UOP_FORMAT_EXIT:
|
||||
printf(" (%d, exit_index=%d, operand=%#" PRIx64,
|
||||
uop->oparg,
|
||||
uop->exit_index,
|
||||
(uint64_t)uop->operand);
|
||||
break;
|
||||
default:
|
||||
printf(" (%d, Unknown format)", uop->oparg);
|
||||
}
|
||||
|
@ -1094,7 +1068,7 @@ sanity_check(_PyExecutorObject *executor)
|
|||
}
|
||||
bool ended = false;
|
||||
uint32_t i = 0;
|
||||
CHECK(executor->trace[0].opcode == _START_EXECUTOR || executor->trace[0].opcode == _COLD_EXIT);
|
||||
CHECK(executor->trace[0].opcode == _START_EXECUTOR);
|
||||
for (; i < executor->code_size; i++) {
|
||||
const _PyUOpInstruction *inst = &executor->trace[i];
|
||||
uint16_t opcode = inst->opcode;
|
||||
|
@ -1104,22 +1078,15 @@ sanity_check(_PyExecutorObject *executor)
|
|||
case UOP_FORMAT_TARGET:
|
||||
CHECK(target_unused(opcode));
|
||||
break;
|
||||
case UOP_FORMAT_EXIT:
|
||||
CHECK(opcode == _EXIT_TRACE);
|
||||
CHECK(inst->exit_index < executor->exit_count);
|
||||
break;
|
||||
case UOP_FORMAT_JUMP:
|
||||
CHECK(inst->jump_target < executor->code_size);
|
||||
break;
|
||||
case UOP_FORMAT_UNUSED:
|
||||
CHECK(0);
|
||||
break;
|
||||
}
|
||||
if (_PyUop_Flags[opcode] & HAS_ERROR_FLAG) {
|
||||
CHECK(inst->format == UOP_FORMAT_JUMP);
|
||||
CHECK(inst->error_target < executor->code_size);
|
||||
}
|
||||
if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE || opcode == _COLD_EXIT) {
|
||||
if (opcode == _JUMP_TO_TOP || opcode == _EXIT_TRACE) {
|
||||
ended = true;
|
||||
i++;
|
||||
break;
|
||||
|
@ -1133,9 +1100,6 @@ sanity_check(_PyExecutorObject *executor)
|
|||
opcode == _DEOPT ||
|
||||
opcode == _EXIT_TRACE ||
|
||||
opcode == _ERROR_POP_N);
|
||||
if (opcode == _EXIT_TRACE) {
|
||||
CHECK(inst->format == UOP_FORMAT_EXIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1157,9 +1121,8 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
|
|||
}
|
||||
|
||||
/* Initialize exits */
|
||||
assert(exit_count < COLD_EXIT_COUNT);
|
||||
for (int i = 0; i < exit_count; i++) {
|
||||
executor->exits[i].executor = &COLD_EXITS[i];
|
||||
executor->exits[i].executor = NULL;
|
||||
executor->exits[i].temperature = initial_temperature_backoff_counter();
|
||||
}
|
||||
int next_exit = exit_count-1;
|
||||
|
@ -1173,8 +1136,7 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
|
|||
assert(opcode != _POP_JUMP_IF_FALSE && opcode != _POP_JUMP_IF_TRUE);
|
||||
if (opcode == _EXIT_TRACE) {
|
||||
executor->exits[next_exit].target = buffer[i].target;
|
||||
dest->exit_index = next_exit;
|
||||
dest->format = UOP_FORMAT_EXIT;
|
||||
dest->oparg = next_exit;
|
||||
next_exit--;
|
||||
}
|
||||
if (opcode == _DYNAMIC_EXIT) {
|
||||
|
@ -1216,36 +1178,6 @@ make_executor_from_uops(_PyUOpInstruction *buffer, int length, const _PyBloomFil
|
|||
return executor;
|
||||
}
|
||||
|
||||
static int
|
||||
init_cold_exit_executor(_PyExecutorObject *executor, int oparg)
|
||||
{
|
||||
_Py_SetImmortalUntracked((PyObject *)executor);
|
||||
Py_SET_TYPE(executor, &_PyUOpExecutor_Type);
|
||||
executor->trace = (_PyUOpInstruction *)executor->exits;
|
||||
executor->code_size = 1;
|
||||
executor->exit_count = 0;
|
||||
_PyUOpInstruction *inst = (_PyUOpInstruction *)&executor->trace[0];
|
||||
inst->opcode = _COLD_EXIT;
|
||||
inst->oparg = oparg;
|
||||
executor->vm_data.valid = true;
|
||||
executor->vm_data.linked = false;
|
||||
for (int i = 0; i < _Py_BLOOM_FILTER_WORDS; i++) {
|
||||
assert(executor->vm_data.bloom.bits[i] == 0);
|
||||
}
|
||||
#ifdef Py_DEBUG
|
||||
sanity_check(executor);
|
||||
#endif
|
||||
#ifdef _Py_JIT
|
||||
executor->jit_code = NULL;
|
||||
executor->jit_side_entry = NULL;
|
||||
executor->jit_size = 0;
|
||||
if (_PyJIT_Compile(executor, executor->trace, 1)) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef Py_STATS
|
||||
/* Returns the effective trace length.
|
||||
* Ignores NOPs and trailing exit and error handling.*/
|
||||
|
@ -1258,8 +1190,7 @@ int effective_trace_length(_PyUOpInstruction *buffer, int length)
|
|||
nop_count++;
|
||||
}
|
||||
if (opcode == _EXIT_TRACE ||
|
||||
opcode == _JUMP_TO_TOP ||
|
||||
opcode == _COLD_EXIT) {
|
||||
opcode == _JUMP_TO_TOP) {
|
||||
return i+1-nop_count;
|
||||
}
|
||||
}
|
||||
|
@ -1624,13 +1555,8 @@ executor_clear(_PyExecutorObject *executor)
|
|||
*/
|
||||
Py_INCREF(executor);
|
||||
for (uint32_t i = 0; i < executor->exit_count; i++) {
|
||||
const _PyExecutorObject *cold = &COLD_EXITS[i];
|
||||
const _PyExecutorObject *side = executor->exits[i].executor;
|
||||
executor->exits[i].temperature = initial_unreachable_backoff_counter();
|
||||
if (side != cold) {
|
||||
executor->exits[i].executor = cold;
|
||||
Py_DECREF(side);
|
||||
}
|
||||
Py_CLEAR(executor->exits[i].executor);
|
||||
}
|
||||
_Py_ExecutorDetach(executor);
|
||||
Py_DECREF(executor);
|
||||
|
|
4
Python/optimizer_cases.c.h
generated
4
Python/optimizer_cases.c.h
generated
|
@ -2180,10 +2180,6 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _COLD_EXIT: {
|
||||
break;
|
||||
}
|
||||
|
||||
case _DYNAMIC_EXIT: {
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue