Пример #1
0
int uopz_constant_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
#if PHP_VERSION_ID >= 70100
	if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) {
		CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL);
	}
#else
	if (EX(opline)->op1_type == IS_UNUSED) {
		if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) {
			CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL);
		}
	} else {
		zend_string *key = NULL;
		zval *mock = NULL;
		zend_class_entry *poser = NULL;

		if (EX(opline)->op1_type == IS_CONST) {
			key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1)));			

			if ((mock = zend_hash_find(&UOPZ(mocks), key))) {
				if (Z_TYPE_P(mock) == IS_OBJECT) {
					poser = Z_OBJCE_P(mock);
				} else poser = zend_lookup_class(Z_STR_P(mock));
				CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser);
			}

			if (CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)))) {
				CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL);
			}

			zend_string_release(key);		
		} else {
			key = zend_string_tolower(Z_CE_P(EX_VAR(EX(opline)->op1.var))->name);
			
			if ((mock = zend_hash_find(&UOPZ(mocks), key))) {
				if (Z_TYPE_P(mock) == IS_OBJECT) {
					poser = Z_OBJCE_P(mock);
				} else poser = zend_lookup_class(Z_STR_P(mock));

				Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser;
			}

			CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), 
								  Z_CE_P(EX_VAR(EX(opline)->op1.var)), NULL);

			zend_string_release(key);
		}
	}
#endif

	if (uopz_fetch_constant_handler) {
		return uopz_fetch_constant_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
	}

	return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
Пример #2
0
int uopz_add_class_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	zval *name = EX_CONSTANT(EX(opline)->op2);
	zend_string *key = zend_string_tolower(Z_STR_P(name));
	zval *mock = NULL;
	
	if ((mock = zend_hash_find(&UOPZ(mocks), key))) {
		if (Z_TYPE_P(mock) == IS_STRING) {
			zend_class_entry *ce = zend_lookup_class(Z_STR_P(mock));
			
			if (ce) {
				CACHE_PTR(Z_CACHE_SLOT_P(name), ce);
			}
		} else {
			CACHE_PTR(Z_CACHE_SLOT_P(name), Z_OBJCE_P(mock));
		}
	}
	
	zend_string_release(key);	

	if (uopz_add_trait_handler || uopz_add_interface_handler) {
		switch (EX(opline)->opcode) {
			case ZEND_ADD_INTERFACE:
				return uopz_add_interface_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);

			case ZEND_ADD_TRAIT:
				return uopz_add_trait_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		}
	}
	
	return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
Пример #3
0
int uopz_class_constant_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	if (EX(opline)->op1_type == IS_CONST) {
		zval *name = EX_CONSTANT(EX(opline)->op1);
		zend_string *key = Z_STR_P(name);
		zval *mock = NULL;
		zend_class_entry *poser = NULL;

		key = zend_string_tolower(key);
		
		if ((mock = zend_hash_find(&UOPZ(mocks), key))) {
			if (Z_TYPE_P(mock) == IS_OBJECT) {
				poser = Z_OBJCE_P(mock);
			} else poser = zend_lookup_class(Z_STR_P(mock));

			if (poser) {
				CACHE_PTR(Z_CACHE_SLOT_P(name), poser);
			}
		}

		zend_string_release(key);
	}

	CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op2)), NULL);

	if (uopz_fetch_class_constant_handler) {
		return uopz_fetch_class_constant_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
	}
	
	return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
