static void zend_persist_op_array_ex(zend_op_array *op_array, zend_persistent_script* main_persistent_script) { int already_stored = 0; zend_op *persist_ptr; zval *orig_literals = NULL; if (op_array->type != ZEND_USER_FUNCTION) { return; } if (--(*op_array->refcount) == 0) { efree(op_array->refcount); } op_array->refcount = NULL; if (main_persistent_script) { zend_execute_data *orig_execute_data = EG(current_execute_data); zend_execute_data fake_execute_data; zval *offset; memset(&fake_execute_data, 0, sizeof(fake_execute_data)); fake_execute_data.func = (zend_function*)op_array; EG(current_execute_data) = &fake_execute_data; if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) { main_persistent_script->compiler_halt_offset = Z_LVAL_P(offset); } EG(current_execute_data) = orig_execute_data; } if (op_array->static_variables) { zend_hash_persist(op_array->static_variables, zend_persist_zval); zend_accel_store(op_array->static_variables, sizeof(HashTable)); } if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) { already_stored = 1; } if (op_array->literals) { if (already_stored) { orig_literals = zend_shared_alloc_get_xlat_entry(op_array->literals); ZEND_ASSERT(orig_literals != NULL); op_array->literals = orig_literals; } else { zval *p = zend_accel_memdup(op_array->literals, sizeof(zval) * op_array->last_literal); zval *end = p + op_array->last_literal; orig_literals = op_array->literals; op_array->literals = p; while (p < end) { zend_persist_zval(p); p++; } efree(orig_literals); } } if (already_stored) { persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->opcodes); ZEND_ASSERT(persist_ptr != NULL); op_array->opcodes = persist_ptr; } else { zend_op *new_opcodes = zend_accel_memdup(op_array->opcodes, sizeof(zend_op) * op_array->last); #if ZEND_USE_ABS_CONST_ADDR || ZEND_USE_ABS_JMP_ADDR zend_op *opline = new_opcodes; zend_op *end = new_opcodes + op_array->last; int offset = 0; for (; opline < end ; opline++, offset++) { # if ZEND_USE_ABS_CONST_ADDR if (ZEND_OP1_TYPE(opline) == IS_CONST) { opline->op1.zv = (zval*)((char*)opline->op1.zv + ((char*)op_array->literals - (char*)orig_literals)); } if (ZEND_OP2_TYPE(opline) == IS_CONST) { opline->op2.zv = (zval*)((char*)opline->op2.zv + ((char*)op_array->literals - (char*)orig_literals)); } # endif # if ZEND_USE_ABS_JMP_ADDR if (ZEND_DONE_PASS_TWO(op_array)) { /* fix jumps to point to new array */ switch (opline->opcode) { case ZEND_JMP: case ZEND_GOTO: case ZEND_FAST_CALL: ZEND_OP1(opline).jmp_addr = &new_opcodes[ZEND_OP1(opline).jmp_addr - op_array->opcodes]; break; case ZEND_JMPZNZ: /* relative extended_value don't have to be changed */ /* break omitted intentionally */ case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_NEW: case ZEND_FE_RESET: case ZEND_FE_FETCH: ZEND_OP2(opline).jmp_addr = &new_opcodes[ZEND_OP2(opline).jmp_addr - op_array->opcodes]; break; } } # endif } #endif efree(op_array->opcodes); op_array->opcodes = new_opcodes; if (op_array->run_time_cache) { efree(op_array->run_time_cache); op_array->run_time_cache = NULL; } } if (op_array->function_name && !IS_ACCEL_INTERNED(op_array->function_name)) { zend_string *new_name; if (already_stored) { new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name); ZEND_ASSERT(new_name != NULL); op_array->function_name = new_name; } else { zend_accel_store_string(op_array->function_name); } } if (op_array->filename) { /* do not free! PHP has centralized filename storage, compiler will free it */ zend_accel_memdup_string(op_array->filename); } if (op_array->arg_info) { if (already_stored) { zend_arg_info *new_ptr = zend_shared_alloc_get_xlat_entry(op_array->arg_info); ZEND_ASSERT(new_ptr != NULL); op_array->arg_info = new_ptr; } else { uint32_t i, num_args; num_args = op_array->num_args; if (op_array->fn_flags & ZEND_ACC_VARIADIC) { num_args++; } zend_accel_store(op_array->arg_info, sizeof(zend_arg_info) * num_args); for (i = 0; i < num_args; i++) { if (op_array->arg_info[i].name) { zend_accel_store_interned_string(op_array->arg_info[i].name); } if (op_array->arg_info[i].class_name) { zend_accel_store_interned_string(op_array->arg_info[i].class_name); } } } } if (op_array->brk_cont_array) { zend_accel_store(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); } if (op_array->scope) { op_array->scope = zend_shared_alloc_get_xlat_entry(op_array->scope); } if (op_array->doc_comment) { if (ZCG(accel_directives).save_comments) { if (already_stored) { op_array->doc_comment = zend_shared_alloc_get_xlat_entry(op_array->doc_comment); ZEND_ASSERT(op_array->doc_comment != NULL); } else { zend_accel_store_string(op_array->doc_comment); } } else { if (!already_stored) { zend_string_release(op_array->doc_comment); } op_array->doc_comment = NULL; } } if (op_array->try_catch_array) { zend_accel_store(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); } if (op_array->vars) { if (already_stored) { persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->vars); ZEND_ASSERT(persist_ptr != NULL); op_array->vars = (zend_string**)persist_ptr; } else { int i; zend_accel_store(op_array->vars, sizeof(zend_string*) * op_array->last_var); for (i = 0; i < op_array->last_var; i++) { zend_accel_store_interned_string(op_array->vars[i]); } } } /* "prototype" may be undefined if "scope" isn't set */ if (op_array->scope && op_array->prototype) { if ((persist_ptr = zend_shared_alloc_get_xlat_entry(op_array->prototype))) { op_array->prototype = (union _zend_function*)persist_ptr; /* we use refcount to show that op_array is referenced from several places */ op_array->prototype->op_array.refcount++; } } else { op_array->prototype = NULL; } }
static void zend_persist_op_array_calc_ex(zend_op_array *op_array) { if (op_array->type != ZEND_USER_FUNCTION) { return; } if (op_array->static_variables) { if (!zend_shared_alloc_get_xlat_entry(op_array->static_variables)) { HashTable *old = op_array->static_variables; ADD_DUP_SIZE(op_array->static_variables, sizeof(HashTable)); zend_hash_persist_calc(op_array->static_variables, zend_persist_zval_calc); zend_shared_alloc_register_xlat_entry(old, op_array->static_variables); } } if (zend_shared_alloc_get_xlat_entry(op_array->opcodes)) { /* already stored */ if (op_array->function_name) { zend_string *new_name = zend_shared_alloc_get_xlat_entry(op_array->function_name); if (IS_ACCEL_INTERNED(new_name)) { op_array->function_name = new_name; } } return; } if (op_array->literals) { zval *p = op_array->literals; zval *end = p + op_array->last_literal; ADD_DUP_SIZE(op_array->literals, sizeof(zval) * op_array->last_literal); while (p < end) { zend_persist_zval_calc(p); p++; } } ADD_DUP_SIZE(op_array->opcodes, sizeof(zend_op) * op_array->last); if (op_array->function_name) { zend_string *old_name = op_array->function_name; zend_string *new_name = zend_shared_alloc_get_xlat_entry(old_name); if (new_name) { op_array->function_name = new_name; } else { ADD_INTERNED_STRING(op_array->function_name, 0); zend_shared_alloc_register_xlat_entry(old_name, op_array->function_name); } } if (op_array->filename) { ADD_STRING(op_array->filename); } if (op_array->arg_info) { zend_arg_info *arg_info = op_array->arg_info; uint32_t num_args = op_array->num_args; uint32_t i; num_args = op_array->num_args; if (op_array->fn_flags & ZEND_ACC_VARIADIC) { num_args++; } if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { arg_info--; num_args++; } ADD_DUP_SIZE(op_array->arg_info, sizeof(zend_arg_info) * num_args); ADD_DUP_SIZE(arg_info, sizeof(zend_arg_info) * num_args); for (i = 0; i < num_args; i++) { if (arg_info[i].name) { ADD_INTERNED_STRING(arg_info[i].name, 1); } if (arg_info[i].class_name) { ADD_INTERNED_STRING(arg_info[i].class_name, 1); } } } if (op_array->brk_cont_array) { ADD_DUP_SIZE(op_array->brk_cont_array, sizeof(zend_brk_cont_element) * op_array->last_brk_cont); } if (ZCG(accel_directives).save_comments && op_array->doc_comment) { ADD_STRING(op_array->doc_comment); } if (op_array->try_catch_array) { ADD_DUP_SIZE(op_array->try_catch_array, sizeof(zend_try_catch_element) * op_array->last_try_catch); } if (op_array->vars) { int i; ADD_DUP_SIZE(op_array->vars, sizeof(zend_string*) * op_array->last_var); for (i = 0; i < op_array->last_var; i++) { ADD_INTERNED_STRING(op_array->vars[i], 0); } } }