void zephir_concat_svsvs(zval **result, const char *op1, zend_uint op1_len, zval *op2, const char *op3, zend_uint op3_len, zval *op4, const char *op5, zend_uint op5_len, int self_var TSRMLS_DC) { zval result_copy, op2_copy, op4_copy; int use_copy = 0, use_copy2 = 0, use_copy4 = 0; uint offset = 0, length; if (Z_TYPE_P(op2) != IS_STRING) { zend_make_printable_zval(op2, &op2_copy, &use_copy2); if (use_copy2) { op2 = &op2_copy; } } if (Z_TYPE_P(op4) != IS_STRING) { zend_make_printable_zval(op4, &op4_copy, &use_copy4); if (use_copy4) { op4 = &op4_copy; } } length = op1_len + Z_STRLEN_P(op2) + op3_len + Z_STRLEN_P(op4) + op5_len; if (self_var) { if (Z_TYPE_PP(result) != IS_STRING) { zend_make_printable_zval(*result, &result_copy, &use_copy); if (use_copy) { ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy)); } } offset = Z_STRLEN_PP(result); length += offset; Z_STRVAL_PP(result) = (char *) str_erealloc(Z_STRVAL_PP(result), length + 1); } else { Z_STRVAL_PP(result) = (char *) emalloc(length + 1); } memcpy(Z_STRVAL_PP(result) + offset, op1, op1_len); memcpy(Z_STRVAL_PP(result) + offset + op1_len, Z_STRVAL_P(op2), Z_STRLEN_P(op2)); memcpy(Z_STRVAL_PP(result) + offset + op1_len + Z_STRLEN_P(op2), op3, op3_len); memcpy(Z_STRVAL_PP(result) + offset + op1_len + Z_STRLEN_P(op2) + op3_len, Z_STRVAL_P(op4), Z_STRLEN_P(op4)); memcpy(Z_STRVAL_PP(result) + offset + op1_len + Z_STRLEN_P(op2) + op3_len + Z_STRLEN_P(op4), op5, op5_len); Z_STRVAL_PP(result)[length] = 0; Z_TYPE_PP(result) = IS_STRING; Z_STRLEN_PP(result) = length; if (use_copy2) { zval_dtor(op2); } if (use_copy4) { zval_dtor(op4); } if (use_copy) { zval_dtor(&result_copy); } }
ZEND_API int string_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */ { zval op1_copy, op2_copy; int use_copy1 = 0, use_copy2 = 0; if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); } if (Z_TYPE_P(op2) != IS_STRING) { zend_make_printable_zval(op2, &op2_copy, &use_copy2); } if (use_copy1) { op1 = &op1_copy; } if (use_copy2) { op2 = &op2_copy; } if (case_insensitive) { ZVAL_LONG(result, zend_binary_zval_strcasecmp(op1, op2)); } else { ZVAL_LONG(result, zend_binary_zval_strcmp(op1, op2)); } if (use_copy1) { zval_dtor(op1); } if (use_copy2) { zval_dtor(op2); } return SUCCESS; }
void zephir_concat_vsvs(zval **result, zval *op1, const char *op2, zend_uint op2_len, zval *op3, const char *op4, zend_uint op4_len, int self_var TSRMLS_DC){ zval result_copy, op1_copy, op3_copy; int use_copy = 0, use_copy1 = 0, use_copy3 = 0; uint offset = 0, length; if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); if (use_copy1) { op1 = &op1_copy; } } if (Z_TYPE_P(op3) != IS_STRING) { zend_make_printable_zval(op3, &op3_copy, &use_copy3); if (use_copy3) { op3 = &op3_copy; } } length = Z_STRLEN_P(op1) + op2_len + Z_STRLEN_P(op3) + op4_len; if (self_var) { if (Z_TYPE_PP(result) != IS_STRING) { zend_make_printable_zval(*result, &result_copy, &use_copy); if (use_copy) { ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy)); } } offset = Z_STRLEN_PP(result); length += offset; Z_STRVAL_PP(result) = (char *) str_erealloc(Z_STRVAL_PP(result), length + 1); } else { Z_STRVAL_PP(result) = (char *) emalloc(length + 1); } memcpy(Z_STRVAL_PP(result) + offset, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1), op2, op2_len); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + op2_len, Z_STRVAL_P(op3), Z_STRLEN_P(op3)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + op2_len + Z_STRLEN_P(op3), op4, op4_len); Z_STRVAL_PP(result)[length] = 0; Z_TYPE_PP(result) = IS_STRING; Z_STRLEN_PP(result) = length; if (use_copy1) { zval_dtor(op1); } if (use_copy3) { zval_dtor(op3); } if (use_copy) { zval_dtor(&result_copy); } }
void zephir_concat_vv(zval **result, zval *op1, zval *op2, int self_var TSRMLS_DC){ zval result_copy, op1_copy, op2_copy; int use_copy = 0, use_copy1 = 0, use_copy2 = 0; uint offset = 0, length; if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); if (use_copy1) { op1 = &op1_copy; } } if (Z_TYPE_P(op2) != IS_STRING) { zend_make_printable_zval(op2, &op2_copy, &use_copy2); if (use_copy2) { op2 = &op2_copy; } } length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); if (self_var) { if (Z_TYPE_PP(result) != IS_STRING) { zend_make_printable_zval(*result, &result_copy, &use_copy); if (use_copy) { ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy)); } } offset = Z_STRLEN_PP(result); length += offset; Z_STRVAL_PP(result) = (char *) erealloc(Z_STRVAL_PP(result), length + 1); } else { Z_STRVAL_PP(result) = (char *) emalloc(length + 1); } memcpy(Z_STRVAL_PP(result) + offset, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); Z_STRVAL_PP(result)[length] = 0; Z_TYPE_PP(result) = IS_STRING; Z_STRLEN_PP(result) = length; if (use_copy1) { zval_dtor(op1); } if (use_copy2) { zval_dtor(op2); } if (use_copy) { zval_dtor(&result_copy); } }
void phalcon_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy){ zend_make_printable_zval(expr, expr_copy, use_copy); if (use_copy) { Z_SET_REFCOUNT_P(expr_copy, 1); Z_UNSET_ISREF_P(expr_copy); } }
void zephir_concat_ss(zval **result, const char *op1, zend_uint op1_len, const char *op2, zend_uint op2_len, int self_var TSRMLS_DC){ zval result_copy; int use_copy = 0; uint offset = 0, length; length = op1_len + op2_len; if (self_var) { if (Z_TYPE_PP(result) != IS_STRING) { zend_make_printable_zval(*result, &result_copy, &use_copy); if (use_copy) { ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy)); } } offset = Z_STRLEN_PP(result); length += offset; Z_STRVAL_PP(result) = (char *) str_erealloc(Z_STRVAL_PP(result), length + 1); } else { Z_STRVAL_PP(result) = (char *) emalloc(length + 1); } memcpy(Z_STRVAL_PP(result) + offset, op1, op1_len); memcpy(Z_STRVAL_PP(result) + offset + op1_len, op2, op2_len); Z_STRVAL_PP(result)[length] = 0; Z_TYPE_PP(result) = IS_STRING; Z_STRLEN_PP(result) = length; if (use_copy) { zval_dtor(&result_copy); } }
void phalcon_raw_url_encode(zval *return_value, zval *url) { zval copy; char *escaped; int use_copy = 0, length; if (Z_TYPE_P(url) == IS_STRING) { zend_make_printable_zval(url, ©, &use_copy); if (use_copy) { url = © } } escaped = php_raw_url_encode(Z_STRVAL_P(url), Z_STRLEN_P(url), &length); if (use_copy) { zval_dtor(url); } if (escaped) { RETURN_STRINGL(escaped, length, 0); } else { RETURN_NULL(); } }
/** * Sends the headers to the client * * @return boolean */ PHP_METHOD(Phalcon_Http_Response_Headers, send){ zval *headers, *value = NULL, *header = NULL; zval *http_header = NULL; zval copy; int use_copy; HashTable *ah0; HashPosition hp0; zval **hd; sapi_header_line ctr = { NULL, 0, 0 }; PHALCON_MM_GROW(); if (!SG(headers_sent)) { PHALCON_OBS_VAR(headers); phalcon_read_property_this(&headers, this_ptr, SL("_headers"), PH_NOISY_CC); phalcon_is_iterable(headers, &ah0, &hp0, 0, 0); while (zend_hash_get_current_data_ex(ah0, (void**) &hd, &hp0) == SUCCESS) { PHALCON_GET_HKEY(header, ah0, hp0); PHALCON_GET_HVALUE(value); if (PHALCON_IS_NOT_EMPTY(value)) { PHALCON_INIT_NVAR(http_header); PHALCON_CONCAT_VSV(http_header, header, ": ", value); ctr.line = Z_STRVAL_P(http_header); ctr.line_len = Z_STRLEN_P(http_header); sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); } else { zend_make_printable_zval(header, ©, &use_copy); if (unlikely(use_copy)) { header = © } ctr.line = Z_STRVAL_P(header); ctr.line_len = Z_STRLEN_P(header); sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); if (unlikely(use_copy)) { zval_dtor(©); } } zend_hash_move_forward_ex(ah0, &hp0); } RETURN_MM_TRUE; } RETURN_MM_FALSE; }
/** * Fast call to php strlen */ void zephir_fast_strlen(zval *return_value, zval *str){ zval copy; int use_copy = 0; if (Z_TYPE_P(str) != IS_STRING) { zend_make_printable_zval(str, ©, &use_copy); if (use_copy) { str = © } } ZVAL_LONG(return_value, Z_STRLEN_P(str)); if (use_copy) { zval_dtor(str); } }
/** * Fast call to php strlen */ int zephir_fast_strlen_ev(zval *str){ zval copy; int use_copy = 0, length; if (Z_TYPE_P(str) != IS_STRING) { zend_make_printable_zval(str, ©, &use_copy); if (use_copy) { str = © } } length = Z_STRLEN_P(str); if (use_copy) { zval_dtor(str); } return length; }
bool protobuf_convert_to_string(zval* from) { switch (Z_TYPE_P(from)) { case IS_STRING: { return true; } case IS_BOOL: case IS_LONG: case IS_DOUBLE: { int use_copy; zval tmp; zend_make_printable_zval(from, &tmp, &use_copy); ZVAL_COPY_VALUE(from, &tmp); return true; } default: zend_error(E_USER_ERROR, "Given value cannot be converted to string."); return false; } }
ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent) { zval expr_copy; int use_copy; zend_make_printable_zval(expr, &expr_copy, &use_copy); if (use_copy) { expr = &expr_copy; } if (expr->value.str.len==0) { /* optimize away empty strings */ if (use_copy) { zval_dtor(expr); } return 0; } write_func(expr->value.str.val, expr->value.str.len); if (use_copy) { zval_dtor(expr); } return expr->value.str.len; }
/** * Filter identifiers string like variables or database columns/tables */ void phalcon_filter_identifier(zval *return_value, zval *param){ int i; char ch; zval copy = {}; smart_str filtered_str = {0}; int use_copy = 0; if (Z_TYPE_P(param) != IS_STRING) { use_copy = zend_make_printable_zval(param, ©); if (use_copy) { param = © } } for (i = 0; i < Z_STRLEN_P(param); i++) { ch = Z_STRVAL_P(param)[i]; if (ch == '\0') { break; } if (isalnum(ch) || ch == '_') { smart_str_appendc(&filtered_str, ch); } } if (use_copy) { zval_ptr_dtor(param); } smart_str_0(&filtered_str); if (filtered_str.s) { RETURN_NEW_STR(filtered_str.s); } else { smart_str_free(&filtered_str); RETURN_EMPTY_STRING(); } }
/** * Filter identifiers string like variables or database columns/tables */ void zephir_filter_identifier(zval *return_value, zval *param){ unsigned int i; unsigned char ch; zval copy; smart_str filtered_str = {0}; int use_copy = 0; if (Z_TYPE_P(param) != IS_STRING) { zend_make_printable_zval(param, ©, &use_copy); if (use_copy) { param = © } } for (i = 0; i < Z_STRLEN_P(param); i++) { ch = Z_STRVAL_P(param)[i]; if (ch == '\0') { break; } if (isalnum(ch) || ch == '_') { smart_str_appendc(&filtered_str, ch); } } if (use_copy) { zval_dtor(param); } smart_str_0(&filtered_str); if (filtered_str.c) { RETURN_STRINGL(filtered_str.c, filtered_str.len, 0); } else { RETURN_EMPTY_STRING(); } }
/** * Fast call to php strlen */ void zephir_fast_strtolower(zval *return_value, zval *str){ zval copy; int use_copy = 0; char *lower_str; unsigned int length; if (Z_TYPE_P(str) != IS_STRING) { zend_make_printable_zval(str, ©, &use_copy); if (use_copy) { str = © } } length = Z_STRLEN_P(str); lower_str = estrndup(Z_STRVAL_P(str), length); php_strtolower(lower_str, length); if (use_copy) { zval_dtor(str); } ZVAL_STRINGL(return_value, lower_str, length, 0); }
/** * Perform escaping of non-alphanumeric characters to different formats */ void zephir_escape_multi(zval *return_value, zval *param, const char *escape_char, unsigned int escape_length, char escape_extra, int use_whitelist) { unsigned int i; zval copy; smart_str escaped_str = {0}; char machine_little_endian, *hex; int big_endian_long_map[4]; int use_copy = 0, machine_endian_check = 1; int issigned = 0; long value; if (Z_TYPE_P(param) != IS_STRING) { use_copy = zend_make_printable_zval(param, ©); if (use_copy) { param = © } } if (Z_STRLEN_P(param) <= 0) { RETURN_FALSE; } /** * This is how the big_ending_long_map is calculated as in 'pack' */ machine_little_endian = ((char *) &machine_endian_check)[0]; if (machine_little_endian) { big_endian_long_map[0] = 3; big_endian_long_map[1] = 2; big_endian_long_map[2] = 1; big_endian_long_map[3] = 0; } else { int size = sizeof(Z_LVAL_P(param)); big_endian_long_map[0] = size - 4; big_endian_long_map[1] = size - 3; big_endian_long_map[2] = size - 2; big_endian_long_map[3] = size - 1; } /** * The input must be a valid UTF-32 string */ if ((Z_STRLEN_P(param) % 4) != 0) { RETURN_FALSE; } for (i = 0; i < Z_STRLEN_P(param); i += 4) { issigned = Z_STRVAL_P(param)[i] & 0x80; value = 0; if (sizeof(long) > 4 && issigned) { value = ~INT_MAX; } value |= zephir_unpack(&Z_STRVAL_P(param)[i], 4, issigned, big_endian_long_map); if (sizeof(long) > 4) { value = (unsigned int) value; } /** * CSS 2.1 section 4.1.3: "It is undefined in CSS 2.1 what happens if a * style sheet does contain a character with Unicode codepoint zero." */ if (value == '\0') { RETURN_FALSE; } /** * Alphanumeric characters are not escaped */ if (value < 256 && isalnum(value)) { smart_str_appendc(&escaped_str, (unsigned char) value); continue; } /** * Chararters in the whitelist are left as they are */ if (use_whitelist) { switch (value) { case ' ': case '/': case '*': case '+': case '-': case '\t': case '\n': case '^': case '$': case '!': case '?': case '\\': case '#': case '}': case '{': case ')': case '(': case ']': case '[': case '.': case ',': case ':': case ';': case '_': case '|': smart_str_appendc(&escaped_str, (unsigned char) value); continue; } } /** * Convert character to hexadecimal */ hex = zephir_longtohex(value); /** * Append the escaped character */ smart_str_appendl(&escaped_str, escape_char, escape_length); smart_str_appendl(&escaped_str, hex, strlen(hex)); if (escape_extra != '\0') { smart_str_appendc(&escaped_str, escape_extra); } efree(hex); } if (use_copy) { zval_dtor(param); } smart_str_0(&escaped_str); if (escaped_str.s) { RETURN_STR(escaped_str.s); } else { RETURN_EMPTY_STRING(); } }
/* php_formatted_print() {{{ * New sprintf implementation for PHP. * * Modifiers: * * " " pad integers with spaces * "-" left adjusted field * n field size * "."n precision (floats only) * "+" Always place a sign (+ or -) in front of a number * * Type specifiers: * * "%" literal "%", modifiers are ignored. * "b" integer argument is printed as binary * "c" integer argument is printed as a single character * "d" argument is an integer * "f" the argument is a float * "o" integer argument is printed as octal * "s" argument is a string * "x" integer argument is printed as lowercase hexadecimal * "X" integer argument is printed as uppercase hexadecimal * */ static char * php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC) { zval ***args, **z_format; int argc, size = 240, inpos = 0, outpos = 0, temppos; int alignment, currarg, adjusting, argnum, width, precision; char *format, *result, padding; int always_sign; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) { return NULL; } /* verify the number of args */ if ((use_array && argc != (2 + format_offset)) || (!use_array && argc < (1 + format_offset))) { efree(args); WRONG_PARAM_COUNT_WITH_RETVAL(NULL); } if (use_array) { int i = 1; zval ***newargs; zval **array; z_format = args[format_offset]; array = args[1 + format_offset]; SEPARATE_ZVAL(array); convert_to_array_ex(array); argc = 1 + zend_hash_num_elements(Z_ARRVAL_PP(array)); newargs = (zval ***)safe_emalloc(argc, sizeof(zval *), 0); newargs[0] = z_format; for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(array)); zend_hash_get_current_data(Z_ARRVAL_PP(array), (void **)&newargs[i++]) == SUCCESS; zend_hash_move_forward(Z_ARRVAL_PP(array))); efree(args); args = newargs; format_offset = 0; } convert_to_string_ex(args[format_offset]); format = Z_STRVAL_PP(args[format_offset]); result = emalloc(size); currarg = 1; while (inpos<Z_STRLEN_PP(args[format_offset])) { int expprec = 0, multiuse = 0; zval *tmp; PRINTF_DEBUG(("sprintf: format[%d]='%c'\n", inpos, format[inpos])); PRINTF_DEBUG(("sprintf: outpos=%d\n", outpos)); if (format[inpos] != '%') { php_sprintf_appendchar(&result, &outpos, &size, format[inpos++] TSRMLS_CC); } else if (format[inpos + 1] == '%') { php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC); inpos += 2; } else { /* starting a new format specifier, reset variables */ alignment = ALIGN_RIGHT; adjusting = 0; padding = ' '; always_sign = 0; inpos++; /* skip the '%' */ PRINTF_DEBUG(("sprintf: first looking at '%c', inpos=%d\n", format[inpos], inpos)); if (isascii((int)format[inpos]) && !isalpha((int)format[inpos])) { /* first look for argnum */ temppos = inpos; while (isdigit((int)format[temppos])) temppos++; if (format[temppos] == '$') { argnum = php_sprintf_getnumber(format, &inpos); if (argnum <= 0) { efree(result); efree(args); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument number must be greater than zero"); return NULL; } multiuse = 1; inpos++; /* skip the '$' */ } else { argnum = currarg++; } argnum += format_offset; /* after argnum comes modifiers */ PRINTF_DEBUG(("sprintf: looking for modifiers\n" "sprintf: now looking at '%c', inpos=%d\n", format[inpos], inpos)); for (;; inpos++) { if (format[inpos] == ' ' || format[inpos] == '0') { padding = format[inpos]; } else if (format[inpos] == '-') { alignment = ALIGN_LEFT; /* space padding, the default */ } else if (format[inpos] == '+') { always_sign = 1; } else if (format[inpos] == '\'') { padding = format[++inpos]; } else { PRINTF_DEBUG(("sprintf: end of modifiers\n")); break; } } PRINTF_DEBUG(("sprintf: padding='%c'\n", padding)); PRINTF_DEBUG(("sprintf: alignment=%s\n", (alignment == ALIGN_LEFT) ? "left" : "right")); /* after modifiers comes width */ if (isdigit((int)format[inpos])) { PRINTF_DEBUG(("sprintf: getting width\n")); if ((width = php_sprintf_getnumber(format, &inpos)) < 0) { efree(result); efree(args); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Width must be greater than zero and less than %d", INT_MAX); return NULL; } adjusting |= ADJ_WIDTH; } else { width = 0; } PRINTF_DEBUG(("sprintf: width=%d\n", width)); /* after width and argnum comes precision */ if (format[inpos] == '.') { inpos++; PRINTF_DEBUG(("sprintf: getting precision\n")); if (isdigit((int)format[inpos])) { if ((precision = php_sprintf_getnumber(format, &inpos)) < 0) { efree(result); efree(args); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Precision must be greater than zero and less than %d", INT_MAX); return NULL; } adjusting |= ADJ_PRECISION; expprec = 1; } else { precision = 0; } } else { precision = 0; } PRINTF_DEBUG(("sprintf: precision=%d\n", precision)); } else { width = precision = 0; argnum = currarg++ + format_offset; } if (argnum >= argc) { efree(result); efree(args); php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too few arguments"); return NULL; } if (format[inpos] == 'l') { inpos++; } PRINTF_DEBUG(("sprintf: format character='%c'\n", format[inpos])); /* now we expect to find a type specifier */ if (multiuse) { MAKE_STD_ZVAL(tmp); *tmp = **(args[argnum]); INIT_PZVAL(tmp); zval_copy_ctor(tmp); } else { SEPARATE_ZVAL(args[argnum]); tmp = *(args[argnum]); } switch (format[inpos]) { case 's': { zval *var, var_copy; int use_copy; zend_make_printable_zval(tmp, &var_copy, &use_copy); if (use_copy) { var = &var_copy; } else { var = tmp; } php_sprintf_appendstring(&result, &outpos, &size, Z_STRVAL_P(var), width, precision, padding, alignment, Z_STRLEN_P(var), 0, expprec, 0); if (use_copy) { zval_dtor(&var_copy); } break; } case 'd': convert_to_long(tmp); php_sprintf_appendint(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment, always_sign); break; case 'u': convert_to_long(tmp); php_sprintf_appenduint(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment); break; case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': convert_to_double(tmp); php_sprintf_appenddouble(&result, &outpos, &size, Z_DVAL_P(tmp), width, padding, alignment, precision, adjusting, format[inpos], always_sign TSRMLS_CC); break; case 'c': convert_to_long(tmp); php_sprintf_appendchar(&result, &outpos, &size, (char) Z_LVAL_P(tmp) TSRMLS_CC); break; case 'o': convert_to_long(tmp); php_sprintf_append2n(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment, 3, hexchars, expprec); break; case 'x': convert_to_long(tmp); php_sprintf_append2n(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment, 4, hexchars, expprec); break; case 'X': convert_to_long(tmp); php_sprintf_append2n(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment, 4, HEXCHARS, expprec); break; case 'b': convert_to_long(tmp); php_sprintf_append2n(&result, &outpos, &size, Z_LVAL_P(tmp), width, padding, alignment, 1, hexchars, expprec); break; case '%': php_sprintf_appendchar(&result, &outpos, &size, '%' TSRMLS_CC); break; default: break; } if (multiuse) { zval_ptr_dtor(&tmp); } inpos++; } } efree(args); /* possibly, we have to make sure we have room for the terminating null? */ result[outpos]=0; *len = outpos; return result; }
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 } }
/** * Writes a zval to a stream */ void zephir_file_put_contents(zval *return_value, zval *filename, zval *data) { php_stream *stream; int numbytes = 0, use_copy = 0; zval *zcontext = NULL; zval copy; php_stream_context *context = NULL; if (Z_TYPE_P(filename) != IS_STRING) { php_error_docref(NULL, E_WARNING, "Invalid arguments supplied for zephir_file_put_contents()"); if (return_value) { RETVAL_FALSE; } return; } context = php_stream_context_from_zval(zcontext, 0 & PHP_FILE_NO_DEFAULT_CONTEXT); stream = php_stream_open_wrapper_ex(Z_STRVAL_P(filename), "wb", ((0 & PHP_FILE_USE_INCLUDE_PATH) ? USE_PATH : 0) | REPORT_ERRORS, NULL, context); if (stream == NULL) { if (return_value) { RETURN_FALSE; } return; } switch (Z_TYPE_P(data)) { case IS_NULL: case IS_LONG: case IS_DOUBLE: case IS_TRUE: case IS_FALSE: case IS_CONSTANT: use_copy = zend_make_printable_zval(data, ©); if (use_copy) { data = © } /* no break */ case IS_STRING: if (Z_STRLEN_P(data)) { numbytes = php_stream_write(stream, Z_STRVAL_P(data), Z_STRLEN_P(data)); if (numbytes != Z_STRLEN_P(data)) { php_error_docref(NULL, E_WARNING, "Only %d of %d bytes written, possibly out of free disk space", numbytes, Z_STRLEN_P(data)); numbytes = -1; } } break; default: numbytes = -1; break; } php_stream_close(stream); if (use_copy) { zval_dtor(data); } if (numbytes < 0) { if (return_value) { RETURN_FALSE; } else { return; } } if (return_value) { RETURN_LONG(numbytes); } return; }
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); if (op_array->last_literal) { cache_size = 0; 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, 1, 1); break; case ZEND_INIT_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2); break; case ZEND_INIT_NS_FCALL_BY_NAME: LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3); break; case ZEND_INIT_METHOD_CALL: if (ZEND_OP2_TYPE(opline) == IS_CONST) { optimizer_literal_obj_info( info, opline->op1_type, opline->op1, opline->op2.constant, LITERAL_METHOD, 2, 2, op_array); } break; case ZEND_INIT_STATIC_METHOD_CALL: if (ZEND_OP1_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); } if (ZEND_OP2_TYPE(opline) == IS_CONST) { optimizer_literal_class_info( info, opline->op1_type, opline->op1, opline->op2.constant, LITERAL_STATIC_METHOD, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 2, op_array); } break; case ZEND_CATCH: LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); break; case ZEND_DEFINED: LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1, 1, 2); break; case ZEND_FETCH_CONSTANT: if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) { LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5); } else { LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3); } break; case ZEND_FETCH_CLASS_CONSTANT: if (ZEND_OP1_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); } optimizer_literal_class_info( info, opline->op1_type, opline->op1, opline->op2.constant, LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1, op_array); 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 (ZEND_OP2_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); } if (ZEND_OP1_TYPE(opline) == IS_CONST) { optimizer_literal_class_info( info, opline->op2_type, opline->op2, opline->op1.constant, LITERAL_STATIC_PROPERTY, 2, 1, op_array); } break; case ZEND_FETCH_CLASS: case ZEND_ADD_INTERFACE: case ZEND_ADD_TRAIT: case ZEND_INSTANCEOF: if (ZEND_OP2_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); } break; case ZEND_NEW: if (ZEND_OP1_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 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 (ZEND_OP2_TYPE(opline) == IS_CONST) { optimizer_literal_obj_info( info, opline->op1_type, opline->op1, opline->op2.constant, LITERAL_PROPERTY, 2, 1, op_array); } 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 (ZEND_OP2_TYPE(opline) == IS_CONST) { if (opline->extended_value == ZEND_ASSIGN_OBJ) { optimizer_literal_obj_info( info, opline->op1_type, opline->op1, opline->op2.constant, LITERAL_PROPERTY, 2, 1, op_array); } else { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1); } } break; case ZEND_BIND_GLOBAL: LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1); break; case ZEND_RECV_INIT: LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 0, 0, 1); if (Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) != (uint32_t)-1) { Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = cache_size; cache_size += sizeof(void *); } break; case ZEND_DECLARE_FUNCTION: case ZEND_DECLARE_CLASS: case ZEND_DECLARE_INHERITED_CLASS: case ZEND_DECLARE_INHERITED_CLASS_DELAYED: LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 0, 0, 2); break; case ZEND_RECV: case ZEND_RECV_VARIADIC: case ZEND_VERIFY_RETURN_TYPE: if (opline->op2.num != (uint32_t)-1) { opline->op2.num = cache_size; cache_size += sizeof(void *); } default: if (ZEND_OP1_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1); } if (ZEND_OP2_TYPE(opline) == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 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_dtor(&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) { /* unsed literal */ zval_dtor(&op_array->literals[i]); continue; } switch (Z_TYPE(op_array->literals[i])) { case IS_NULL: /* Only checking MAY_MERGE for IS_NULL here * is because only IS_NULL can be default value for class type hinting(RECV_INIT). */ if ((info[i].flags & LITERAL_MAY_MERGE)) { 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; } else { map[i] = j; if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } j++; } 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 ((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++; } 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: case IS_CONSTANT: if (info[i].flags & LITERAL_MAY_MERGE) { if (info[i].flags & LITERAL_EX_OBJ) { int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]); key = zend_string_alloc(key_len, 0); memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1); memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1); ZSTR_LEN(key) = key_len; } else if (info[i].flags & LITERAL_EX_CLASS) { int key_len; zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num]; key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN(op_array->literals[i]); key = zend_string_alloc(key_len, 0); memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name)); memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1); memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1); } else { key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0); } ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key)); ZSTR_H(key) += info[i].flags; } if ((info[i].flags & LITERAL_MAY_MERGE) && (pos = zend_hash_find(&hash, key)) != NULL && Z_TYPE(op_array->literals[i]) == Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) && info[i].flags == info[Z_LVAL_P(pos)].flags) { zend_string_release(key); map[i] = Z_LVAL_P(pos); zval_dtor(&op_array->literals[i]); n = LITERAL_NUM_RELATED(info[i].flags); while (n > 1) { i++; zval_dtor(&op_array->literals[i]); n--; } } else { map[i] = j; if (info[i].flags & LITERAL_MAY_MERGE) { ZVAL_LONG(&zv, j); zend_hash_add_new(&hash, key, &zv); zend_string_release(key); } if (i != j) { op_array->literals[j] = op_array->literals[i]; info[j] = info[i]; } if (LITERAL_NUM_SLOTS(info[i].flags)) { Z_CACHE_SLOT(op_array->literals[j]) = cache_size; cache_size += LITERAL_NUM_SLOTS(info[i].flags) * sizeof(void*); } 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_dtor(&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_destroy(&hash); op_array->last_literal = j; op_array->cache_size = cache_size; /* Update opcodes to use new literals table */ opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { if (ZEND_OP1_TYPE(opline) == IS_CONST) { opline->op1.constant = map[opline->op1.constant]; } if (ZEND_OP2_TYPE(opline) == IS_CONST) { opline->op2.constant = map[opline->op2.constant]; } opline++; } zend_arena_release(&ctx->arena, checkpoint); #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_dtor(&zv); } } fflush(stderr); } #endif } }
void zephir_concat_vvvvsvv(zval **result, zval *op1, zval *op2, zval *op3, zval *op4, const char *op5, zend_uint op5_len, zval *op6, zval *op7, int self_var TSRMLS_DC){ zval result_copy, op1_copy, op2_copy, op3_copy, op4_copy, op6_copy, op7_copy; int use_copy = 0, use_copy1 = 0, use_copy2 = 0, use_copy3 = 0, use_copy4 = 0, use_copy6 = 0, use_copy7 = 0; uint offset = 0, length; if (Z_TYPE_P(op1) != IS_STRING) { zend_make_printable_zval(op1, &op1_copy, &use_copy1); if (use_copy1) { op1 = &op1_copy; } } if (Z_TYPE_P(op2) != IS_STRING) { zend_make_printable_zval(op2, &op2_copy, &use_copy2); if (use_copy2) { op2 = &op2_copy; } } if (Z_TYPE_P(op3) != IS_STRING) { zend_make_printable_zval(op3, &op3_copy, &use_copy3); if (use_copy3) { op3 = &op3_copy; } } if (Z_TYPE_P(op4) != IS_STRING) { zend_make_printable_zval(op4, &op4_copy, &use_copy4); if (use_copy4) { op4 = &op4_copy; } } if (Z_TYPE_P(op6) != IS_STRING) { zend_make_printable_zval(op6, &op6_copy, &use_copy6); if (use_copy6) { op6 = &op6_copy; } } if (Z_TYPE_P(op7) != IS_STRING) { zend_make_printable_zval(op7, &op7_copy, &use_copy7); if (use_copy7) { op7 = &op7_copy; } } length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2) + Z_STRLEN_P(op3) + Z_STRLEN_P(op4) + op5_len + Z_STRLEN_P(op6) + Z_STRLEN_P(op7); if (self_var) { if (Z_TYPE_PP(result) != IS_STRING) { zend_make_printable_zval(*result, &result_copy, &use_copy); if (use_copy) { ZEPHIR_CPY_WRT_CTOR(*result, (&result_copy)); } } offset = Z_STRLEN_PP(result); length += offset; Z_STRVAL_PP(result) = (char *) str_erealloc(Z_STRVAL_PP(result), length + 1); } else { Z_STRVAL_PP(result) = (char *) emalloc(length + 1); } memcpy(Z_STRVAL_PP(result) + offset, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + Z_STRLEN_P(op2), Z_STRVAL_P(op3), Z_STRLEN_P(op3)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + Z_STRLEN_P(op2) + Z_STRLEN_P(op3), Z_STRVAL_P(op4), Z_STRLEN_P(op4)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + Z_STRLEN_P(op2) + Z_STRLEN_P(op3) + Z_STRLEN_P(op4), op5, op5_len); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + Z_STRLEN_P(op2) + Z_STRLEN_P(op3) + Z_STRLEN_P(op4) + op5_len, Z_STRVAL_P(op6), Z_STRLEN_P(op6)); memcpy(Z_STRVAL_PP(result) + offset + Z_STRLEN_P(op1) + Z_STRLEN_P(op2) + Z_STRLEN_P(op3) + Z_STRLEN_P(op4) + op5_len + Z_STRLEN_P(op6), Z_STRVAL_P(op7), Z_STRLEN_P(op7)); Z_STRVAL_PP(result)[length] = 0; Z_TYPE_PP(result) = IS_STRING; Z_STRLEN_PP(result) = length; if (use_copy1) { zval_dtor(op1); } if (use_copy2) { zval_dtor(op2); } if (use_copy3) { zval_dtor(op3); } if (use_copy4) { zval_dtor(op4); } if (use_copy6) { zval_dtor(op6); } if (use_copy7) { zval_dtor(op7); } if (use_copy) { zval_dtor(&result_copy); } }