Skip to content

Implement operator overloading and improve GMP #342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
2 changes: 2 additions & 0 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1643,6 +1643,8 @@ ZEND_API zend_object_handlers std_object_handlers = {
NULL, /* get_debug_info */
zend_std_get_closure, /* get_closure */
zend_std_get_gc, /* get_gc */
NULL, /* do_operation */
NULL, /* compare */
};

/*
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_object_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ typedef zend_object_value (*zend_object_clone_obj_t)(zval *object TSRMLS_DC);
typedef zend_class_entry *(*zend_object_get_class_entry_t)(const zval *object TSRMLS_DC);
typedef int (*zend_object_get_class_name_t)(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC);
typedef int (*zend_object_compare_zvals_t)(zval *resul, zval *op1, zval *op2 TSRMLS_DC);

/* Cast an object to some other type
*/
Expand All @@ -113,6 +114,8 @@ typedef int (*zend_object_get_closure_t)(zval *obj, zend_class_entry **ce_ptr, u

typedef HashTable *(*zend_object_get_gc_t)(zval *object, zval ***table, int *n TSRMLS_DC);

typedef int (*zend_object_do_operation_t)(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC);

struct _zend_object_handlers {
/* general object functions */
zend_object_add_ref_t add_ref;
Expand Down Expand Up @@ -142,6 +145,8 @@ struct _zend_object_handlers {
zend_object_get_debug_info_t get_debug_info;
zend_object_get_closure_t get_closure;
zend_object_get_gc_t get_gc;
zend_object_do_operation_t do_operation;
zend_object_compare_zvals_t compare;
};

extern ZEND_API zend_object_handlers std_object_handlers;
Expand Down
208 changes: 152 additions & 56 deletions Zend/zend_operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,8 @@ ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *

default:
if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);

zendi_convert_scalar_to_number(op1, op1_copy, result);
zendi_convert_scalar_to_number(op2, op2_copy, result);
converted = 1;
Expand Down Expand Up @@ -904,6 +906,8 @@ ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *

default:
if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);

zendi_convert_scalar_to_number(op1, op1_copy, result);
zendi_convert_scalar_to_number(op2, op2_copy, result);
converted = 1;
Expand Down Expand Up @@ -945,6 +949,8 @@ ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *

default:
if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);

zendi_convert_scalar_to_number(op1, op1_copy, result);
zendi_convert_scalar_to_number(op2, op2_copy, result);
converted = 1;
Expand Down Expand Up @@ -1010,6 +1016,8 @@ ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *

default:
if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);

zendi_convert_scalar_to_number(op1, op1_copy, result);
zendi_convert_scalar_to_number(op2, op2_copy, result);
converted = 1;
Expand All @@ -1027,9 +1035,15 @@ ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ *
zval op1_copy, op2_copy;
long op1_lval;

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MOD);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

if (Z_LVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
Expand All @@ -1053,9 +1067,16 @@ ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
zval op1_copy, op2_copy;
long op1_lval;

zendi_convert_to_boolean(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_boolean(op2, op2_copy, result);
if (Z_TYPE_P(op1) != IS_BOOL || Z_TYPE_P(op2) != IS_BOOL) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BOOL_XOR);

zendi_convert_to_boolean(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_boolean(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_BOOL(result, op1_lval ^ Z_LVAL_P(op2));
return SUCCESS;
}
Expand All @@ -1065,37 +1086,45 @@ ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
{
zval op1_copy;

zendi_convert_to_boolean(op1, op1_copy, result);
if (Z_TYPE_P(op1) != IS_BOOL) {
ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);

zendi_convert_to_boolean(op1, op1_copy, result);
}

ZVAL_BOOL(result, !Z_LVAL_P(op1));
return SUCCESS;
}
/* }}} */

ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC) /* {{{ */
{
zval op1_copy = *op1;

op1 = &op1_copy;

if (Z_TYPE_P(op1) == IS_LONG) {
ZVAL_LONG(result, ~Z_LVAL_P(op1));
return SUCCESS;
} else if (Z_TYPE_P(op1) == IS_DOUBLE) {
ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
return SUCCESS;
} else if (Z_TYPE_P(op1) == IS_STRING) {
int i;

Z_TYPE_P(result) = IS_STRING;
Z_STRVAL_P(result) = estrndup(Z_STRVAL_P(op1), Z_STRLEN_P(op1));
Z_STRLEN_P(result) = Z_STRLEN_P(op1);
for (i = 0; i < Z_STRLEN_P(op1); i++) {
Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
switch (Z_TYPE_P(op1)) {
case IS_LONG:
ZVAL_LONG(result, ~Z_LVAL_P(op1));
return SUCCESS;
case IS_DOUBLE:
ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
return SUCCESS;
case IS_STRING: {
int i;
zval op1_copy = *op1;

Z_TYPE_P(result) = IS_STRING;
Z_STRVAL_P(result) = estrndup(Z_STRVAL(op1_copy), Z_STRLEN(op1_copy));
Z_STRLEN_P(result) = Z_STRLEN(op1_copy);
for (i = 0; i < Z_STRLEN(op1_copy); i++) {
Z_STRVAL_P(result)[i] = ~Z_STRVAL(op1_copy)[i];
}
return SUCCESS;
}
return SUCCESS;
default:
ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);

zend_error(E_ERROR, "Unsupported operand types");
return FAILURE;
}
zend_error(E_ERROR, "Unsupported operand types");
return FAILURE; /* unknown datatype */
}
/* }}} */

Expand Down Expand Up @@ -1130,9 +1159,16 @@ ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /
Z_STRLEN_P(result) = result_len;
return SUCCESS;
}
zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);

