void zend_optimizer_update_op1_const(zend_op_array *op_array, zend_op *opline, zval *val) { if (opline->opcode == ZEND_FREE) { MAKE_NOP(opline); zval_dtor(val); } else { ZEND_OP1_TYPE(opline) = IS_CONST; if (Z_TYPE_P(val) == IS_STRING) { switch (opline->opcode) { case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_CATCH: case ZEND_FETCH_CONSTANT: case ZEND_DEFINED: case ZEND_NEW: opline->op1.constant = zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->last_cache_slot++; zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(op_array->literals[opline->op1.constant+1])); break; default: opline->op1.constant = zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); break; } } else { opline->op1.constant = zend_optimizer_add_literal(op_array, val); } } }
inline int wrapper_zend_hash_get_current_key(HashTable *ht, char **key, uint *idx, ulong *num) { zval str_key; ZVAL_STRING(&str_key, *key); int type = zend_hash_get_current_key(ht, &Z_STR(str_key), (zend_ulong*) num); *key = Z_STR(str_key)->val; return type; }
static void copy_zend_constant(zval *zv) { zend_constant *c = Z_PTR_P(zv); ZEND_ASSERT(c->flags & CONST_PERSISTENT); Z_PTR_P(zv) = pemalloc(sizeof(zend_constant), 1); memcpy(Z_PTR_P(zv), c, sizeof(zend_constant)); c = Z_PTR_P(zv); c->name = zend_string_copy(c->name); if (Z_TYPE(c->value) == IS_STRING) { Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1); } }
inline int sw_zend_hash_add(HashTable *ht, char *k, int len, void *pData, int datasize, void **pDest) { zval key; ZVAL_STRING(&key, k); zval **real_p = pData; return zend_hash_add(ht, Z_STR(key), *real_p) ? SUCCESS : FAILURE; }
inline int sw_zend_hash_del(HashTable *ht, char *k, int len) { zval key; ZVAL_STRING(&key, k); return zend_hash_del(ht, Z_STR(key)); }
/** * Interpolates context values into the message placeholders * * @see http://www.php-fig.org/psr/psr-3/ Section 1.2 Message * @param string $message * @param array $context */ PHP_METHOD(Phalcon_Logger_Formatter, interpolate) { zval *message, *context; zval replace, *val; zend_string *str_key; ulong idx; phalcon_fetch_params(0, 2, 0, &message, &context); if (Z_TYPE_P(context) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(context)) > 0) { array_init(&replace); ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(context), idx, str_key, val) { zval index; char *tmp; uint str_length; if (str_key) {; str_length = spprintf(&tmp, 0, "{%s}", str_key->val); ZVAL_STRINGL(&index, tmp, str_length); } else { str_length = spprintf(&tmp, 0, "{%ld}", idx); ZVAL_STRINGL(&index, tmp, str_length); } Z_TRY_ADDREF_P(val); zend_hash_add(Z_ARRVAL(replace), Z_STR(index), val); efree(tmp); } ZEND_HASH_FOREACH_END();
ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval_ptr, int argc, zval *args) { ZEND_RESULT_CODE rv; zval retval; ZVAL_UNDEF(&retval); Z_ADDREF_P(zobject); cb->fci.object = Z_OBJ_P(zobject); cb->fcc.object = Z_OBJ_P(zobject); cb->fci.retval = retval_ptr ? retval_ptr : &retval; cb->fci.param_count = argc; cb->fci.params = args; if (cb->fcc.called_scope != Z_OBJCE_P(zobject)) { cb->fcc.called_scope = Z_OBJCE_P(zobject); cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); } rv = zend_call_function(&cb->fci, &cb->fcc); zval_ptr_dtor(zobject); if (!retval_ptr && !Z_ISUNDEF(retval)) { zval_ptr_dtor(&retval); } return rv; }
static inline int msgpack_convert_string_to_properties(zval *object, zend_string *key, zval *val, HashTable *var)/* {{{ */ { zend_class_entry *ce = Z_OBJCE_P(object); HashTable *propers = Z_OBJPROP_P(object); zend_string *prot_name, *priv_name; zval pub_name; int return_code; ZVAL_STR(&pub_name, key); priv_name = zend_mangle_property_name(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(key), ZSTR_LEN(key), 1); prot_name = zend_mangle_property_name("*", 1, ZSTR_VAL(key), ZSTR_LEN(key), 1); if (zend_hash_find(propers, priv_name) != NULL) { zend_update_property_ex(ce, object, key, val); return_code = SUCCESS; } else if (zend_hash_find(propers, prot_name) != NULL) { zend_update_property_ex(ce, object, key, val); return_code = SUCCESS; } else { zend_std_write_property(object, &pub_name, val, NULL); return_code = FAILURE; } zend_hash_add(var, Z_STR(pub_name), val); zend_string_release(priv_name); zend_string_release(prot_name); return return_code; }
inline int sw_zend_hash_get_current_key(HashTable *ht, char **key, uint32_t *keylen, ulong *num) { zval str_key; int type = zend_hash_get_current_key(ht, &Z_STR(str_key), (zend_ulong* ) num); *key = Z_STRVAL(str_key); *keylen = Z_STRLEN(str_key); return type; }
ZEND_API void zend_strip(void) { zval token; int token_type; int prev_space = 0; ZVAL_UNDEF(&token); while ((token_type=lex_scan(&token))) { switch (token_type) { case T_WHITESPACE: if (!prev_space) { zend_write(" ", sizeof(" ") - 1); prev_space = 1; } /* lack of break; is intentional */ case T_COMMENT: case T_DOC_COMMENT: ZVAL_UNDEF(&token); continue; case T_END_HEREDOC: zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); /* read the following character, either newline or ; */ if (lex_scan(&token) != T_WHITESPACE) { zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); } zend_write("\n", sizeof("\n") - 1); prev_space = 1; ZVAL_UNDEF(&token); continue; default: zend_write((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); break; } if (Z_TYPE(token) == IS_STRING) { switch (token_type) { case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: case T_CLOSE_TAG: case T_WHITESPACE: case T_COMMENT: case T_DOC_COMMENT: break; default: zend_string_release(Z_STR(token)); break; } } prev_space = 0; ZVAL_UNDEF(&token); } /* Discard parse errors thrown during tokenization */ zend_clear_exception(); }
static int accel_file_in_cache(INTERNAL_FUNCTION_PARAMETERS) { zval zfilename; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_array_ex(1, &zfilename) == FAILURE || Z_TYPE(zfilename) != IS_STRING || Z_STRLEN(zfilename) == 0) { return 0; } return filename_is_in_cache(Z_STR(zfilename)); }
inline int sw_zend_hash_exists(HashTable *ht, char *k, int len) { zval key; ZVAL_STRING(&key, k); zval *value = zend_hash_find(ht, Z_STR(key)); if (value == NULL) { return FAILURE; } else { return SUCCESS; } }
void skyray_http_request_resolve_queries_if_needed(skyray_http_request_t *self) { if (!ZVAL_IS_NULL(&self->query_params) || ZVAL_IS_NULL(&self->uri)) { return; } array_init(&self->query_params); php_url *url = php_url_parse_ex(Z_STR(self->uri)->val, Z_STR(self->uri)->len); if (!url->query) { php_url_free(url); return; } zend_string *query = zend_string_init(url->query, strlen(url->query), 0); char *res = estrdup(url->query); sapi_module.treat_data(PARSE_STRING, res, &self->query_params); zend_string_free(query); php_url_free(url); }
int zend_optimizer_update_op1_const(zend_op_array *op_array, zend_op *opline, zval *val) { switch (opline->opcode) { case ZEND_FREE: MAKE_NOP(opline); zval_dtor(val); break; case ZEND_INIT_STATIC_METHOD_CALL: case ZEND_CATCH: case ZEND_FETCH_CONSTANT: case ZEND_FETCH_CLASS_CONSTANT: case ZEND_DEFINED: case ZEND_NEW: REQUIRES_STRING(val); ZEND_OP1_TYPE(opline) = IS_CONST; drop_leading_backslash(val); opline->op1.constant = zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size; op_array->cache_size += sizeof(void*); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); break; case ZEND_CONCAT: case ZEND_FAST_CONCAT: TO_STRING_NOWARN(val); /* break missing intentionally */ default: ZEND_OP1_TYPE(opline) = IS_CONST; opline->op1.constant = zend_optimizer_add_literal(op_array, val); if (Z_TYPE_P(val) == IS_STRING) { zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline))); } break; } return 1; }
HashTable *mysqli_object_get_debug_info(zval *object, int *is_temp) { mysqli_object *obj = Z_MYSQLI_P(object); HashTable *retval, *props = obj->prop_handler; mysqli_prop_handler *entry; retval = zend_new_array(zend_hash_num_elements(props) + 1); ZEND_HASH_FOREACH_PTR(props, entry) { zval rv, member; zval *value; ZVAL_STR(&member, entry->name); value = mysqli_read_property(object, &member, BP_VAR_IS, 0, &rv); if (value != &EG(uninitialized_zval)) { zend_hash_add(retval, Z_STR(member), value); } } ZEND_HASH_FOREACH_END();
php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len) { if (!cb) { cb = ecalloc(1, sizeof(*cb)); } else { memset(cb, 0, sizeof(*cb)); } cb->fci.size = sizeof(cb->fci); ZVAL_STRINGL(&cb->fci.function_name, method_str, method_len); #if PHP_VERSION_ID < 70300 cb->fcc.initialized = 1; #endif cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject); cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL); return cb; }
inline int sw_zend_hash_find(HashTable *ht, char *k, int len, void **v) { // char _key[128]; // zend_string *key; // // if (sizeof (zend_string) + len > sizeof (_key)) { // key = emalloc(sizeof (zend_string) + len); // } else { // key = _key; // } // // key->len = len; // memcpy(key->val, k, len); // key->val[len] = 0; #if PHP_MAJOR_VERSION < 7 zval **tmp = NULL; if(zend_hash_find(ht, k,len, (void **) &tmp) == SUCCESS) { *v = *tmp; return SUCCESS; } else { *v = NULL; return FAILURE; } #else zval key; ZVAL_STRINGL(&key, k, len - 1); zval *value = zend_hash_find(ht, Z_STR(key)); if (value == NULL) { return FAILURE; } else { *v = (void *) value; v = (void *) value; return SUCCESS; } #endif }
static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { while (elements-- > 0) { zval key, *data, d, *old_data; zend_ulong idx; ZVAL_UNDEF(&key); if (!php_var_unserialize_ex(&key, p, max, NULL, classes)) { zval_dtor(&key); return 0; } data = NULL; ZVAL_UNDEF(&d); if (!objprops) { if (Z_TYPE(key) == IS_LONG) { idx = Z_LVAL(key); numeric_key: if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) { //??? update hash var_push_dtor(var_hash, old_data); data = zend_hash_index_update(ht, idx, &d); } else { data = zend_hash_index_add_new(ht, idx, &d); } } else if (Z_TYPE(key) == IS_STRING) { if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) { goto numeric_key; } if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) { //??? update hash var_push_dtor(var_hash, old_data); data = zend_hash_update(ht, Z_STR(key), &d); } else { data = zend_hash_add_new(ht, Z_STR(key), &d); } } else { zval_dtor(&key); return 0; } } else { if (EXPECTED(Z_TYPE(key) == IS_STRING)) { string_key: if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { if (Z_TYPE_P(old_data) == IS_INDIRECT) { old_data = Z_INDIRECT_P(old_data); } var_push_dtor(var_hash, old_data); data = zend_hash_update_ind(ht, Z_STR(key), &d); } else { data = zend_hash_add_new(ht, Z_STR(key), &d); } } else if (Z_TYPE(key) == IS_LONG) { /* object properties should include no integers */ convert_to_string(&key); goto string_key; } else { zval_dtor(&key); return 0; } } if (!php_var_unserialize_ex(data, p, max, var_hash, classes)) { zval_dtor(&key); return 0; } if (UNEXPECTED(Z_ISUNDEF_P(data))) { if (Z_TYPE(key) == IS_LONG) { zend_hash_index_del(ht, Z_LVAL(key)); } else { zend_hash_del_ind(ht, Z_STR(key)); } } else { var_push_dtor(var_hash, data); } zval_dtor(&key); if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; return 0; } } return 1; }
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int i = 0; zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; zend_bool collect_constants = (op_array == &ctx->script->main_op_array); while (opline < end) { switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_POW: case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: case ZEND_FAST_CONCAT: case ZEND_IS_EQUAL: case ZEND_IS_NOT_EQUAL: case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: case ZEND_BW_OR: case ZEND_BW_AND: case ZEND_BW_XOR: case ZEND_BOOL_XOR: if (ZEND_OP1_TYPE(opline) == IS_CONST && ZEND_OP2_TYPE(opline) == IS_CONST) { /* binary operation with constant operands */ binary_op_type binary_op = get_binary_op(opline->opcode); uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ zval result; int er; if (opline->opcode == ZEND_DIV && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_LONG && Z_LVAL(ZEND_OP2_LITERAL(opline)) == 0) { /* div by 0 */ break; } er = EG(error_reporting); EG(error_reporting) = 0; /* evaluate constant expression */ if (binary_op(&result, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) != SUCCESS) { EG(error_reporting) = er; break; } EG(error_reporting) = er; if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_CAST: if (ZEND_OP1_TYPE(opline) == IS_CONST && opline->extended_value != IS_ARRAY && opline->extended_value != IS_OBJECT && opline->extended_value != IS_RESOURCE) { /* cast of constant operand */ zend_uchar type = opline->result_type; uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ zval res; res = ZEND_OP1_LITERAL(opline); zval_copy_ctor(&res); switch (opline->extended_value) { case IS_NULL: convert_to_null(&res); break; case _IS_BOOL: convert_to_boolean(&res); break; case IS_LONG: convert_to_long(&res); break; case IS_DOUBLE: convert_to_double(&res); break; case IS_STRING: convert_to_string(&res); break; } if (zend_optimizer_replace_by_const(op_array, opline + 1, type, tv, &res)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } else if (opline->extended_value == _IS_BOOL) { /* T = CAST(X, IS_BOOL) => T = BOOL(X) */ opline->opcode = ZEND_BOOL; opline->extended_value = 0; } break; case ZEND_BW_NOT: case ZEND_BOOL_NOT: if (ZEND_OP1_TYPE(opline) == IS_CONST) { /* unary operation on constant operand */ unary_op_type unary_op = get_unary_op(opline->opcode); zval result; uint32_t tv = ZEND_RESULT(opline).var; /* temporary variable */ int er; er = EG(error_reporting); EG(error_reporting) = 0; if (unary_op(&result, &ZEND_OP1_LITERAL(opline)) != SUCCESS) { EG(error_reporting) = er; break; } EG(error_reporting) = er; if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, tv, &result)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; #if 0 case ZEND_ADD_STRING: case ZEND_ADD_CHAR: { zend_op *next_op = opline + 1; int requires_conversion = (opline->opcode == ZEND_ADD_CHAR? 1 : 0); size_t final_length = 0; zend_string *str; char *ptr; zend_op *last_op; /* There is always a ZEND_RETURN at the end if (next_op>=end) { break; } */ while (next_op->opcode == ZEND_ADD_STRING || next_op->opcode == ZEND_ADD_CHAR) { if (ZEND_RESULT(opline).var != ZEND_RESULT(next_op).var) { break; } if (next_op->opcode == ZEND_ADD_CHAR) { final_length += 1; } else { /* ZEND_ADD_STRING */ final_length += Z_STRLEN(ZEND_OP2_LITERAL(next_op)); } next_op++; } if (final_length == 0) { break; } last_op = next_op; final_length += (requires_conversion? 1 : Z_STRLEN(ZEND_OP2_LITERAL(opline))); str = zend_string_alloc(final_length, 0); str->len = final_length; ptr = str->val; ptr[final_length] = '\0'; if (requires_conversion) { /* ZEND_ADD_CHAR */ char chval = (char)Z_LVAL(ZEND_OP2_LITERAL(opline)); ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str); ptr[0] = chval; opline->opcode = ZEND_ADD_STRING; ptr++; } else { /* ZEND_ADD_STRING */ memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline))); ptr += Z_STRLEN(ZEND_OP2_LITERAL(opline)); zend_string_release(Z_STR(ZEND_OP2_LITERAL(opline))); ZVAL_NEW_STR(&ZEND_OP2_LITERAL(opline), str); } next_op = opline + 1; while (next_op < last_op) { if (next_op->opcode == ZEND_ADD_STRING) { memcpy(ptr, Z_STRVAL(ZEND_OP2_LITERAL(next_op)), Z_STRLEN(ZEND_OP2_LITERAL(next_op))); ptr += Z_STRLEN(ZEND_OP2_LITERAL(next_op)); literal_dtor(&ZEND_OP2_LITERAL(next_op)); } else { /* ZEND_ADD_CHAR */ *ptr = (char)Z_LVAL(ZEND_OP2_LITERAL(next_op)); ptr++; } MAKE_NOP(next_op); next_op++; } if (!((ZEND_OPTIMIZER_PASS_5|ZEND_OPTIMIZER_PASS_10) & OPTIMIZATION_LEVEL)) { /* NOP removal is disabled => insert JMP over NOPs */ if (last_op-opline >= 3) { /* If we have more than 2 NOPS then JMP over them */ (opline + 1)->opcode = ZEND_JMP; ZEND_OP1(opline + 1).opline_num = last_op - op_array->opcodes; /* that's OK even for ZE2, since opline_num's are resolved in pass 2 later */ } } } break; #endif case ZEND_FETCH_CONSTANT: if (ZEND_OP1_TYPE(opline) == IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 && memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) { /* substitute __COMPILER_HALT_OFFSET__ constant */ zend_execute_data *orig_execute_data = EG(current_execute_data); zend_execute_data fake_execute_data; zval *offset; memset(&fake_execute_data, 0, sizeof(zend_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) { uint32_t tv = ZEND_RESULT(opline).var; if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, offset)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } EG(current_execute_data) = orig_execute_data; break; } if (ZEND_OP1_TYPE(opline) == IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { /* substitute persistent constants */ uint32_t tv = ZEND_RESULT(opline).var; zval c; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) { if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) { break; } } if (Z_TYPE(c) == IS_CONSTANT_AST) { break; } if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } /* class constant */ if (ZEND_OP1_TYPE(opline) != IS_UNUSED && ZEND_OP2_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { zend_class_entry *ce = NULL; if (ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { /* for A::B */ if (op_array->scope && !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), op_array->scope->name->val, Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) { ce = op_array->scope; } else { if ((ce = zend_hash_find_ptr(EG(class_table), Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL || (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->type != MODULE_PERSISTENT) || (ce->type == ZEND_USER_CLASS && ZEND_CE_FILENAME(ce) != op_array->filename)) { break; } } } else if (op_array->scope && ZEND_OP1_TYPE(opline) == IS_VAR && (opline - 1)->opcode == ZEND_FETCH_CLASS && (ZEND_OP1_TYPE(opline - 1) == IS_UNUSED && ((opline - 1)->extended_value & ~ZEND_FETCH_CLASS_NO_AUTOLOAD) == ZEND_FETCH_CLASS_SELF) && ZEND_RESULT((opline - 1)).var == ZEND_OP1(opline).var) { /* for self::B */ ce = op_array->scope; } if (ce) { uint32_t tv = ZEND_RESULT(opline).var; zval *c, t; if ((c = zend_hash_find(&ce->constants_table, Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL) { ZVAL_DEREF(c); if (Z_TYPE_P(c) == IS_CONSTANT_AST) { break; } if (ZEND_IS_CONSTANT_TYPE(Z_TYPE_P(c))) { if (!zend_optimizer_get_persistent_constant(Z_STR_P(c), &t, 1) || ZEND_IS_CONSTANT_TYPE(Z_TYPE(t))) { break; } } else { ZVAL_COPY_VALUE(&t, c); zval_copy_ctor(&t); } if (ZEND_OP1_TYPE(opline) == IS_CONST) { literal_dtor(&ZEND_OP1_LITERAL(opline)); } else { MAKE_NOP((opline - 1)); } if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &t)) { literal_dtor(&ZEND_OP2_LITERAL(opline)); MAKE_NOP(opline); } } } } break; case ZEND_DO_ICALL: { zend_op *send1_opline = opline - 1; zend_op *send2_opline = NULL; zend_op *init_opline = NULL; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || ZEND_OP1_TYPE(send1_opline) != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } if (send1_opline->op2.num == 2) { send2_opline = send1_opline; send1_opline--; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || ZEND_OP1_TYPE(send1_opline) != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } } init_opline = send1_opline - 1; while (init_opline->opcode == ZEND_NOP) { init_opline--; } if (init_opline->opcode != ZEND_INIT_FCALL || ZEND_OP2_TYPE(init_opline) != IS_CONST || Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } /* define("name", scalar); */ if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 && zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) { if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING && send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) { if (collect_constants) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline)); } if (RESULT_UNUSED(opline) && !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { opline->opcode = ZEND_DECLARE_CONST; opline->op1_type = IS_CONST; opline->op2_type = IS_CONST; opline->result_type = IS_UNUSED; opline->op1.constant = send1_opline->op1.constant; opline->op2.constant = send2_opline->op1.constant; opline->result.num = 0; literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); MAKE_NOP(send1_opline); MAKE_NOP(send2_opline); } break; } } /* pre-evaluate constant functions: defined(x) constant(x) function_exists(x) is_callable(x) extension_loaded(x) */ if (!send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) { if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "function_exists", sizeof("function_exists")-1)) || (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "is_callable", sizeof("is_callable")))) { zend_internal_function *func; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL && func->type == ZEND_INTERNAL_FUNCTION && func->module->type == MODULE_PERSISTENT) { zval t; if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 || func->handler != ZEND_FN(display_disabled_function)) { ZVAL_TRUE(&t); } else { ZVAL_FALSE(&t); } if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); zend_string_release(lc_name); break; } } zend_string_release(lc_name); } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "extension_loaded", sizeof("extension_loaded")-1)) { zval t; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); zend_module_entry *m = zend_hash_find_ptr(&module_registry, lc_name); zend_string_release(lc_name); if (!m) { if (!PG(enable_dl)) { break; } else { ZVAL_FALSE(&t); } } else { if (m->type == MODULE_PERSISTENT) { ZVAL_TRUE(&t); } else { break; } } if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("defined")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "defined", sizeof("defined")-1)) { zval t; if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 0)) { ZVAL_TRUE(&t); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "constant", sizeof("constant")-1)) { zval t; if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) { if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } } else if ((CG(compiler_options) & ZEND_COMPILE_NO_BUILTIN_STRLEN) == 0 && Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("strlen") - 1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "strlen", sizeof("strlen") - 1)) { zval t; ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(send1_opline))); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "dirname", sizeof("dirname")-1) && IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0); dirname->len = zend_dirname(dirname->val, dirname->len); if (IS_ABSOLUTE_PATH(dirname->val, dirname->len)) { zval t; ZVAL_STR(&t, dirname); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); MAKE_NOP(opline); break; } } else { zend_string_release(dirname); } } } /* don't colllect constants after any other function call */ collect_constants = 0; break; } case ZEND_STRLEN: if (ZEND_OP1_TYPE(opline) == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { zval t; ZVAL_LONG(&t, Z_STRLEN(ZEND_OP1_LITERAL(opline))); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, ZEND_RESULT(opline).var, &t)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_DEFINED: { zval c; uint32_t tv = ZEND_RESULT(opline).var; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) { break; } ZVAL_TRUE(&c); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, tv, &c)) { literal_dtor(&ZEND_OP1_LITERAL(opline)); MAKE_NOP(opline); } } break; case ZEND_DECLARE_CONST: if (collect_constants && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); } break; case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: case ZEND_EXIT: case ZEND_THROW: case ZEND_CATCH: case ZEND_BRK: case ZEND_CONT: case ZEND_GOTO: case ZEND_FAST_CALL: case ZEND_FAST_RET: case ZEND_JMP: case ZEND_JMPZNZ: case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: collect_constants = 0; break; case ZEND_FETCH_R: case ZEND_FETCH_W: case ZEND_FETCH_RW: case ZEND_FETCH_FUNC_ARG: case ZEND_FETCH_IS: case ZEND_FETCH_UNSET: if (opline != op_array->opcodes && (opline-1)->opcode == ZEND_BEGIN_SILENCE && (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL && opline->op1_type == IS_CONST && opline->op2_type == IS_UNUSED && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && (Z_STRLEN(ZEND_OP1_LITERAL(opline)) != sizeof("this")-1 || memcmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), "this", sizeof("this") - 1) != 0)) { int var = opline->result.var; int level = 0; zend_op *op = opline + 1; zend_op *use = NULL; while (op < end) { if (op->opcode == ZEND_BEGIN_SILENCE) { level++; } else if (op->opcode == ZEND_END_SILENCE) { if (level == 0) { break; } else { level--; } } if (op->op1_type == IS_VAR && op->op1.var == var) { if (use) { /* used more than once */ use = NULL; break; } use = op; } else if (op->op2_type == IS_VAR && op->op2.var == var) { if (use) { /* used more than once */ use = NULL; break; } use = op; } op++; } if (use) { if (use->op1_type == IS_VAR && use->op1.var == var) { use->op1_type = IS_CV; use->op1.var = zend_optimizer_lookup_cv(op_array, Z_STR(ZEND_OP1_LITERAL(opline))); MAKE_NOP(opline); } else if (use->op2_type == IS_VAR && use->op2.var == var) { use->op2_type = IS_CV; use->op2.var = zend_optimizer_lookup_cv(op_array, Z_STR(ZEND_OP1_LITERAL(opline))); MAKE_NOP(opline); } } } break; } opline++; i++; } }
/** * Sends the cookie to the HTTP client * Stores the cookie definition in session * * @return Phalcon\Http\Cookie */ PHP_METHOD(Phalcon_Http_Cookie, send){ zval *name, *value, *expire, *domain, *path, *secure, *http_only, *dependency_injector; zval service = {}, has_session = {}, definition = {}, session = {}, key = {}, encryption = {}, crypt = {}, encrypt_value = {}; name = phalcon_read_property(getThis(), SL("_name"), PH_NOISY); value = phalcon_read_property(getThis(), SL("_value"), PH_NOISY); expire = phalcon_read_property(getThis(), SL("_expire"), PH_NOISY); domain = phalcon_read_property(getThis(), SL("_domain"), PH_NOISY); path = phalcon_read_property(getThis(), SL("_path"), PH_NOISY); secure = phalcon_read_property(getThis(), SL("_secure"), PH_NOISY); http_only = phalcon_read_property(getThis(), SL("_httpOnly"), PH_NOISY); dependency_injector = phalcon_read_property(getThis(), SL("_dependencyInjector"), PH_NOISY); if (Z_TYPE_P(dependency_injector) == IS_OBJECT) { ZVAL_STRING(&service, ISV(session)); PHALCON_CALL_METHODW(&has_session, dependency_injector, "has", &service); if (zend_is_true(&has_session)) { array_init(&definition); if (!PHALCON_IS_LONG(expire, 0)) { phalcon_array_update_str(&definition, SL("expire"), expire, PH_COPY); } if (PHALCON_IS_NOT_EMPTY(path)) { phalcon_array_update_str(&definition, SL("path"), path, PH_COPY); } if (PHALCON_IS_NOT_EMPTY(domain)) { phalcon_array_update_string(&definition, IS(domain), domain, PH_COPY); } if (PHALCON_IS_NOT_EMPTY(secure)) { phalcon_array_update_str(&definition, SL("secure"), secure, PH_COPY); } if (PHALCON_IS_NOT_EMPTY(http_only)) { phalcon_array_update_str(&definition, SL("httpOnly"), http_only, PH_COPY); } /** * The definition is stored in session */ if (phalcon_fast_count_ev(&definition)) { PHALCON_CALL_METHODW(&session, dependency_injector, "getshared", &service); if (Z_TYPE(session) != IS_NULL) { PHALCON_VERIFY_INTERFACEW(&session, phalcon_session_adapterinterface_ce); PHALCON_CONCAT_SV(&key, "_PHCOOKIE_", name); PHALCON_CALL_METHODW(NULL, &session, "set", &key, &definition); } } } } phalcon_return_property(&encryption, getThis(), SL("_useEncryption")); if (zend_is_true(&encryption) && PHALCON_IS_NOT_EMPTY(value)) { if (Z_TYPE_P(dependency_injector) != IS_OBJECT) { PHALCON_THROW_EXCEPTION_STRW(phalcon_http_cookie_exception_ce, "A dependency injection object is required to access the 'filter' service"); return; } ZVAL_STRING(&service, "crypt"); PHALCON_CALL_METHODW(&crypt, dependency_injector, "getshared", &service); PHALCON_VERIFY_INTERFACEW(&crypt, phalcon_cryptinterface_ce); /** * Encrypt the value also coding it with base64 */ PHALCON_CALL_METHODW(&encrypt_value, &crypt, "encryptbase64", value); } else { PHALCON_CPY_WRT_CTOR(&encrypt_value, value); } /** * Sets the cookie using the standard 'setcookie' function */ convert_to_string_ex(name); convert_to_long_ex(expire); convert_to_string_ex(domain); convert_to_string_ex(path); convert_to_long_ex(secure); convert_to_long_ex(http_only); convert_to_string_ex(&encrypt_value); php_setcookie(Z_STR_P(name), Z_STR(encrypt_value), Z_LVAL_P(expire), Z_STR_P(path), Z_STR_P(domain), Z_LVAL_P(secure), 1, Z_LVAL_P(http_only)); RETURN_THISW(); }
static void binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, zval* return_value, HashTable* fieldspec) { ZVAL_NULL(return_value); switch (thrift_typeID) { case T_STOP: case T_VOID: RETURN_NULL(); return; case T_STRUCT: { zval* val_ptr = zend_hash_str_find(fieldspec, "class", sizeof("class")-1); if (val_ptr == nullptr) { throw_tprotocolexception("no class type in spec", INVALID_DATA); skip_element(T_STRUCT, transport); RETURN_NULL(); } char* structType = Z_STRVAL_P(val_ptr); // Create an object in PHP userland based on our spec createObject(structType, return_value); if (Z_TYPE_P(return_value) == IS_NULL) { // unable to create class entry skip_element(T_STRUCT, transport); RETURN_NULL(); } zval* spec = zend_read_static_property(Z_OBJCE_P(return_value), "_TSPEC", sizeof("_TSPEC")-1, false); if (Z_TYPE_P(spec) != IS_ARRAY) { char errbuf[128]; snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType, Z_TYPE_P(spec)); throw_tprotocolexception(errbuf, INVALID_DATA); RETURN_NULL(); } binary_deserialize_spec(return_value, transport, Z_ARRVAL_P(spec)); return; } break; case T_BOOL: { uint8_t c; transport.readBytes(&c, 1); RETURN_BOOL(c != 0); } //case T_I08: // same numeric value as T_BYTE case T_BYTE: { uint8_t c; transport.readBytes(&c, 1); RETURN_LONG((int8_t)c); } case T_I16: { uint16_t c; transport.readBytes(&c, 2); RETURN_LONG((int16_t)ntohs(c)); } case T_I32: { uint32_t c; transport.readBytes(&c, 4); RETURN_LONG((int32_t)ntohl(c)); } case T_U64: case T_I64: { uint64_t c; transport.readBytes(&c, 8); RETURN_LONG((int64_t)ntohll(c)); } case T_DOUBLE: { union { uint64_t c; double d; } a; transport.readBytes(&(a.c), 8); a.c = ntohll(a.c); RETURN_DOUBLE(a.d); } //case T_UTF7: // aliases T_STRING case T_UTF8: case T_UTF16: case T_STRING: { uint32_t size = transport.readU32(); if (size) { char strbuf[size+1]; transport.readBytes(strbuf, size); strbuf[size] = '\0'; ZVAL_STRINGL(return_value, strbuf, size); } else { ZVAL_EMPTY_STRING(return_value); } return; } case T_MAP: { // array of key -> value uint8_t types[2]; transport.readBytes(types, 2); uint32_t size = transport.readU32(); array_init(return_value); zval *val_ptr; val_ptr = zend_hash_str_find(fieldspec, "key", sizeof("key")-1); HashTable* keyspec = Z_ARRVAL_P(val_ptr); val_ptr = zend_hash_str_find(fieldspec, "val", sizeof("val")-1); HashTable* valspec = Z_ARRVAL_P(val_ptr); for (uint32_t s = 0; s < size; ++s) { zval key, value; binary_deserialize(types[0], transport, &key, keyspec); binary_deserialize(types[1], transport, &value, valspec); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); } else { if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); } zval_dtor(&key); } return; // return_value already populated } case T_LIST: { // array with autogenerated numeric keys int8_t type = transport.readI8(); uint32_t size = transport.readU32(); zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); HashTable* elemspec = Z_ARRVAL_P(val_ptr); array_init(return_value); for (uint32_t s = 0; s < size; ++s) { zval value; binary_deserialize(type, transport, &value, elemspec); zend_hash_next_index_insert(Z_ARR_P(return_value), &value); } return; } case T_SET: { // array of key -> TRUE uint8_t type; uint32_t size; transport.readBytes(&type, 1); transport.readBytes(&size, 4); size = ntohl(size); zval *val_ptr = zend_hash_str_find(fieldspec, "elem", sizeof("elem")-1); HashTable* elemspec = Z_ARRVAL_P(val_ptr); array_init(return_value); for (uint32_t s = 0; s < size; ++s) { zval key, value; ZVAL_TRUE(&value); binary_deserialize(type, transport, &key, elemspec); if (Z_TYPE(key) == IS_LONG) { zend_hash_index_update(Z_ARR_P(return_value), Z_LVAL(key), &value); } else { if (Z_TYPE(key) != IS_STRING) convert_to_string(&key); zend_symtable_update(Z_ARR_P(return_value), Z_STR(key), &value); } zval_dtor(&key); } return; } }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(errbuf, INVALID_DATA); }
void zend_optimizer_update_op2_const(zend_op_array *op_array, zend_op *opline, zval *val) { ZEND_OP2_TYPE(opline) = IS_CONST; if (opline->opcode == ZEND_INIT_FCALL) { zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); opline->op2.constant = zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline))); Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size; op_array->cache_size += sizeof(void*); return; } else if (opline->opcode == ZEND_ROPE_INIT || opline->opcode == ZEND_ROPE_ADD || opline->opcode == ZEND_ROPE_END || opline->opcode == ZEND_CONCAT || opline->opcode == ZEND_FAST_CONCAT) { convert_to_string(val); } opline->op2.constant = zend_optimizer_add_literal(op_array, val); if (Z_TYPE_P(val) == IS_STRING) { zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline))); switch (opline->opcode) { case ZEND_FETCH_CLASS: case ZEND_INIT_FCALL_BY_NAME: /*case ZEND_INIT_NS_FCALL_BY_NAME:*/ case ZEND_ADD_INTERFACE: case ZEND_ADD_TRAIT: case ZEND_INSTANCEOF: case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: case ZEND_FETCH_STATIC_PROP_IS: case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: case ZEND_ISSET_ISEMPTY_STATIC_PROP: Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size; op_array->cache_size += sizeof(void*); zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); break; case ZEND_INIT_DYNAMIC_CALL: opline->opcode = ZEND_INIT_FCALL_BY_NAME; Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size; op_array->cache_size += sizeof(void*); zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); break; case ZEND_INIT_METHOD_CALL: case ZEND_INIT_STATIC_METHOD_CALL: zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val)); zend_optimizer_add_literal(op_array, val); zend_string_hash_val(Z_STR(op_array->literals[opline->op2.constant+1])); /* break missing intentionally */ /*case ZEND_FETCH_CLASS_CONSTANT:*/ case ZEND_ASSIGN_OBJ: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_IS: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_UNSET_OBJ: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: case ZEND_POST_INC_OBJ: case ZEND_POST_DEC_OBJ: case ZEND_ISSET_ISEMPTY_PROP_OBJ: Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size; op_array->cache_size += 2 * sizeof(void*); break; case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: case ZEND_ASSIGN_DIV: case ZEND_ASSIGN_POW: case ZEND_ASSIGN_MOD: case ZEND_ASSIGN_SL: case ZEND_ASSIGN_SR: case ZEND_ASSIGN_CONCAT: case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: if (opline->extended_value == ZEND_ASSIGN_OBJ) { Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size; op_array->cache_size += 2 * sizeof(void*); } break; case ZEND_OP_DATA: if ((opline-1)->opcode == ZEND_ASSIGN_DIM || ((opline-1)->extended_value == ZEND_ASSIGN_DIM && ((opline-1)->opcode == ZEND_ASSIGN_ADD || (opline-1)->opcode == ZEND_ASSIGN_SUB || (opline-1)->opcode == ZEND_ASSIGN_MUL || (opline-1)->opcode == ZEND_ASSIGN_DIV || (opline-1)->opcode == ZEND_ASSIGN_POW || (opline-1)->opcode == ZEND_ASSIGN_MOD || (opline-1)->opcode == ZEND_ASSIGN_SL || (opline-1)->opcode == ZEND_ASSIGN_SR || (opline-1)->opcode == ZEND_ASSIGN_CONCAT || (opline-1)->opcode == ZEND_ASSIGN_BW_OR || (opline-1)->opcode == ZEND_ASSIGN_BW_AND || (opline-1)->opcode == ZEND_ASSIGN_BW_XOR))) { goto check_numeric; } break; case ZEND_ISSET_ISEMPTY_DIM_OBJ: case ZEND_ADD_ARRAY_ELEMENT: case ZEND_INIT_ARRAY: case ZEND_ASSIGN_DIM: case ZEND_UNSET_DIM: case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_IS: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: case ZEND_FETCH_LIST: check_numeric: { zend_ulong index; if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) { zval_dtor(val); ZVAL_LONG(val, index); op_array->literals[opline->op2.constant] = *val; } } break; default: break; } } }
void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx) { zend_op *opline, *end; int i, j, n, *map, cache_size; zval zv, *pos; literal_info *info; int l_null = -1; int l_false = -1; int l_true = -1; int l_empty_arr = -1; HashTable hash; zend_string *key = NULL; void *checkpoint = zend_arena_checkpoint(ctx->arena); int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot; if (op_array->last_literal) { info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info)); /* Mark literals of specific types */ opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { switch (opline->opcode) { case ZEND_INIT_FCALL: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1); break; case ZEND_INIT_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 2); break; case ZEND_INIT_NS_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 3); break; case ZEND_INIT_METHOD_CALL: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1); } if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_METHOD, 2); } break; case ZEND_INIT_STATIC_METHOD_CALL: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2); } if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_STATIC_METHOD, 2); } break; case ZEND_CATCH: LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2); break; case ZEND_DEFINED: LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 2); break; case ZEND_FETCH_CONSTANT: if ((opline->op1.num & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) { LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 5); } else { LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 3); } break; case ZEND_FETCH_CLASS_CONSTANT: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2); } LITERAL_INFO(opline->op2.constant, LITERAL_CLASS_CONST, 1); break; case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: case ZEND_FETCH_STATIC_PROP_IS: case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: case ZEND_ISSET_ISEMPTY_STATIC_PROP: if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2); } if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_STATIC_PROPERTY, 1); } break; case ZEND_FETCH_CLASS: case ZEND_INSTANCEOF: if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2); } break; case ZEND_NEW: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 2); } break; case ZEND_ASSIGN_OBJ: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_IS: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_UNSET_OBJ: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: case ZEND_POST_INC_OBJ: case ZEND_POST_DEC_OBJ: case ZEND_ISSET_ISEMPTY_PROP_OBJ: if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1); } break; case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: case ZEND_ASSIGN_DIV: case ZEND_ASSIGN_POW: case ZEND_ASSIGN_MOD: case ZEND_ASSIGN_SL: case ZEND_ASSIGN_SR: case ZEND_ASSIGN_CONCAT: case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: if (opline->op2_type == IS_CONST) { if (opline->extended_value == ZEND_ASSIGN_OBJ) { LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1); } else if (opline->extended_value == ZEND_ASSIGN_DIM) { if (Z_EXTRA(op_array->literals[opline->op2.constant]) == ZEND_EXTRA_VALUE) { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 2); } else { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); } } else { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); } } break; case ZEND_BIND_GLOBAL: LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 1); break; case ZEND_RECV_INIT: LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); break; case ZEND_DECLARE_FUNCTION: case ZEND_DECLARE_CLASS: LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2); break; case ZEND_DECLARE_INHERITED_CLASS: case ZEND_DECLARE_INHERITED_CLASS_DELAYED: LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 2); LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 2); break; case ZEND_DECLARE_ANON_INHERITED_CLASS: LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1); LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 2); break; case ZEND_ISSET_ISEMPTY_DIM_OBJ: case ZEND_ASSIGN_DIM: case ZEND_UNSET_DIM: case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_IS: case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_DIM_UNSET: case ZEND_FETCH_LIST_R: case ZEND_FETCH_LIST_W: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1); } if (opline->op2_type == IS_CONST) { if (Z_EXTRA(op_array->literals[opline->op2.constant]) == ZEND_EXTRA_VALUE) { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 2); } else { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); } } break; default: if (opline->op1_type == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1); } if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1); } break; } opline++; } #if DEBUG_COMPACT_LITERALS { int i, use_copy; fprintf(stderr, "File %s func %s\n", op_array->filename->val, op_array->function_name ? op_array->function_name->val : "main"); fprintf(stderr, "Literlas table size %d\n", op_array->last_literal); for (i = 0; i < op_array->last_literal; i++) { zval zv; ZVAL_COPY_VALUE(&zv, op_array->literals + i); use_copy = zend_make_printable_zval(op_array->literals + i, &zv); fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv)); if (use_copy) { zval_ptr_dtor_nogc(&zv); } } fflush(stderr); } #endif /* Merge equal constants */ j = 0; zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0); map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int)); memset(map, 0, op_array->last_literal * sizeof(int)); for (i = 0; i < op_array->last_literal; i++) { if (!info[i].flags) { /* unset literal */ zval_ptr_dtor_nogc(&op_array->literals[i]); continue; } switch (Z_TYPE(op_array->literals[i])) { case IS_NULL: if (l_null < 0) { l_null = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } map[i] = l_null; break; case IS_FALSE: if (l_false < 0) { l_false = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } map[i] = l_false; break; case IS_TRUE: if (l_true < 0) { l_true = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } map[i] = l_true; break; case IS_LONG: if (LITERAL_NUM_RELATED(info[i].flags) == 1) { if ((pos = zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i]))) != NULL) { map[i] = Z_LVAL_P(pos); } else { map[i] = j; ZVAL_LONG(&zv, j); zend_hash_index_add_new(&hash, Z_LVAL(op_array->literals[i]), &zv); if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } } else { ZEND_ASSERT(LITERAL_NUM_RELATED(info[i].flags) == 2); key = zend_string_init(Z_STRVAL(op_array->literals[i+1]), Z_STRLEN(op_array->literals[i+1]), 0); ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i+1])) + 100 + LITERAL_NUM_RELATED(info[i].flags) - 1; if ((pos = zend_hash_find(&hash, key)) != NULL && LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) == 2) { map[i] = Z_LVAL_P(pos); zval_ptr_dtor_nogc(&op_array->literals[i+1]); } else { map[i] = j; ZVAL_LONG(&zv, j); zend_hash_add_new(&hash, key, &zv); if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; op_array->literals[j+1] = op_array->literals[i+1]; info[j+1] = info[i+1]; } j += 2; } zend_string_release_ex(key, 0); i++; } break; case IS_DOUBLE: if ((pos = zend_hash_str_find(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double))) != NULL) { map[i] = Z_LVAL_P(pos); } else { map[i] = j; ZVAL_LONG(&zv, j); zend_hash_str_add(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double), &zv); if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } break; case IS_STRING: if (LITERAL_NUM_RELATED(info[i].flags) == 1) { key = zend_string_copy(Z_STR(op_array->literals[i])); } else { key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0); ZSTR_H(key) = ZSTR_HASH(Z_STR(op_array->literals[i])) + LITERAL_NUM_RELATED(info[i].flags) - 1; } pos = zend_hash_find(&hash, key); if (pos != NULL && Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) == IS_STRING && LITERAL_NUM_RELATED(info[i].flags) == LITERAL_NUM_RELATED(info[Z_LVAL_P(pos)].flags) && (LITERAL_NUM_RELATED(info[i].flags) != 2 || ((info[i].flags & LITERAL_KIND_MASK) != LITERAL_VALUE && (info[Z_LVAL_P(pos)].flags & LITERAL_KIND_MASK) != LITERAL_VALUE))) { zend_string_release_ex(key, 0); map[i] = Z_LVAL_P(pos); zval_ptr_dtor_nogc(&op_array->literals[i]); n = LITERAL_NUM_RELATED(info[i].flags); while (n > 1) { i++; zval_ptr_dtor_nogc(&op_array->literals[i]); n--; } } else { map[i] = j; ZVAL_LONG(&zv, j); zend_hash_add_new(&hash, key, &zv); zend_string_release_ex(key, 0); if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; n = LITERAL_NUM_RELATED(info[i].flags); while (n > 1) { i++; if (i != j) op_array->literals[j] = op_array->literals[i]; j++; n--; } } break; case IS_ARRAY: if (zend_hash_num_elements(Z_ARRVAL(op_array->literals[i])) == 0) { if (l_empty_arr < 0) { l_empty_arr = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } else { zval_ptr_dtor_nogc(&op_array->literals[i]); } map[i] = l_empty_arr; break; } /* break missing intentionally */ default: /* don't merge other types */ map[i] = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; break; } } zend_hash_clean(&hash); op_array->last_literal = j; const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int)); memset(const_slot, -1, j * 6 * sizeof(int)); class_slot = const_slot + j; func_slot = class_slot + j; bind_var_slot = func_slot + j; property_slot = bind_var_slot + j; method_slot = property_slot + j; /* Update opcodes to use new literals table */ cache_size = 0; opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { if (opline->op1_type == IS_CONST) { opline->op1.constant = map[opline->op1.constant]; } if (opline->op2_type == IS_CONST) { opline->op2.constant = map[opline->op2.constant]; } switch (opline->opcode) { case ZEND_RECV_INIT: if (class_name_type_hint(op_array, opline->op1.num)) { opline->extended_value = cache_size; cache_size += sizeof(void *); } break; case ZEND_RECV: case ZEND_RECV_VARIADIC: if (class_name_type_hint(op_array, opline->op1.num)) { opline->op2.num = cache_size; cache_size += sizeof(void *); } break; case ZEND_VERIFY_RETURN_TYPE: if (class_name_type_hint(op_array, 0)) { opline->op2.num = cache_size; cache_size += sizeof(void *); } break; case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: case ZEND_ASSIGN_DIV: case ZEND_ASSIGN_POW: case ZEND_ASSIGN_MOD: case ZEND_ASSIGN_SL: case ZEND_ASSIGN_SR: case ZEND_ASSIGN_CONCAT: case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: if (opline->extended_value != ZEND_ASSIGN_OBJ) { break; } if (opline->op2_type == IS_CONST) { // op2 property if (opline->op1_type == IS_UNUSED && property_slot[opline->op2.constant] >= 0) { (opline+1)->extended_value = property_slot[opline->op2.constant]; } else { (opline+1)->extended_value = cache_size; cache_size += 2 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { property_slot[opline->op2.constant] = (opline+1)->extended_value; } } } break; case ZEND_ASSIGN_OBJ: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_IS: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_UNSET_OBJ: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: case ZEND_POST_INC_OBJ: case ZEND_POST_DEC_OBJ: if (opline->op2_type == IS_CONST) { // op2 property if (opline->op1_type == IS_UNUSED && property_slot[opline->op2.constant] >= 0) { opline->extended_value = property_slot[opline->op2.constant]; } else { opline->extended_value = cache_size; cache_size += 2 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { property_slot[opline->op2.constant] = opline->extended_value; } } } break; case ZEND_ISSET_ISEMPTY_PROP_OBJ: if (opline->op2_type == IS_CONST) { // op2 property if (opline->op1_type == IS_UNUSED && property_slot[opline->op2.constant] >= 0) { opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY); } else { opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); cache_size += 2 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY; } } } break; case ZEND_INIT_FCALL: case ZEND_INIT_FCALL_BY_NAME: case ZEND_INIT_NS_FCALL_BY_NAME: // op2 func if (func_slot[opline->op2.constant] >= 0) { opline->result.num = func_slot[opline->op2.constant]; } else { opline->result.num = cache_size; cache_size += sizeof(void *); func_slot[opline->op2.constant] = opline->result.num; } break; case ZEND_INIT_METHOD_CALL: if (opline->op2_type == IS_CONST) { // op2 method if (opline->op1_type == IS_UNUSED && method_slot[opline->op2.constant] >= 0) { opline->result.num = method_slot[opline->op2.constant]; } else { opline->result.num = cache_size; cache_size += 2 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { method_slot[opline->op2.constant] = opline->result.num; } } } break; case ZEND_INIT_STATIC_METHOD_CALL: if (opline->op2_type == IS_CONST) { // op2 static method if (opline->op1_type == IS_CONST) { opline->result.num = add_static_slot(&hash, op_array, opline->op1.constant, opline->op2.constant, LITERAL_STATIC_METHOD, &cache_size); } else { opline->result.num = cache_size; cache_size += 2 * sizeof(void *); } } else if (opline->op1_type == IS_CONST) { // op1 class if (class_slot[opline->op1.constant] >= 0) { opline->result.num = class_slot[opline->op1.constant]; } else { opline->result.num = cache_size; cache_size += sizeof(void *); class_slot[opline->op1.constant] = opline->result.num; } } break; case ZEND_DEFINED: // op1 const if (const_slot[opline->op1.constant] >= 0) { opline->extended_value = const_slot[opline->op1.constant]; } else { opline->extended_value = cache_size; cache_size += sizeof(void *); const_slot[opline->op1.constant] = opline->extended_value; } break; case ZEND_FETCH_CONSTANT: // op2 const if (const_slot[opline->op2.constant] >= 0) { opline->extended_value = const_slot[opline->op2.constant]; } else { opline->extended_value = cache_size; cache_size += sizeof(void *); const_slot[opline->op2.constant] = opline->extended_value; } break; case ZEND_FETCH_CLASS_CONSTANT: if (opline->op1_type == IS_CONST) { // op1/op2 class_const opline->extended_value = add_static_slot(&hash, op_array, opline->op1.constant, opline->op2.constant, LITERAL_CLASS_CONST, &cache_size); } else { opline->extended_value = cache_size; cache_size += 2 * sizeof(void *); } break; case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: case ZEND_FETCH_STATIC_PROP_IS: case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: if (opline->op1_type == IS_CONST) { // op1 static property if (opline->op2_type == IS_CONST) { opline->extended_value = add_static_slot(&hash, op_array, opline->op2.constant, opline->op1.constant, LITERAL_STATIC_PROPERTY, &cache_size); } else { opline->extended_value = cache_size; cache_size += 2 * sizeof(void *); } } else if (opline->op2_type == IS_CONST) { // op2 class if (class_slot[opline->op2.constant] >= 0) { opline->extended_value = class_slot[opline->op2.constant]; } else { opline->extended_value = cache_size; cache_size += sizeof(void *); class_slot[opline->op2.constant] = opline->extended_value; } } break; case ZEND_ISSET_ISEMPTY_STATIC_PROP: if (opline->op1_type == IS_CONST) { // op1 static property if (opline->op2_type == IS_CONST) { opline->extended_value = add_static_slot(&hash, op_array, opline->op2.constant, opline->op1.constant, LITERAL_STATIC_PROPERTY, &cache_size) | (opline->extended_value & ZEND_ISEMPTY); } else { opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); cache_size += 2 * sizeof(void *); } } else if (opline->op2_type == IS_CONST) { // op2 class if (class_slot[opline->op2.constant] >= 0) { opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY); } else { opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); cache_size += sizeof(void *); class_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY; } } break; case ZEND_FETCH_CLASS: case ZEND_INSTANCEOF: if (opline->op2_type == IS_CONST) { // op2 class if (class_slot[opline->op2.constant] >= 0) { opline->extended_value = class_slot[opline->op2.constant]; } else { opline->extended_value = cache_size; cache_size += sizeof(void *); class_slot[opline->op2.constant] = opline->extended_value; } } break; case ZEND_NEW: if (opline->op1_type == IS_CONST) { // op1 class if (class_slot[opline->op1.constant] >= 0) { opline->op2.num = class_slot[opline->op1.constant]; } else { opline->op2.num = cache_size; cache_size += sizeof(void *); class_slot[opline->op1.constant] = opline->op2.num; } } break; case ZEND_CATCH: if (opline->op1_type == IS_CONST) { // op1 class if (class_slot[opline->op1.constant] >= 0) { opline->extended_value = class_slot[opline->op1.constant] | (opline->extended_value & ZEND_LAST_CATCH); } else { opline->extended_value = cache_size | (opline->extended_value & ZEND_LAST_CATCH); cache_size += sizeof(void *); class_slot[opline->op1.constant] = opline->extended_value & ~ZEND_LAST_CATCH; } } break; case ZEND_BIND_GLOBAL: // op2 bind var if (bind_var_slot[opline->op2.constant] >= 0) { opline->extended_value = bind_var_slot[opline->op2.constant]; } else { opline->extended_value = cache_size; cache_size += sizeof(void *); bind_var_slot[opline->op2.constant] = opline->extended_value; } break; } opline++; } op_array->cache_size = cache_size; zend_hash_destroy(&hash); zend_arena_release(&ctx->arena, checkpoint); if (1) { opline = op_array->opcodes; while (1) { if (opline->opcode == ZEND_RECV_INIT) { zval *val = &op_array->literals[opline->op2.constant]; if (Z_TYPE_P(val) == IS_CONSTANT_AST) { uint32_t slot = ZEND_MM_ALIGNED_SIZE_EX(op_array->cache_size, 8); Z_CACHE_SLOT_P(val) = slot; op_array->cache_size += sizeof(zval); } } else if (opline->opcode != ZEND_RECV) { break; } opline++; } } #if DEBUG_COMPACT_LITERALS { int i, use_copy; fprintf(stderr, "Optimized literlas table size %d\n", op_array->last_literal); for (i = 0; i < op_array->last_literal; i++) { zval zv; ZVAL_COPY_VALUE(&zv, op_array->literals + i); use_copy = zend_make_printable_zval(op_array->literals + i, &zv); fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv)); if (use_copy) { zval_ptr_dtor_nogc(&zv); } } fflush(stderr); } #endif } }
/* {{{ zend_call_method Only returns the returned zval if retval_ptr != NULL */ ZEND_API zval* zend_call_method(zval *object, zend_class_entry *obj_ce, zend_function **fn_proxy, const char *function_name, size_t function_name_len, zval *retval_ptr, int param_count, zval* arg1, zval* arg2) { int result; zend_fcall_info fci; zval retval; HashTable *function_table; zval params[2]; if (param_count > 0) { ZVAL_COPY_VALUE(¶ms[0], arg1); } if (param_count > 1) { ZVAL_COPY_VALUE(¶ms[1], arg2); } fci.size = sizeof(fci); /*fci.function_table = NULL; will be read form zend_class_entry of object if needed */ fci.object = (object && Z_TYPE_P(object) == IS_OBJECT) ? Z_OBJ_P(object) : NULL; ZVAL_STRINGL(&fci.function_name, function_name, function_name_len); fci.retval = retval_ptr ? retval_ptr : &retval; fci.param_count = param_count; fci.params = params; fci.no_separation = 1; fci.symbol_table = NULL; if (!fn_proxy && !obj_ce) { /* no interest in caching and no information already present that is * needed later inside zend_call_function. */ fci.function_table = !object ? EG(function_table) : NULL; result = zend_call_function(&fci, NULL); zval_ptr_dtor(&fci.function_name); } else { zend_fcall_info_cache fcic; fcic.initialized = 1; if (!obj_ce) { obj_ce = object ? Z_OBJCE_P(object) : NULL; } if (obj_ce) { function_table = &obj_ce->function_table; } else { function_table = EG(function_table); } if (!fn_proxy || !*fn_proxy) { if ((fcic.function_handler = zend_hash_find_ptr(function_table, Z_STR(fci.function_name))) == NULL) { /* error at c-level */ zend_error_noreturn(E_CORE_ERROR, "Couldn't find implementation for method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name); } if (fn_proxy) { *fn_proxy = fcic.function_handler; } } else { fcic.function_handler = *fn_proxy; } fcic.calling_scope = obj_ce; if (object) { fcic.called_scope = Z_OBJCE_P(object); } else { zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data)); if (obj_ce && (!called_scope || !instanceof_function(called_scope, obj_ce))) { fcic.called_scope = obj_ce; } else { fcic.called_scope = called_scope; } } fcic.object = object ? Z_OBJ_P(object) : NULL; result = zend_call_function(&fci, &fcic); zval_ptr_dtor(&fci.function_name); } if (result == FAILURE) { /* error at c-level */ if (!obj_ce) { obj_ce = object ? Z_OBJCE_P(object) : NULL; } if (!EG(exception)) { zend_error_noreturn(E_CORE_ERROR, "Couldn't execute method %s%s%s", obj_ce ? obj_ce->name->val : "", obj_ce ? "::" : "", function_name); } } /* copy arguments back, they might be changed by references */ if (param_count > 0 && Z_ISREF(params[0]) && !Z_ISREF_P(arg1)) { ZVAL_COPY_VALUE(arg1, ¶ms[0]); } if (param_count > 1 && Z_ISREF(params[1]) && !Z_ISREF_P(arg2)) { ZVAL_COPY_VALUE(arg2, ¶ms[1]); } if (!retval_ptr) { zval_ptr_dtor(&retval); return NULL; } return retval_ptr; }
static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { while (elements-- > 0) { zval key, *data, d, *old_data; ZVAL_UNDEF(&key); if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { zval_dtor(&key); return 0; } if (Z_TYPE(key) != IS_LONG && Z_TYPE(key) != IS_STRING) { zval_dtor(&key); return 0; } data = NULL; ZVAL_UNDEF(&d); if (!objprops) { switch (Z_TYPE(key)) { case IS_LONG: if ((old_data = zend_hash_index_find(ht, Z_LVAL(key))) != NULL) { //??? update hash var_push_dtor(var_hash, old_data); } data = zend_hash_index_update(ht, Z_LVAL(key), &d); break; case IS_STRING: if ((old_data = zend_symtable_find(ht, Z_STR(key))) != NULL) { //??? update hash var_push_dtor(var_hash, old_data); } data = zend_symtable_update(ht, Z_STR(key), &d); break; } } else { /* object properties should include no integers */ convert_to_string(&key); //??? #if 1 data = zend_hash_update_ind(ht, Z_STR(key), &d); #else if ((data = zend_hash_find(ht, Z_STR(key))) != NULL) { if (Z_TYPE_P(data) == IS_INDIRECT) { data = Z_INDIRECT_P(data); } zval_ptr_dtor(data); //??? var_push_dtor(var_hash, data); ZVAL_UNDEF(data); } else { data = zend_hash_update(ht, Z_STR(key), &d); } #endif } zval_dtor(&key); if (!php_var_unserialize(data, p, max, var_hash TSRMLS_CC)) { return 0; } if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; return 0; } } return 1; }
/* {{{ php_build_argv */ static void php_build_argv(char *s, zval *track_vars_array) { zval arr, argc, tmp; int count = 0; char *ss, *space; if (!(SG(request_info).argc || track_vars_array)) { return; } array_init(&arr); /* Prepare argv */ if (SG(request_info).argc) { /* are we in cli sapi? */ int i; for (i = 0; i < SG(request_info).argc; i++) { ZVAL_STRING(&tmp, SG(request_info).argv[i]); if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) { zend_string_free(Z_STR(tmp)); } } } else if (s && *s) { ss = s; while (ss) { space = strchr(ss, '+'); if (space) { *space = '\0'; } /* auto-type */ ZVAL_STRING(&tmp, ss); count++; if (zend_hash_next_index_insert(Z_ARRVAL(arr), &tmp) == NULL) { zend_string_free(Z_STR(tmp)); } if (space) { *space = '+'; ss = space + 1; } else { ss = space; } } } /* prepare argc */ if (SG(request_info).argc) { ZVAL_LONG(&argc, SG(request_info).argc); } else { ZVAL_LONG(&argc, count); } if (SG(request_info).argc) { Z_ADDREF(arr); zend_hash_str_update(&EG(symbol_table), "argv", sizeof("argv")-1, &arr); zend_hash_str_add(&EG(symbol_table), "argc", sizeof("argc")-1, &argc); } if (track_vars_array && Z_TYPE_P(track_vars_array) == IS_ARRAY) { Z_ADDREF(arr); zend_hash_str_update(Z_ARRVAL_P(track_vars_array), "argv", sizeof("argv")-1, &arr); zend_hash_str_update(Z_ARRVAL_P(track_vars_array), "argc", sizeof("argc")-1, &argc); } zval_ptr_dtor(&arr); }
static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { while (elements-- > 0) { zval key, *data, d, *old_data; zend_ulong idx; ZVAL_UNDEF(&key); if (!php_var_unserialize_internal(&key, p, max, NULL)) { zval_ptr_dtor(&key); return 0; } data = NULL; ZVAL_UNDEF(&d); if (!objprops) { if (Z_TYPE(key) == IS_LONG) { idx = Z_LVAL(key); numeric_key: if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) { //??? update hash var_push_dtor(var_hash, old_data); data = zend_hash_index_update(ht, idx, &d); } else { data = zend_hash_index_add_new(ht, idx, &d); } } else if (Z_TYPE(key) == IS_STRING) { if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) { goto numeric_key; } if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) { //??? update hash var_push_dtor(var_hash, old_data); data = zend_hash_update(ht, Z_STR(key), &d); } else { data = zend_hash_add_new(ht, Z_STR(key), &d); } } else { zval_ptr_dtor(&key); return 0; } } else { if (EXPECTED(Z_TYPE(key) == IS_STRING)) { string_key: { zend_property_info *existing_propinfo; zend_string *new_key, *unmangled; const char *unmangled_class = NULL; const char *unmangled_prop; size_t unmangled_prop_len; if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) { zval_ptr_dtor(&key); return 0; } unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); if (Z_TYPE_P(rval) == IS_OBJECT && ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { new_key = zend_mangle_property_name( "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); zend_string_release(unmangled); } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { new_key = zend_mangle_property_name( unmangled_class, strlen(unmangled_class), ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); } else { new_key = zend_mangle_property_name( ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); } zend_string_release(unmangled); } else { ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC); new_key = unmangled; } zend_string_release(Z_STR(key)); ZVAL_STR(&key, new_key); } else { zend_string_release(unmangled); } if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { if (Z_TYPE_P(old_data) == IS_INDIRECT) { old_data = Z_INDIRECT_P(old_data); } var_push_dtor(var_hash, old_data); data = zend_hash_update_ind(ht, Z_STR(key), &d); } else { data = zend_hash_add_new(ht, Z_STR(key), &d); } } } else if (Z_TYPE(key) == IS_LONG) { /* object properties should include no integers */ convert_to_string(&key); goto string_key; } else { zval_ptr_dtor(&key); return 0; } } if (!php_var_unserialize_internal(data, p, max, var_hash)) { zval_ptr_dtor(&key); return 0; } var_push_dtor(var_hash, data); zval_ptr_dtor(&key); if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; return 0; } } return 1; }
ZEND_API void zend_highlight(zend_syntax_highlighter_ini *syntax_highlighter_ini) { zval token; int token_type; char *last_color = syntax_highlighter_ini->highlight_html; char *next_color; zend_printf("<code>"); zend_printf("<span style=\"color: %s\">\n", last_color); /* highlight stuff coming back from zendlex() */ ZVAL_UNDEF(&token); while ((token_type=lex_scan(&token))) { switch (token_type) { case T_INLINE_HTML: next_color = syntax_highlighter_ini->highlight_html; break; case T_COMMENT: case T_DOC_COMMENT: next_color = syntax_highlighter_ini->highlight_comment; break; case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: case T_CLOSE_TAG: case T_LINE: case T_FILE: case T_DIR: case T_TRAIT_C: case T_METHOD_C: case T_FUNC_C: case T_NS_C: case T_CLASS_C: next_color = syntax_highlighter_ini->highlight_default; break; case '"': case T_ENCAPSED_AND_WHITESPACE: case T_CONSTANT_ENCAPSED_STRING: next_color = syntax_highlighter_ini->highlight_string; break; case T_WHITESPACE: zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); /* no color needed */ ZVAL_UNDEF(&token); continue; break; default: if (Z_TYPE(token) == IS_UNDEF) { next_color = syntax_highlighter_ini->highlight_keyword; } else { next_color = syntax_highlighter_ini->highlight_default; } break; } if (last_color != next_color) { if (last_color != syntax_highlighter_ini->highlight_html) { zend_printf("</span>"); } last_color = next_color; if (last_color != syntax_highlighter_ini->highlight_html) { zend_printf("<span style=\"color: %s\">", last_color); } } zend_html_puts((char*)LANG_SCNG(yy_text), LANG_SCNG(yy_leng)); if (Z_TYPE(token) == IS_STRING) { switch (token_type) { case T_OPEN_TAG: case T_OPEN_TAG_WITH_ECHO: case T_CLOSE_TAG: case T_WHITESPACE: case T_COMMENT: case T_DOC_COMMENT: break; default: zend_string_release(Z_STR(token)); break; } } ZVAL_UNDEF(&token); } if (last_color != syntax_highlighter_ini->highlight_html) { zend_printf("</span>\n"); } zend_printf("</span>\n"); zend_printf("</code>"); /* Discard parse errors thrown during tokenization */ zend_clear_exception(); }
void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) { int i = 0; zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; zend_bool collect_constants = (ZEND_OPTIMIZER_PASS_15 & ctx->optimization_level)? (op_array == &ctx->script->main_op_array) : 0; while (opline < end) { switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_POW: case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: case ZEND_FAST_CONCAT: case ZEND_IS_EQUAL: case ZEND_IS_NOT_EQUAL: case ZEND_IS_SMALLER: case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_IS_IDENTICAL: case ZEND_IS_NOT_IDENTICAL: case ZEND_BW_OR: case ZEND_BW_AND: case ZEND_BW_XOR: case ZEND_BOOL_XOR: case ZEND_SPACESHIP: case ZEND_CASE: if (opline->op1_type == IS_CONST && opline->op2_type == IS_CONST) { /* binary operation with constant operands */ zval result; if (zend_optimizer_eval_binary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)) == SUCCESS) { literal_dtor(&ZEND_OP1_LITERAL(opline)); literal_dtor(&ZEND_OP2_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &result); } } } break; case ZEND_CAST: if (opline->op1_type == IS_CONST) { /* cast of constant operand */ zval result; if (zend_optimizer_eval_cast(&result, opline->extended_value, &ZEND_OP1_LITERAL(opline)) == SUCCESS) { literal_dtor(&ZEND_OP1_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline + 1, opline->result_type, opline->result.var, &result)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; zend_optimizer_update_op1_const(op_array, opline, &result); } break; } } if (opline->extended_value == _IS_BOOL) { /* T = CAST(X, IS_BOOL) => T = BOOL(X) */ opline->opcode = ZEND_BOOL; opline->extended_value = 0; } break; case ZEND_BW_NOT: case ZEND_BOOL_NOT: if (opline->op1_type == IS_CONST) { /* unary operation on constant operand */ zval result; if (zend_optimizer_eval_unary_op(&result, opline->opcode, &ZEND_OP1_LITERAL(opline)) == SUCCESS) { literal_dtor(&ZEND_OP1_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &result)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; zend_optimizer_update_op1_const(op_array, opline, &result); } } } break; case ZEND_FETCH_CONSTANT: if (opline->op2_type == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING && Z_STRLEN(ZEND_OP2_LITERAL(opline)) == sizeof("__COMPILER_HALT_OFFSET__") - 1 && memcmp(Z_STRVAL(ZEND_OP2_LITERAL(opline)), "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) { /* substitute __COMPILER_HALT_OFFSET__ constant */ zend_execute_data *orig_execute_data = EG(current_execute_data); zend_execute_data fake_execute_data; zval *offset; memset(&fake_execute_data, 0, sizeof(zend_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) { literal_dtor(&ZEND_OP2_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, offset)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, offset); } } EG(current_execute_data) = orig_execute_data; break; } if (opline->op2_type == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { /* substitute persistent constants */ zval c; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP2_LITERAL(opline)), &c, 1)) { if (!ctx->constants || !zend_optimizer_get_collected_constant(ctx->constants, &ZEND_OP2_LITERAL(opline), &c)) { break; } } if (Z_TYPE(c) == IS_CONSTANT_AST) { break; } literal_dtor(&ZEND_OP2_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &c); } } break; case ZEND_FETCH_CLASS_CONSTANT: if (opline->op2_type == IS_CONST && Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { zend_class_entry *ce = NULL; if (opline->op1_type == IS_CONST && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) { /* for A::B */ if (op_array->scope && !strncasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), ZSTR_VAL(op_array->scope->name), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1)) { ce = op_array->scope; } else { if ((ce = zend_hash_find_ptr(EG(class_table), Z_STR(op_array->literals[opline->op1.constant + 1]))) == NULL || (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->type != MODULE_PERSISTENT) || (ce->type == ZEND_USER_CLASS && ce->info.user.filename != op_array->filename)) { break; } } } else if (op_array->scope && opline->op1_type == IS_UNUSED && (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) { /* for self::B */ ce = op_array->scope; } else if (op_array->scope && opline->op1_type == IS_VAR && (opline - 1)->opcode == ZEND_FETCH_CLASS && ((opline - 1)->op2_type == IS_UNUSED && ((opline - 1)->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF) && (opline - 1)->result.var == opline->op1.var) { /* for self::B */ ce = op_array->scope; } if (ce) { zend_class_constant *cc; zval *c, t; if ((cc = zend_hash_find_ptr(&ce->constants_table, Z_STR(ZEND_OP2_LITERAL(opline)))) != NULL && (Z_ACCESS_FLAGS(cc->value) & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) { c = &cc->value; if (Z_TYPE_P(c) == IS_CONSTANT_AST) { zend_ast *ast = Z_ASTVAL_P(c); if (ast->kind != ZEND_AST_CONSTANT || !zend_optimizer_get_persistent_constant(zend_ast_get_constant_name(ast), &t, 1) || Z_TYPE(t) == IS_CONSTANT_AST) { break; } } else { ZVAL_COPY_OR_DUP(&t, c); } if (opline->op1_type == IS_CONST) { literal_dtor(&ZEND_OP1_LITERAL(opline)); } else if (opline->op1_type == IS_VAR) { MAKE_NOP((opline - 1)); } literal_dtor(&ZEND_OP2_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &t); } } } } break; case ZEND_DO_ICALL: { zend_op *send1_opline = opline - 1; zend_op *send2_opline = NULL; zend_op *init_opline = NULL; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || send1_opline->op1_type != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } if (send1_opline->op2.num == 2) { send2_opline = send1_opline; send1_opline--; while (send1_opline->opcode == ZEND_NOP) { send1_opline--; } if (send1_opline->opcode != ZEND_SEND_VAL || send1_opline->op1_type != IS_CONST) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } } init_opline = send1_opline - 1; while (init_opline->opcode == ZEND_NOP) { init_opline--; } if (init_opline->opcode != ZEND_INIT_FCALL || init_opline->op2_type != IS_CONST || Z_TYPE(ZEND_OP2_LITERAL(init_opline)) != IS_STRING) { /* don't colllect constants after unknown function call */ collect_constants = 0; break; } /* define("name", scalar); */ if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("define")-1 && zend_binary_strcasecmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), Z_STRLEN(ZEND_OP2_LITERAL(init_opline)), "define", sizeof("define")-1) == 0) { if (Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING && send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send2_opline)) <= IS_STRING) { if (collect_constants) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(send1_opline), &ZEND_OP1_LITERAL(send2_opline)); } if (RESULT_UNUSED(opline) && !zend_memnstr(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), "::", sizeof("::") - 1, Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)) + Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { opline->opcode = ZEND_DECLARE_CONST; opline->op1_type = IS_CONST; opline->op2_type = IS_CONST; opline->result_type = IS_UNUSED; opline->op1.constant = send1_opline->op1.constant; opline->op2.constant = send2_opline->op1.constant; opline->result.num = 0; literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); MAKE_NOP(send1_opline); MAKE_NOP(send2_opline); } break; } } /* pre-evaluate constant functions: constant(x) function_exists(x) is_callable(x) extension_loaded(x) */ if (!send2_opline && Z_TYPE(ZEND_OP1_LITERAL(send1_opline)) == IS_STRING) { if ((Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("function_exists")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "function_exists", sizeof("function_exists")-1) && !zend_optimizer_is_disabled_func("function_exists", sizeof("function_exists") - 1)) || (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "is_callable", sizeof("is_callable")) && !zend_optimizer_is_disabled_func("is_callable", sizeof("is_callable") - 1))) { zend_internal_function *func; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); if ((func = zend_hash_find_ptr(EG(function_table), lc_name)) != NULL && func->type == ZEND_INTERNAL_FUNCTION && func->module->type == MODULE_PERSISTENT #ifdef ZEND_WIN32 && func->module->handle == NULL #endif ) { zval t; if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("is_callable") - 1 || func->handler != ZEND_FN(display_disabled_function)) { ZVAL_TRUE(&t); } else { ZVAL_FALSE(&t); } literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &t); } } zend_string_release_ex(lc_name, 0); break; } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("extension_loaded")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "extension_loaded", sizeof("extension_loaded")-1) && !zend_optimizer_is_disabled_func("extension_loaded", sizeof("extension_loaded") - 1)) { zval t; zend_string *lc_name = zend_string_tolower( Z_STR(ZEND_OP1_LITERAL(send1_opline))); zend_module_entry *m = zend_hash_find_ptr(&module_registry, lc_name); zend_string_release_ex(lc_name, 0); if (!m) { if (PG(enable_dl)) { break; } else { ZVAL_FALSE(&t); } } else { if (m->type == MODULE_PERSISTENT #ifdef ZEND_WIN32 && m->handle == NULL #endif ) { ZVAL_TRUE(&t); } else { break; } } literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &t); } break; } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("constant")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "constant", sizeof("constant")-1) && !zend_optimizer_is_disabled_func("constant", sizeof("constant") - 1)) { zval t; if (zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(send1_opline)), &t, 1)) { literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &t); } } break; /* dirname(IS_CONST/IS_STRING) -> IS_CONST/IS_STRING */ } else if (Z_STRLEN(ZEND_OP2_LITERAL(init_opline)) == sizeof("dirname")-1 && !memcmp(Z_STRVAL(ZEND_OP2_LITERAL(init_opline)), "dirname", sizeof("dirname") - 1) && !zend_optimizer_is_disabled_func("dirname", sizeof("dirname") - 1) && IS_ABSOLUTE_PATH(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)))) { zend_string *dirname = zend_string_init(Z_STRVAL(ZEND_OP1_LITERAL(send1_opline)), Z_STRLEN(ZEND_OP1_LITERAL(send1_opline)), 0); ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname)); if (IS_ABSOLUTE_PATH(ZSTR_VAL(dirname), ZSTR_LEN(dirname))) { zval t; ZVAL_STR(&t, dirname); literal_dtor(&ZEND_OP2_LITERAL(init_opline)); MAKE_NOP(init_opline); literal_dtor(&ZEND_OP1_LITERAL(send1_opline)); MAKE_NOP(send1_opline); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; SET_UNUSED(opline->op2); zend_optimizer_update_op1_const(op_array, opline, &t); } } else { zend_string_release_ex(dirname, 0); } break; } } /* don't colllect constants after any other function call */ collect_constants = 0; break; } case ZEND_STRLEN: if (opline->op1_type == IS_CONST) { zval t; if (zend_optimizer_eval_strlen(&t, &ZEND_OP1_LITERAL(opline)) == SUCCESS) { literal_dtor(&ZEND_OP1_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline + 1, IS_TMP_VAR, opline->result.var, &t)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; zend_optimizer_update_op1_const(op_array, opline, &t); } } } break; case ZEND_DEFINED: { zval c; if (!zend_optimizer_get_persistent_constant(Z_STR(ZEND_OP1_LITERAL(opline)), &c, 0)) { break; } ZVAL_TRUE(&c); literal_dtor(&ZEND_OP1_LITERAL(opline)); if (zend_optimizer_replace_by_const(op_array, opline, IS_TMP_VAR, opline->result.var, &c)) { MAKE_NOP(opline); } else { opline->opcode = ZEND_QM_ASSIGN; zend_optimizer_update_op1_const(op_array, opline, &c); } } break; case ZEND_DECLARE_CONST: if (collect_constants && Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_STRING) { zend_optimizer_collect_constant(ctx, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); } break; case ZEND_RETURN: case ZEND_RETURN_BY_REF: case ZEND_GENERATOR_RETURN: case ZEND_EXIT: case ZEND_THROW: case ZEND_CATCH: case ZEND_FAST_CALL: case ZEND_FAST_RET: case ZEND_JMP: case ZEND_JMPZNZ: case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: collect_constants = 0; break; } opline++; i++; } }
inline int sw_zend_hash_update(HashTable *ht, char *k, int len, void * val, int size, void *ptr) { zval key; ZVAL_STRING(&key, k); return zend_hash_update(ht, Z_STR(key), val) ? SUCCESS : FAILURE; }