1
0
mirror of https://github.com/php/php-src.git synced 2026-04-24 08:28:26 +02:00

Wrap JIT compiler with zend_try to recover in case of memory overflow

This commit is contained in:
Dmitry Stogov
2022-09-27 22:28:16 +03:00
parent d981def074
commit 2568db287d
2 changed files with 214 additions and 168 deletions
+32 -14
View File
@@ -4265,24 +4265,30 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
zend_op_array *op_array = &EX(func)->op_array;
zend_op *opline = op_array->opcodes;
zend_jit_op_array_extension *jit_extension;
bool do_bailout = 0;
zend_shared_alloc_lock();
if (ZEND_FUNC_INFO(op_array)) {
SHM_UNPROTECT();
zend_jit_unprotect();
/* restore original opcode handlers */
if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
opline++;
zend_try {
/* restore original opcode handlers */
if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
opline++;
}
}
}
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
opline->handler = jit_extension->orig_handler;
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
opline->handler = jit_extension->orig_handler;
/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, NULL);
/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, NULL);
} zend_catch {
do_bailout = 0;
} zend_end_try();
zend_jit_protect();
SHM_PROTECT();
@@ -4290,6 +4296,10 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
zend_shared_alloc_unlock();
if (do_bailout) {
zend_bailout();
}
/* JIT-ed code is going to be called by VM */
return 0;
}
@@ -4332,6 +4342,7 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
zend_op_array *op_array = &EX(func)->op_array;
zend_jit_op_array_hot_extension *jit_extension;
uint32_t i;
bool do_bailout = 0;
zend_shared_alloc_lock();
jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
@@ -4340,12 +4351,16 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
SHM_UNPROTECT();
zend_jit_unprotect();
for (i = 0; i < op_array->last; i++) {
op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
}
zend_try {
for (i = 0; i < op_array->last; i++) {
op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
}
/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, opline);
/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, opline);
} zend_catch {
do_bailout = 1;
} zend_end_try();
zend_jit_protect();
SHM_PROTECT();
@@ -4353,6 +4368,9 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
zend_shared_alloc_unlock();
if (do_bailout) {
zend_bailout();
}
/* JIT-ed code is going to be called by VM */
}
+182 -154
View File
@@ -7026,6 +7026,7 @@ static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace
uint8_t orig_trigger;
zend_jit_trace_info *t = NULL;
zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
bool do_bailout = 0;
zend_shared_alloc_lock();
@@ -7035,97 +7036,106 @@ static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace
} else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
} else {
SHM_UNPROTECT();
zend_jit_unprotect();
zend_try {
SHM_UNPROTECT();
zend_jit_unprotect();
t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
t->id = ZEND_JIT_TRACE_NUM;
t->root = ZEND_JIT_TRACE_NUM;
t->parent = 0;
t->link = 0;
t->exit_count = 0;
t->child_count = 0;
t->stack_map_size = 0;
t->flags = 0;
t->polymorphism = 0;
t->jmp_table_size = 0;
t->op_array = trace_buffer[0].op_array;
t->opline = trace_buffer[1].opline;
t->exit_info = exit_info;
t->stack_map = NULL;
t->id = ZEND_JIT_TRACE_NUM;
t->root = ZEND_JIT_TRACE_NUM;
t->parent = 0;
t->link = 0;
t->exit_count = 0;
t->child_count = 0;
t->stack_map_size = 0;
t->flags = 0;
t->polymorphism = 0;
t->jmp_table_size = 0;
t->op_array = trace_buffer[0].op_array;
t->opline = trace_buffer[1].opline;
t->exit_info = exit_info;
t->stack_map = NULL;
orig_trigger = JIT_G(trigger);
JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
orig_trigger = JIT_G(trigger);
JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
handler = zend_jit_trace(trace_buffer, 0, 0);
handler = zend_jit_trace(trace_buffer, 0, 0);
JIT_G(trigger) = orig_trigger;
JIT_G(trigger) = orig_trigger;
if (handler) {
zend_jit_trace_exit_info *shared_exit_info = NULL;
if (handler) {
zend_jit_trace_exit_info *shared_exit_info = NULL;
t->exit_info = NULL;
if (t->exit_count) {
/* reallocate exit_info into shared memory */
shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = NULL;
if (t->exit_count) {
/* reallocate exit_info into shared memory */
shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
sizeof(zend_jit_trace_exit_info) * t->exit_count);
if (!shared_exit_info) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
if (!shared_exit_info) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
}
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
memcpy(shared_exit_info, exit_info,
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = shared_exit_info;
}
memcpy(shared_exit_info, exit_info,
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = shared_exit_info;
}
if (t->stack_map_size) {
zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
if (!shared_stack_map) {
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
if (t->stack_map_size) {
zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
if (!shared_stack_map) {
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
}
memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
efree(t->stack_map);
t->stack_map = shared_stack_map;
}
t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
ZEND_JIT_EXIT_COUNTERS += t->exit_count;
((zend_op*)opline)->handler = handler;
ZEND_JIT_TRACE_NUM++;
ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_JITED;
ret = ZEND_JIT_TRACE_STOP_COMPILED;
} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
efree(t->stack_map);
t->stack_map = shared_stack_map;
}
t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
ZEND_JIT_EXIT_COUNTERS += t->exit_count;
((zend_op*)opline)->handler = handler;
ZEND_JIT_TRACE_NUM++;
ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_JITED;
ret = ZEND_JIT_TRACE_STOP_COMPILED;
} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
} else {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
}
ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
} else {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
}
exit:
} zend_catch {
do_bailout = 1;
} zend_end_try();
zend_jit_protect();
SHM_PROTECT();
}
zend_shared_alloc_unlock();
if (do_bailout) {
zend_bailout();
}
if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
&& ret == ZEND_JIT_TRACE_STOP_COMPILED
&& t->exit_count > 0) {
@@ -7612,6 +7622,7 @@ abort:
static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
{
const void *handler;
bool do_bailout = 0;
zend_shared_alloc_lock();
@@ -7619,24 +7630,31 @@ static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
SHM_UNPROTECT();
zend_jit_unprotect();
handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
zend_try {
handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
if (handler) {
zend_jit_link_side_trace(
zend_jit_traces[trace_num].code_start,
zend_jit_traces[trace_num].code_size,
zend_jit_traces[trace_num].jmp_table_size,
exit_num,
handler);
}
zend_jit_traces[trace_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_BLACKLISTED;
if (handler) {
zend_jit_link_side_trace(
zend_jit_traces[trace_num].code_start,
zend_jit_traces[trace_num].code_size,
zend_jit_traces[trace_num].jmp_table_size,
exit_num,
handler);
}
zend_jit_traces[trace_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_BLACKLISTED;
} zend_catch {
do_bailout = 1;
} zend_end_try();
zend_jit_protect();
SHM_PROTECT();
}
zend_shared_alloc_unlock();
if (do_bailout) {
zend_bailout();
}
}
static bool zend_jit_trace_exit_is_bad(uint32_t trace_num, uint32_t exit_num)
@@ -7670,6 +7688,7 @@ static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace
uint8_t orig_trigger;
zend_jit_trace_info *t;
zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
bool do_bailout = 0;
zend_shared_alloc_lock();
@@ -7684,100 +7703,109 @@ static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace
SHM_UNPROTECT();
zend_jit_unprotect();
t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
zend_try {
t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
t->id = ZEND_JIT_TRACE_NUM;
t->root = zend_jit_traces[parent_num].root;
t->parent = parent_num;
t->link = 0;
t->exit_count = 0;
t->child_count = 0;
t->stack_map_size = 0;
t->flags = 0;
t->polymorphism = polymorphism;
t->jmp_table_size = 0;
t->opline = NULL;
t->exit_info = exit_info;
t->stack_map = NULL;
t->id = ZEND_JIT_TRACE_NUM;
t->root = zend_jit_traces[parent_num].root;
t->parent = parent_num;
t->link = 0;
t->exit_count = 0;
t->child_count = 0;
t->stack_map_size = 0;
t->flags = 0;
t->polymorphism = polymorphism;
t->jmp_table_size = 0;
t->opline = NULL;
t->exit_info = exit_info;
t->stack_map = NULL;
orig_trigger = JIT_G(trigger);
JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
orig_trigger = JIT_G(trigger);
JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
JIT_G(trigger) = orig_trigger;
JIT_G(trigger) = orig_trigger;
if (handler) {
zend_jit_trace_exit_info *shared_exit_info = NULL;
if (handler) {
zend_jit_trace_exit_info *shared_exit_info = NULL;
t->exit_info = NULL;
if (t->exit_count) {
/* reallocate exit_info into shared memory */
shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = NULL;
if (t->exit_count) {
/* reallocate exit_info into shared memory */
shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
sizeof(zend_jit_trace_exit_info) * t->exit_count);
if (!shared_exit_info) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
if (!shared_exit_info) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
}
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
memcpy(shared_exit_info, exit_info,
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = shared_exit_info;
}
memcpy(shared_exit_info, exit_info,
sizeof(zend_jit_trace_exit_info) * t->exit_count);
t->exit_info = shared_exit_info;
}
if (t->stack_map_size) {
zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
if (!shared_stack_map) {
if (t->stack_map_size) {
zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
if (!shared_stack_map) {
efree(t->stack_map);
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
}
memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
efree(t->stack_map);
ret = ZEND_JIT_TRACE_STOP_NO_SHM;
goto exit;
t->stack_map = shared_stack_map;
}
zend_jit_link_side_trace(
zend_jit_traces[parent_num].code_start,
zend_jit_traces[parent_num].code_size,
zend_jit_traces[parent_num].jmp_table_size,
exit_num,
handler);
t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
ZEND_JIT_EXIT_COUNTERS += t->exit_count;
zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
ZEND_JIT_TRACE_NUM++;
zend_jit_traces[parent_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_JITED;
ret = ZEND_JIT_TRACE_STOP_COMPILED;
} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
efree(t->stack_map);
t->stack_map = shared_stack_map;
}
zend_jit_link_side_trace(
zend_jit_traces[parent_num].code_start,
zend_jit_traces[parent_num].code_size,
zend_jit_traces[parent_num].jmp_table_size,
exit_num,
handler);
t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
ZEND_JIT_EXIT_COUNTERS += t->exit_count;
zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
ZEND_JIT_TRACE_NUM++;
zend_jit_traces[parent_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_JITED;
ret = ZEND_JIT_TRACE_STOP_COMPILED;
} else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
} else {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
}
ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
} else {
if (t->stack_map) {
efree(t->stack_map);
t->stack_map = NULL;
}
ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
}
exit:
} zend_catch {
do_bailout = 1;
} zend_end_try();
zend_jit_protect();
SHM_PROTECT();
}
zend_shared_alloc_unlock();
if (do_bailout) {
zend_bailout();
}
if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
&& ret == ZEND_JIT_TRACE_STOP_COMPILED
&& t->exit_count > 0) {