if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_OR);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_LONG(result, op1_lval | Z_LVAL_P(op2));
return SUCCESS;
Expand Down Expand Up @@ -1171,10 +1207,15 @@ ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
return SUCCESS;
}

if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_AND);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_LONG(result, op1_lval & Z_LVAL_P(op2));
return SUCCESS;
Expand Down Expand Up @@ -1213,9 +1254,15 @@ ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
return SUCCESS;
}

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_BW_XOR);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_LONG(result, op1_lval ^ Z_LVAL_P(op2));
return SUCCESS;
Expand All @@ -1227,9 +1274,16 @@ ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /
zval op1_copy, op2_copy;
long op1_lval;

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SL);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_LONG(result, op1_lval << Z_LVAL_P(op2));
return SUCCESS;
}
Expand All @@ -1240,9 +1294,16 @@ ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
zval op1_copy, op2_copy;
long op1_lval;

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
if (Z_TYPE_P(op1) != IS_LONG || Z_TYPE_P(op2) != IS_LONG) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SR);

zendi_convert_to_long(op1, op1_copy, result);
op1_lval = Z_LVAL_P(op1);
zendi_convert_to_long(op2, op2_copy, result);
} else {
op1_lval = Z_LVAL_P(op1);
}

ZVAL_LONG(result, op1_lval >> Z_LVAL_P(op2));
return SUCCESS;
}
Expand Down Expand Up @@ -1291,11 +1352,15 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{
zval op1_copy, op2_copy;
int use_copy1 = 0, use_copy2 = 0;

if (Z_TYPE_P(op1) != IS_STRING) {
zend_make_printable_zval(op1, &op1_copy, &use_copy1);
}
if (Z_TYPE_P(op2) != IS_STRING) {
zend_make_printable_zval(op2, &op2_copy, &use_copy2);
if (Z_TYPE_P(op1) != IS_STRING || Z_TYPE_P(op2) != IS_STRING) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);

if (Z_TYPE_P(op1) != IS_STRING) {
zend_make_printable_zval(op1, &op1_copy, &use_copy1);
}
if (Z_TYPE_P(op2) != IS_STRING) {
zend_make_printable_zval(op2, &op2_copy, &use_copy2);
}
}

if (use_copy1) {
Expand Down Expand Up @@ -1526,20 +1591,23 @@ ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {
ZVAL_LONG(result, -1);
return SUCCESS;

case TYPE_PAIR(IS_OBJECT, IS_OBJECT):
/* If both are objects sharing the same comparision handler then use is */
if (Z_OBJ_HANDLER_P(op1,compare_objects) == Z_OBJ_HANDLER_P(op2,compare_objects)) {
default:
if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
return Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2 TSRMLS_CC);
} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
return Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2 TSRMLS_CC);
}

if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
if (Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
/* object handles are identical, apprently this is the same object */
ZVAL_LONG(result, 0);
return SUCCESS;
}
ZVAL_LONG(result, Z_OBJ_HT_P(op1)->compare_objects(op1, op2 TSRMLS_CC));
return SUCCESS;
if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2 TSRMLS_CC));
return SUCCESS;
}
}
/* break missing intentionally */

default:
if (Z_TYPE_P(op1) == IS_OBJECT) {
if (Z_OBJ_HT_P(op1)->get) {
op_free = Z_OBJ_HT_P(op1)->get(op1 TSRMLS_CC);
Expand Down Expand Up @@ -1890,6 +1958,20 @@ ZEND_API int increment_function(zval *op1) /* {{{ */
}
}
break;
case IS_OBJECT:
if (Z_OBJ_HANDLER_P(op1, do_operation)) {
zval *op2;
int res;
TSRMLS_FETCH();

MAKE_STD_ZVAL(op2);
ZVAL_LONG(op2, 1);
res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, op2 TSRMLS_CC);
zval_ptr_dtor(&op2);

return res;
}
return FAILURE;
default:
return FAILURE;
}
Expand Down Expand Up @@ -1936,6 +2018,20 @@ ZEND_API int decrement_function(zval *op1) /* {{{ */
break;
}
break;
case IS_OBJECT:
if (Z_OBJ_HANDLER_P(op1, do_operation)) {
zval *op2;
int res;
TSRMLS_FETCH();

MAKE_STD_ZVAL(op2);
ZVAL_LONG(op2, 1);
res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, op2 TSRMLS_CC);
zval_ptr_dtor(&op2);

return res;
}
return FAILURE;
default:
return FAILURE;
}
Expand Down
18 changes: 18 additions & 0 deletions Zend/zend_operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,24 @@ static zend_always_inline int fast_is_smaller_or_equal_function(zval *result, zv
return Z_LVAL_P(result) <= 0;
}

#define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) \
if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation)) { \
if (SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \
return SUCCESS; \
} \
} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, do_operation)) { \
if (SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2 TSRMLS_CC)) { \
return SUCCESS; \
} \
}

#define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \
if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, do_operation) \
&& SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL TSRMLS_CC) \
) { \
return SUCCESS; \
}

#endif

/*
Expand Down
Loading