int uopz_constant_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ #if PHP_VERSION_ID >= 70100 if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } #else if (EX(opline)->op1_type == IS_UNUSED) { if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } } else { zend_string *key = NULL; zval *mock = NULL; zend_class_entry *poser = NULL; if (EX(opline)->op1_type == IS_CONST) { key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1))); if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_OBJECT) { poser = Z_OBJCE_P(mock); } else poser = zend_lookup_class(Z_STR_P(mock)); CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser); } if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL); } zend_string_release(key); } else { key = zend_string_tolower(Z_CE_P(EX_VAR(EX(opline)->op1.var))->name); if ((mock = zend_hash_find(&UOPZ(mocks), key))) { if (Z_TYPE_P(mock) == IS_OBJECT) { poser = Z_OBJCE_P(mock); } else poser = zend_lookup_class(Z_STR_P(mock)); Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser; } CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), Z_CE_P(EX_VAR(EX(opline)->op1.var)), NULL); zend_string_release(key); } } #endif if (uopz_fetch_constant_handler) { return uopz_fetch_constant_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
static void zend_generator_cleanup_unfinished_execution(zend_generator *generator) /* {{{ */ { zend_execute_data *execute_data = generator->execute_data; zend_op_array *op_array = &execute_data->func->op_array; if (generator->send_target) { if (Z_REFCOUNTED_P(generator->send_target)) Z_DELREF_P(generator->send_target); generator->send_target = NULL; } /* Manually free loop variables, as execution couldn't reach their * SWITCH_FREE / FREE opcodes. */ { /* -1 required because we want the last run opcode, not the * next to-be-run one. */ uint32_t op_num = execute_data->opline - op_array->opcodes - 1; int i; for (i = 0; i < op_array->last_brk_cont; ++i) { zend_brk_cont_element *brk_cont = op_array->brk_cont_array + i; if (brk_cont->start < 0) { continue; } else if ((uint32_t)brk_cont->start > op_num) { break; } else if (brk_cont->brk >= 0 && (uint32_t)brk_cont->brk > op_num) { zend_op *brk_opline = op_array->opcodes + brk_cont->brk; if (brk_opline->opcode == ZEND_FREE) { zval *var = EX_VAR(brk_opline->op1.var); zval_ptr_dtor_nogc(var); } else if (brk_opline->opcode == ZEND_FE_FREE) { zval *var = EX_VAR(brk_opline->op1.var); if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { zend_hash_iterator_del(Z_FE_ITER_P(var)); } zval_ptr_dtor_nogc(var); } } } } /* If yield was used as a function argument there may be active * method calls those objects need to be freed */ while (execute_data->call) { if (Z_OBJ(execute_data->call->This)) { OBJ_RELEASE(Z_OBJ(execute_data->call->This)); } execute_data->call = execute_data->call->prev_execute_data; } }
static zval *get_zval_ptr_safe( int op_type, const znode_op *node, const zend_execute_data *execute_data ) { #ifdef ZEND_ENGINE_3 switch (op_type) { case IS_CONST: return EX_CONSTANT(*node); case IS_CV: case IS_TMP_VAR: case IS_VAR: { zval *zv = EX_VAR(node->var); ZVAL_DEREF(zv); return !Z_ISUNDEF_P(zv) ? zv : NULL; } default: return NULL; } #else switch (op_type) { case IS_CONST: return node->zv; case IS_TMP_VAR: return &SO_EX_T(node->var).tmp_var; case IS_VAR: return SO_EX_T(node->var).var.ptr; case IS_CV: { zval **tmp = SO_EX_CV(node->constant); return tmp ? *tmp : NULL; } default: return NULL; } #endif }
static zval *smd_get_zval_ptr_cv(zend_execute_data *execute_data, uint32_t var, int type, int force_ret) /* {{{ */ { zval *ret = EX_VAR(var); if (UNEXPECTED(Z_TYPE_P(ret) == IS_UNDEF)) { if (force_ret) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: zend_error(E_NOTICE, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(var)))); case BP_VAR_IS: ret = &EG(uninitialized_zval); break; case BP_VAR_RW: zend_error(E_NOTICE, "Undefined variable: %s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(var)))); case BP_VAR_W: ZVAL_NULL(ret); break; } } else { return NULL; } } else { ZVAL_DEREF(ret); } return ret; } /* }}} */
/* {{{ */ static int php_memoize_return(zend_execute_data *execute_data) { zend_long ttl = 0; const zend_function *fbc = EX(func); if (MG(ini.enabled) && php_memoize_is_memoizing(fbc, &ttl)) { zend_string *key = php_memoize_key( &EX(This), fbc, EX_NUM_ARGS(), EX_VAR_NUM(0)); if (key) { zval *return_value; if (EX(opline)->op1_type & IS_CONST) { return_value = EX_CONSTANT(EX(opline)->op1); } else { return_value = EX_VAR(EX(opline)->op1.var); } apc_cache_store(php_memoize_cache, key, return_value, ttl, 1); if (EG(exception)) { zend_clear_exception(); } zend_string_release(key); } } if (zend_return_function) { return zend_return_function(execute_data); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
/* {{{ */ static inline zend_bool php_memoize_is_memoized(const zend_execute_data *execute_data) { const zend_execute_data *call = EX(call); const zend_function *fbc = call->func; if (call && php_memoize_is_memoizing(fbc, NULL)) { zend_string *key = php_memoize_key( &call->This, fbc, ZEND_CALL_NUM_ARGS(call), ZEND_CALL_ARG(call, 1)); zval *return_value; if (!key) { return 0; } return_value = EX_VAR(EX(opline)->result.var); if (apc_cache_fetch(php_memoize_cache, key, php_memoize_time(), &return_value)) { zend_string_release(key); return 1; } zend_string_release(key); } return 0; } /* }}} */
static zval *smd_get_zval_ptr_tmpvar(zend_execute_data *execute_data, uint32_t var, zend_free_op *should_free) /* {{{ */ { zval *ret = EX_VAR(var); if (should_free) { *should_free = ret; } ZVAL_DEREF(ret); return ret; } /* }}} */
static int coro_exit_handler(zend_execute_data *execute_data) { zval ex; zend_object *obj; zend_long flags = 0; if (sw_get_current_cid() != -1) { flags |= SW_EXIT_IN_COROUTINE; } if (SwooleG.serv && SwooleG.serv->gs->start) { flags |= SW_EXIT_IN_SERVER; } if (flags) { const zend_op *opline = EX(opline); zval _exit_status; zval *exit_status = NULL; if (opline->op1_type != IS_UNUSED) { if (opline->op1_type == IS_CONST) { // see: https://github.com/php/php-src/commit/e70618aff6f447a298605d07648f2ce9e5a284f5 #ifdef EX_CONSTANT exit_status = EX_CONSTANT(opline->op1); #else exit_status = RT_CONSTANT(opline, opline->op1); #endif } else { exit_status = EX_VAR(opline->op1.var); } if (Z_ISREF_P(exit_status)) { exit_status = Z_REFVAL_P(exit_status); } } else { exit_status = &_exit_status; ZVAL_NULL(exit_status); } obj = zend_throw_error_exception(swoole_exit_exception_class_entry_ptr, "swoole exit.", 0, E_ERROR TSRMLS_CC); ZVAL_OBJ(&ex, obj); zend_update_property_long(swoole_exit_exception_class_entry_ptr, &ex, ZEND_STRL("flags"), flags); Z_TRY_ADDREF_P(exit_status); zend_update_property(swoole_exit_exception_class_entry_ptr, &ex, ZEND_STRL("status"), exit_status); } return ZEND_USER_OPCODE_DISPATCH; }
int uopz_return_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ zend_execute_data *call = EX(call); if (call) { uopz_return_t *ureturn; uopz_run_hook(call->func, call); ureturn = uopz_find_return(call->func); if (ureturn) { const zend_op *opline = EX(opline); zval rv, *return_value = RETURN_VALUE_USED(opline) ? EX_VAR(EX(opline)->result.var) : &rv; if (UOPZ_RETURN_IS_EXECUTABLE(ureturn)) { if (UOPZ_RETURN_IS_BUSY(ureturn)) { goto _uopz_return_handler_dispatch; } uopz_execute_return(ureturn, call, return_value); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(&rv); } return php_uopz_leave_helper(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(return_value, &ureturn->value); } return php_uopz_leave_helper(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } _uopz_return_handler_dispatch: if (uopz_do_fcall_handler) { return uopz_do_fcall_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */
int uopz_no_exit_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ if (UOPZ(exit)) { if (uopz_exit_handler) return uopz_exit_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); return ZEND_USER_OPCODE_DISPATCH; } if (EX(opline)->op1_type != IS_UNUSED) { zval *estatus; if (EX(opline)->op1_type == IS_CONST) { estatus = EX_CONSTANT(EX(opline)->op1); } else estatus = EX_VAR(EX(opline)->op1.var); if (Z_ISREF_P(estatus)) { estatus = Z_REFVAL_P(estatus); } if (Z_TYPE_P(estatus) == IS_LONG) { EG(exit_status) = Z_LVAL_P(estatus); } else EG(exit_status) = 0; ZVAL_COPY(&UOPZ(estatus), estatus); } if (EX(opline) < &EX(func)->op_array.opcodes[EX(func)->op_array.last - 1]) { EX(opline)++; while (EX(opline)->opcode == ZEND_EXT_STMT) { EX(opline)++; } return ZEND_USER_OPCODE_CONTINUE; } else { return ZEND_USER_OPCODE_RETURN; } } /* }}} */
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC) { zend_execute_data *old_execute_data; if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) { zend_clean_and_cache_symbol_table(EX(symbol_table)); } EG(current_execute_data) = EX(prev_execute_data); if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { OBJ_RELEASE(Z_OBJ(execute_data->This)); } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } zend_vm_stack_free_extra_args_ex(call_info, execute_data); old_execute_data = execute_data; execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); zend_throw_exception_internal(NULL); if (old_opline->result_type != IS_UNDEF) { zval_ptr_dtor(EX_VAR(old_opline->result.var)); } #ifndef HAVE_GCC_GLOBAL_REGS return 2; // ZEND_VM_LEAVE #endif } else { EX(opline)++; #ifdef HAVE_GCC_GLOBAL_REGS opline = EX(opline); #else return 2; // ZEND_VM_LEAVE #endif } }
int uopz_fetch_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ zval *name = NULL; zend_string *key = NULL; int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH; do { if (EX(opline)->op2_type == IS_UNUSED) { break; } if (EX(opline)->op2_type == IS_CONST) { name = EX_CONSTANT(EX(opline)->op2); if (name) { key = Z_STR_P(name); } } else if (EX(opline)->op2_type != IS_UNUSED) { name = EX_VAR(EX(opline)->op2.var); if (Z_TYPE_P(name) == IS_STRING) { key = Z_STR_P(name); } else if (Z_TYPE_P(name) == IS_OBJECT) { key = Z_OBJCE_P(name)->name; } else { } } if (key) { zval *mock = NULL; zend_class_entry *ce = NULL; zend_string *lookup = zend_string_tolower(key); if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), lookup)))) { switch (Z_TYPE_P(mock)) { case IS_OBJECT: ce = Z_OBJCE_P(mock); break; case IS_STRING: ce = zend_lookup_class(Z_STR_P(mock)); break; } if (ce) { if (EX(opline)->op2_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(name), ce); } Z_CE_P(EX_VAR(EX(opline)->result.var)) = ce; UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE; } } zend_string_release(lookup); } } while(0); if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_CONTINUE) { EX(opline) = EX(opline) + 1; } else { if (uopz_fetch_class_handler) { return uopz_fetch_class_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } return UOPZ_VM_ACTION; } /* }}} */
int uopz_mock_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH; zend_string *key; zval *mock = NULL; zend_class_entry *ce; if (EX(opline)->op1_type == IS_CONST) { ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1))); if (UNEXPECTED(ce == NULL)) { key = Z_STR_P(EX_CONSTANT(EX(opline)->op1)); } else { key = ce->name; } key = zend_string_tolower(key); } else if(EX(opline)->op1_type == IS_UNUSED) { ce = zend_fetch_class(NULL, EX(opline)->op1.num); if (UNEXPECTED(ce == NULL)) { return UOPZ_VM_ACTION; } key = zend_string_tolower(ce->name); } else { key = zend_string_tolower( Z_CE_P(EX_VAR(EX(opline)->op1.var))->name); } if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), key)))) { switch (Z_TYPE_P(mock)) { case IS_OBJECT: ZVAL_COPY( EX_VAR(EX(opline)->result.var), mock); #if PHP_VERSION_ID < 70100 EX(opline) = OP_JMP_ADDR(EX(opline), EX(opline)->op2); #else if (EX(opline)->extended_value == 0 && (EX(opline)+1)->opcode == ZEND_DO_FCALL) { EX(opline) += 2; } #endif UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE; break; case IS_STRING: ce = zend_lookup_class(Z_STR_P(mock)); if (EXPECTED(ce)) { if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), ce); } else if (EX(opline)->op1_type != IS_UNUSED) { Z_CE_P(EX_VAR(EX(opline)->op1.var)) = ce; } else { /* oh dear, can't do what is requested */ } } break; } } zend_string_release(key); if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_DISPATCH) { if (uopz_new_handler) { return uopz_new_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } } return UOPZ_VM_ACTION; } /* }}} */
int uopz_call_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */ switch (EX(opline)->opcode) { case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_FCALL: case ZEND_INIT_NS_FCALL_BY_NAME: { zval *function_name = EX_CONSTANT(EX(opline)->op2); CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL); } break; case ZEND_INIT_METHOD_CALL: { if (EX(opline)->op2_type == IS_CONST) { zval *function_name = EX_CONSTANT(EX(opline)->op2); CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL); } } break; case ZEND_INIT_STATIC_METHOD_CALL: { zend_class_entry *ce; zval *mock; zend_string *key = NULL; if (EX(opline)->op1_type == IS_CONST) { key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1))); } else if (EX(opline)->op1_type != IS_UNUSED) { ce = Z_CE_P(EX_VAR(EX(opline)->op1.var)); if (!ce) { break; } key = zend_string_tolower(ce->name); } if (key && (mock = zend_hash_find(&UOPZ(mocks), key))) { zend_class_entry *poser; if (Z_TYPE_P(mock) == IS_STRING) { poser = zend_lookup_class(Z_STR_P(mock)); if (!poser) { break; } } else poser = Z_OBJCE_P(mock); if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser); } else { Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser; } } if (key && EX(opline)->op2_type == IS_CONST) { zval *function_name = EX_CONSTANT(EX(opline)->op2); if (EX(opline)->op1_type == IS_CONST) { CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL); } else { CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL); } } if (key) { zend_string_release(key); } } break; } switch (EX(opline)->opcode) { case ZEND_INIT_FCALL_BY_NAME: if (uopz_init_fcall_by_name_handler) return uopz_init_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_FCALL: if (uopz_init_fcall_handler) return uopz_init_fcall_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_NS_FCALL_BY_NAME: if (uopz_init_ns_fcall_by_name_handler) return uopz_init_ns_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_METHOD_CALL: if (uopz_init_method_call_handler) return uopz_init_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); case ZEND_INIT_STATIC_METHOD_CALL: if (uopz_init_static_method_call_handler) return uopz_init_static_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU); } return ZEND_USER_OPCODE_DISPATCH; } /* }}} */