static HashTable *browscap_entry_to_array(browser_data *bdata, browscap_entry *entry) { zval tmp; uint32_t i; HashTable *ht; ALLOC_HASHTABLE(ht); zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0); ZVAL_STR(&tmp, browscap_convert_pattern(entry->pattern, 0)); zend_hash_str_add(ht, "browser_name_regex", sizeof("browser_name_regex")-1, &tmp); ZVAL_STR_COPY(&tmp, entry->pattern); zend_hash_str_add(ht, "browser_name_pattern", sizeof("browser_name_pattern")-1, &tmp); if (entry->parent) { ZVAL_STR_COPY(&tmp, entry->parent); zend_hash_str_add(ht, "parent", sizeof("parent")-1, &tmp); } for (i = entry->kv_start; i < entry->kv_end; i++) { ZVAL_STR_COPY(&tmp, bdata->kv[i].value); zend_hash_add(ht, bdata->kv[i].key, &tmp); } return ht; }
static int oauth_provider_add_required_param(HashTable *ht, char *required_param) /* {{{ */ { zval zparam, *dest_entry; if((dest_entry = zend_hash_str_find(ht, required_param, strlen(required_param))) == NULL) { ZVAL_NULL(&zparam); if(zend_hash_str_add(ht, required_param, strlen(required_param), &zparam) == NULL) { return FAILURE; } } return SUCCESS; }
void pthreads_stack_tohash(pthreads_stack_t *stack, HashTable *hash) { zval stacked; zval waiting; zval gc; array_init(&stacked); array_init(&waiting); array_init(&gc); zend_hash_str_add(Z_ARRVAL(stacked), ":stacked:", sizeof(":stacked:")-1, &waiting); zend_hash_str_add(Z_ARRVAL(stacked), ":gc:", sizeof(":gc:")-1, &gc); if (pthreads_monitor_lock(stack->monitor)) { pthreads_stack_item_t *item = stack->head; while (item) { if (add_next_index_zval( &waiting, &item->value)) { Z_ADDREF(item->value); } item = item->next; } item = stack->gc->head; while (item) { if (add_next_index_zval( &gc, &item->value)) { Z_ADDREF(item->value); } item = item->next; } pthreads_monitor_unlock(stack->monitor); } zend_hash_str_add(hash, ":stack:", sizeof(":stack:")-1, &stacked); }
static int oauth_provider_set_default_required_params(HashTable *ht) /* {{{ */ { char *required_params[] = {"oauth_consumer_key", "oauth_signature", "oauth_signature_method", "oauth_nonce", "oauth_timestamp", "oauth_token", NULL}; unsigned int idx = 0; do { zval tmp; ZVAL_NULL(&tmp); if(zend_hash_str_add(ht, required_params[idx], strlen(required_params[idx]), &tmp) == NULL) { return FAILURE; } ++idx; } while(required_params[idx]); return SUCCESS; }
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 } }
/* {{{ 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); }
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 } }