Пример #4
0
void uopz_set_mock(zend_string *clazz, zval *mock) { /* {{{ */
	zend_string *key = zend_string_tolower(clazz);

	if (zend_hash_update(&UOPZ(mocks), key, mock)) {
		zval_copy_ctor(mock);
	}

	zend_string_release(key);
} /* }}} */
Пример #5
0
void uopz_get_mock(zend_string *clazz, zval *return_value) { /* {{{ */
	zval *mock = NULL;
	zend_string *key = zend_string_tolower(clazz);
	
	if (!(mock = zend_hash_find(&UOPZ(mocks), key))) {
		zend_string_release(key);
		return;
	}

	ZVAL_COPY(return_value, mock);
	zend_string_release(key);
} /* }}} */
Пример #6
0
static zend_function *zend_closure_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */
{
	zend_string *lc_name;

	lc_name = zend_string_tolower(method);
	if (zend_string_equals_literal(method, ZEND_INVOKE_FUNC_NAME)) {
		zend_string_release(lc_name);
		return zend_get_closure_invoke_method(*object);
	}
	zend_string_release(lc_name);
	return std_object_handlers.get_method(object, method, key);
}
Пример #7
0
void uopz_unset_mock(zend_string *clazz) { /* {{{ */
	zend_string *key = zend_string_tolower(clazz);
	
	if (!zend_hash_exists(&UOPZ(mocks), key)) {
		uopz_exception(
			"the class provided (%s) has no mock set",
			ZSTR_VAL(clazz));
		zend_string_release(key);
		return;
	}

	zend_hash_del(&UOPZ(mocks), key);
	zend_string_release(key);
} /* }}} */
Пример #8
0
/** public function ION\HTTP\Message::hasHeader(string $name) : bool */
CLASS_METHOD(ION_HTTP_Message, hasHeader) {
    ion_http_message * message = ION_THIS_OBJECT(ion_http_message);
    zend_string      * name = NULL;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_STR(name)
    ZEND_PARSE_PARAMETERS_END_EX(PION_ZPP_THROW);

    name = zend_string_tolower(name);
    if(zend_hash_exists(message->headers, name)) {
        RETVAL_TRUE;
    } else {
        RETVAL_FALSE;
    }
    zend_string_release(name);
}
Пример #9
0
/** public function ION\HTTP\Message::getHeader(string $name) : array */
CLASS_METHOD(ION_HTTP_Message, getHeader) {
    ion_http_message * message = ION_THIS_OBJECT(ion_http_message);
    zend_string      * name = NULL;
    zval             * header = NULL;

    ZEND_PARSE_PARAMETERS_START(1, 1)
            Z_PARAM_STR(name)
    ZEND_PARSE_PARAMETERS_END_EX(PION_ZPP_THROW);

    name = zend_string_tolower(name);
    header = zend_hash_find(message->headers, name);
    zend_string_release(name);

    if(header) {
        RETURN_ZVAL(header, 1, 0)
    } else {
Пример #10
0
static zend_class_entry * spl_find_ce_by_name(zend_string *name, zend_bool autoload)
{
	zend_class_entry *ce;

	if (!autoload) {
		zend_string *lc_name = zend_string_tolower(name);

		ce = zend_hash_find_ptr(EG(class_table), lc_name);
		zend_string_free(lc_name);
	} else {
 		ce = zend_lookup_class(name);
 	}
 	if (ce == NULL) {
		php_error_docref(NULL, E_WARNING, "Class %s does not exist%s", ZSTR_VAL(name), autoload ? " and could not be loaded" : "");
		return NULL;
	}

	return ce;
}
Пример #11
0
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;
}
Пример #12
0
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++;
	}
}
Пример #13
0
/*********************************************************************
// Name:  TSendMail
// Input:   1) host:    Name of the mail host where the SMTP server resides
//                      max accepted length of name = 256
//          2) appname: Name of the application to use in the X-mailer
//                      field of the message. if NULL is given the application
//                      name is used as given by the GetCommandLine() function
//                      max accespted length of name = 100
// Output:  1) error:   Returns the error code if something went wrong or
//                      SUCCESS otherwise.
//
//  See SendText() for additional args!
//********************************************************************/
PHPAPI int TSendMail(char *host, int *error, char **error_message,
			  char *headers, char *Subject, char *mailTo, char *data,
			  char *mailCc, char *mailBcc, char *mailRPath)
{
	int ret;
	char *RPath = NULL;
	zend_string *headers_lc = NULL, *headers_trim = NULL; /* headers_lc is only created if we've a header at all */
	char *pos1 = NULL, *pos2 = NULL;

	if (host == NULL) {
		*error = BAD_MAIL_HOST;
		return FAILURE;
	} else if (strlen(host) >= HOST_NAME_LEN) {
		*error = BAD_MAIL_HOST;
		return FAILURE;
	} else {
		strcpy(PW32G(mail_host), host);
	}

	if (headers) {
		char *pos = NULL;

		/* Use PCRE to trim the header into the right format */
		if (NULL == (headers_trim = php_win32_mail_trim_header(headers))) {
			*error = W32_SM_PCRE_ERROR;
			return FAILURE;
		}

		/* Create a lowercased header for all the searches so we're finally case
		 * insensitive when searching for a pattern. */
		headers_lc = zend_string_tolower(headers_trim);
	}

	/* Fall back to sendmail_from php.ini setting */
	if (mailRPath && *mailRPath) {
		RPath = estrdup(mailRPath);
	} else if (INI_STR("sendmail_from")) {
		RPath = estrdup(INI_STR("sendmail_from"));
	} else if (headers_lc) {
		int found = 0;
		char *lookup = ZSTR_VAL(headers_lc);

		while (lookup) {
			pos1 = strstr(lookup, "from:");

			if (!pos1) {
				break;
			} else if (pos1 != ZSTR_VAL(headers_lc) && *(pos1-1) != '\n') {
				if (strlen(pos1) >= sizeof("from:")) {
					lookup = pos1 + sizeof("from:");
					continue;
				} else {
					break;
				}
			}

			found = 1;

			/* Real offset is memaddress from the original headers + difference of
			 * string found in the lowercase headrs + 5 characters to jump over
			 * the from: */
			pos1 = headers + (pos1 - lookup) + 5;
			if (NULL == (pos2 = strstr(pos1, "\r\n"))) {
				RPath = estrndup(pos1, strlen(pos1));
			} else {
				RPath = estrndup(pos1, pos2 - pos1);
			}

			break;
		}

		if (!found) {
			if (headers_lc) {
				zend_string_free(headers_lc);
			}
			*error = W32_SM_SENDMAIL_FROM_NOT_SET;
			return FAILURE;
		}
	}

	/* attempt to connect with mail host */
	*error = MailConnect();
	if (*error != 0) {
		if (RPath) {
			efree(RPath);
		}
		if (headers) {
			zend_string_free(headers_trim);
			zend_string_free(headers_lc);
		}
		/* 128 is safe here, the specifier in snprintf isn't longer than that */
		*error_message = ecalloc(1, HOST_NAME_LEN + 128);
		snprintf(*error_message, HOST_NAME_LEN + 128,
			"Failed to connect to mailserver at \"%s\" port %d, verify your \"SMTP\" "
			"and \"smtp_port\" setting in php.ini or use ini_set()",
			PW32G(mail_host), !INI_INT("smtp_port") ? 25 : INI_INT("smtp_port"));
		return FAILURE;
	} else {
		ret = SendText(RPath, Subject, mailTo, mailCc, mailBcc, data, headers ? ZSTR_VAL(headers_trim) : NULL, headers ? ZSTR_VAL(headers_lc) : NULL, error_message);
		TSMClose();
		if (RPath) {
			efree(RPath);
		}
		if (headers) {
			zend_string_free(headers_trim);
			zend_string_free(headers_lc);
		}
		if (ret != SUCCESS) {
			*error = ret;
			return FAILURE;
		}
		return SUCCESS;
	}
}
Пример #14
0
int uopz_call_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	switch (EX(opline)->opcode) {
		case ZEND_INIT_FCALL_BY_NAME:
		case ZEND_INIT_FCALL:
		case ZEND_INIT_NS_FCALL_BY_NAME: {
			zval *function_name = EX_CONSTANT(EX(opline)->op2);
			CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL);
		} break;

		case ZEND_INIT_METHOD_CALL: {
			if (EX(opline)->op2_type == IS_CONST) {
				zval *function_name = EX_CONSTANT(EX(opline)->op2);
				CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL);
			}
		} break;

		case ZEND_INIT_STATIC_METHOD_CALL: {
			zend_class_entry *ce;
			zval *mock;
			zend_string *key = NULL;
			
			if (EX(opline)->op1_type == IS_CONST) {
				key = zend_string_tolower(Z_STR_P(EX_CONSTANT(EX(opline)->op1)));
			} else if (EX(opline)->op1_type != IS_UNUSED) 	{
				ce = Z_CE_P(EX_VAR(EX(opline)->op1.var));
				if (!ce) {
					break;
				}
				key = zend_string_tolower(ce->name);
			}

			if (key && (mock = zend_hash_find(&UOPZ(mocks), key))) {
				zend_class_entry *poser;

				if (Z_TYPE_P(mock) == IS_STRING) {
					poser = zend_lookup_class(Z_STR_P(mock));
					if (!poser) {
						break;
					}
				} else poser = Z_OBJCE_P(mock);

				if (EX(opline)->op1_type == IS_CONST) {
					CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), poser);
				} else {
					Z_CE_P(EX_VAR(EX(opline)->op1.var)) = poser;
				}
			}

			if (key && EX(opline)->op2_type == IS_CONST) {
				zval *function_name = EX_CONSTANT(EX(opline)->op2);
				if (EX(opline)->op1_type == IS_CONST) {
					CACHE_PTR(Z_CACHE_SLOT_P(function_name), NULL);
				} else {
					CACHE_POLYMORPHIC_PTR(Z_CACHE_SLOT_P(function_name), NULL, NULL);
				}
			}
			
			if (key) {
				zend_string_release(key);
			}
		} break;
	}

	switch (EX(opline)->opcode) {
		case ZEND_INIT_FCALL_BY_NAME:
			if (uopz_init_fcall_by_name_handler)
				return uopz_init_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		case ZEND_INIT_FCALL:
			if (uopz_init_fcall_handler)
				return uopz_init_fcall_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		case ZEND_INIT_NS_FCALL_BY_NAME:
			if (uopz_init_ns_fcall_by_name_handler)
				return uopz_init_ns_fcall_by_name_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		case ZEND_INIT_METHOD_CALL:
			if (uopz_init_method_call_handler)
				return uopz_init_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		case ZEND_INIT_STATIC_METHOD_CALL:
			if (uopz_init_static_method_call_handler)
				return uopz_init_static_method_call_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
	}

	return ZEND_USER_OPCODE_DISPATCH;
} /* }}} */
Пример #15
0
int uopz_mock_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH;
	zend_string *key;
	zval *mock = NULL;
	zend_class_entry *ce;

	if (EX(opline)->op1_type == IS_CONST) {
		ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)));

		if (UNEXPECTED(ce == NULL)) {
			key = Z_STR_P(EX_CONSTANT(EX(opline)->op1));
		} else {
			key = ce->name;
		}

		key = zend_string_tolower(key);
	} else if(EX(opline)->op1_type == IS_UNUSED) {
		ce = zend_fetch_class(NULL, EX(opline)->op1.num);
		if (UNEXPECTED(ce == NULL)) {
			return UOPZ_VM_ACTION;
		}
		key = 
			zend_string_tolower(ce->name);
	} else {
		key = zend_string_tolower(
			Z_CE_P(EX_VAR(EX(opline)->op1.var))->name);
	}

	if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), key)))) {
		switch (Z_TYPE_P(mock)) {
			case IS_OBJECT:
				ZVAL_COPY(
					EX_VAR(EX(opline)->result.var), mock);
#if PHP_VERSION_ID < 70100
				EX(opline) = 
					OP_JMP_ADDR(EX(opline), EX(opline)->op2);
#else
				if (EX(opline)->extended_value == 0 && 
					(EX(opline)+1)->opcode == ZEND_DO_FCALL) {
					EX(opline) += 2;
				}
#endif
				UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE;
			break;

			case IS_STRING:
				ce = zend_lookup_class(Z_STR_P(mock));
				if (EXPECTED(ce)) {
					if (EX(opline)->op1_type == IS_CONST) {
						CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(EX(opline)->op1)), ce);
					} else if (EX(opline)->op1_type != IS_UNUSED) {
						Z_CE_P(EX_VAR(EX(opline)->op1.var)) = ce;
					} else {
						/* oh dear, can't do what is requested */			
					}
					
				}
			break;
		}
	}

	zend_string_release(key);

	if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_DISPATCH) {
		if (uopz_new_handler) {
			return uopz_new_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		}
	}

	return UOPZ_VM_ACTION;
} /* }}} */
Пример #16
0
int zend_optimizer_update_op2_const(zend_op_array *op_array,
                                    zend_op       *opline,
                                    zval          *val)
{
	switch (opline->opcode) {
		case ZEND_ASSIGN_REF:
			zval_dtor(val);
			return 0;
		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:
			REQUIRES_STRING(val);
			drop_leading_backslash(val);
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
			alloc_cache_slots_op2(op_array, opline, 1);
			break;
		case ZEND_INIT_FCALL:
			REQUIRES_STRING(val);
			zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			alloc_cache_slots_op2(op_array, opline, 1);
			break;
		case ZEND_INIT_DYNAMIC_CALL:
			if (Z_TYPE_P(val) == IS_STRING) {
				if (zend_memrchr(Z_STRVAL_P(val), ':', Z_STRLEN_P(val))) {
					zval_dtor(val);
					return 0;
				}

				opline->opcode = ZEND_INIT_FCALL_BY_NAME;
				drop_leading_backslash(val);
				opline->op2.constant = zend_optimizer_add_literal(op_array, val);
				zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
				alloc_cache_slots_op2(op_array, opline, 1);
			} else {
				opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			}
			break;
		case ZEND_INIT_METHOD_CALL:
		case ZEND_INIT_STATIC_METHOD_CALL:
			REQUIRES_STRING(val);
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
			alloc_cache_slots_op2(op_array, opline, 2);
			break;
		/*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:
			TO_STRING_NOWARN(val);
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			alloc_cache_slots_op2(op_array, opline, 2);
			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) {
				TO_STRING_NOWARN(val);
				opline->op2.constant = zend_optimizer_add_literal(op_array, val);
				alloc_cache_slots_op2(op_array, opline, 2);
			} else {
				opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			}
			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))
			) {
				opline->op2.constant = zend_optimizer_add_literal(op_array, val);
				break;
			}
			/* break missing intentionally */
		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:
			if (Z_TYPE_P(val) == IS_STRING) {
				zend_ulong index;
				if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
					zval_dtor(val);
					ZVAL_LONG(val, index);
				}
			}
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			break;
		case ZEND_ROPE_INIT:
		case ZEND_ROPE_ADD:
		case ZEND_ROPE_END:
		case ZEND_CONCAT:
		case ZEND_FAST_CONCAT:
			TO_STRING_NOWARN(val);
			/* break missing intentionally */
		default:
			opline->op2.constant = zend_optimizer_add_literal(op_array, val);
			break;
	}

	ZEND_OP2_TYPE(opline) = IS_CONST;
	if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
		zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
	}
	return 1;
}
Пример #17
0
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++;
	}
}
Пример #18
0
int uopz_fetch_handler(UOPZ_OPCODE_HANDLER_ARGS) { /* {{{ */
	zval *name = NULL;
	zend_string *key = NULL;
	int UOPZ_VM_ACTION = ZEND_USER_OPCODE_DISPATCH;

	do {
		if (EX(opline)->op2_type == IS_UNUSED) {
			break;
		}
		
		if (EX(opline)->op2_type == IS_CONST) {
			name = 
				EX_CONSTANT(EX(opline)->op2);
			if (name) {
				key = Z_STR_P(name);
			}			
		} else if (EX(opline)->op2_type != IS_UNUSED) {
			name = EX_VAR(EX(opline)->op2.var);
			if (Z_TYPE_P(name) == IS_STRING) {
				key = Z_STR_P(name);
			} else if (Z_TYPE_P(name) == IS_OBJECT) {
				key = Z_OBJCE_P(name)->name;
			} else {
				
			}
		}

		if (key) {
			zval *mock = NULL;
			zend_class_entry *ce = NULL;
			zend_string *lookup = zend_string_tolower(key);

			if (UNEXPECTED((mock = zend_hash_find(&UOPZ(mocks), lookup)))) {

				switch (Z_TYPE_P(mock)) {
					case IS_OBJECT: ce = Z_OBJCE_P(mock); break;
					case IS_STRING: ce = zend_lookup_class(Z_STR_P(mock)); break;
				}

				if (ce) {
					if (EX(opline)->op2_type == IS_CONST) {
						CACHE_PTR(Z_CACHE_SLOT_P(name), ce);
					}

					Z_CE_P(EX_VAR(EX(opline)->result.var)) = ce;
					UOPZ_VM_ACTION = ZEND_USER_OPCODE_CONTINUE;
				}
			}

			zend_string_release(lookup);
		}
	} while(0);

	if (UOPZ_VM_ACTION == ZEND_USER_OPCODE_CONTINUE) {
		EX(opline) = EX(opline) + 1;
	} else {
		if (uopz_fetch_class_handler) {
			return uopz_fetch_class_handler(UOPZ_OPCODE_HANDLER_ARGS_PASSTHRU);
		}
	}

	return UOPZ_VM_ACTION;
} /* }}} */