Index: ext/spl/spl_array.c =================================================================== --- ext/spl/spl_array.c (revision 297868) +++ ext/spl/spl_array.c (working copy) @@ -717,63 +717,62 @@ } /* }}} */ -static zval *spl_array_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 - && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) { + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { return spl_array_read_dimension(object, member, type TSRMLS_CC); } - return std_object_handlers.read_property(object, member, type TSRMLS_CC); + return std_object_handlers.read_property(object, member, type, key TSRMLS_CC); } /* }}} */ -static void spl_array_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ +static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 - && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) { + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { spl_array_write_dimension(object, member, value TSRMLS_CC); return; } - std_object_handlers.write_property(object, member, value TSRMLS_CC); + std_object_handlers.write_property(object, member, value, key TSRMLS_CC); } /* }}} */ -static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 - && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) { + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { return spl_array_get_dimension_ptr_ptr(1, object, member, 0 TSRMLS_CC); } - return std_object_handlers.get_property_ptr_ptr(object, member TSRMLS_CC); + return std_object_handlers.get_property_ptr_ptr(object, member, key TSRMLS_CC); } /* }}} */ -static int spl_array_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */ +static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 - && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) { + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC); } - return std_object_handlers.has_property(object, member, has_set_exists TSRMLS_CC); - + return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC); } /* }}} */ -static void spl_array_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 - && !std_object_handlers.has_property(object, member, 2 TSRMLS_CC)) { + && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) { spl_array_unset_dimension(object, member TSRMLS_CC); spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */ return; } - std_object_handlers.unset_property(object, member TSRMLS_CC); + std_object_handlers.unset_property(object, member, key TSRMLS_CC); } /* }}} */ static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */ Index: ext/spl/spl_iterators.c =================================================================== --- ext/spl/spl_iterators.c (revision 297868) +++ ext/spl/spl_iterators.c (working copy) @@ -753,7 +753,7 @@ } } /* }}} */ -static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC) +static union _zend_function *spl_recursive_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC) { union _zend_function *function_handler; spl_recursive_it_object *object = (spl_recursive_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC); @@ -765,12 +765,12 @@ } zobj = object->iterators[level].zobject; - function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC); + function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC); if (!function_handler) { if (zend_hash_find(&Z_OBJCE_P(zobj)->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) { if (Z_OBJ_HT_P(zobj)->get_method) { *object_ptr = zobj; - function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC); + function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC); } } } @@ -1158,19 +1158,19 @@ } #endif -static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len TSRMLS_DC) +static union _zend_function *spl_dual_it_get_method(zval **object_ptr, char *method, int method_len, const zend_literal *key TSRMLS_DC) { union _zend_function *function_handler; spl_dual_it_object *intern; intern = (spl_dual_it_object*)zend_object_store_get_object(*object_ptr TSRMLS_CC); - function_handler = std_object_handlers.get_method(object_ptr, method, method_len TSRMLS_CC); + function_handler = std_object_handlers.get_method(object_ptr, method, method_len, key TSRMLS_CC); if (!function_handler && intern->inner.ce) { if (zend_hash_find(&intern->inner.ce->function_table, method, method_len+1, (void **) &function_handler) == FAILURE) { if (Z_OBJ_HT_P(intern->inner.zobject)->get_method) { *object_ptr = intern->inner.zobject; - function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len TSRMLS_CC); + function_handler = Z_OBJ_HT_P(*object_ptr)->get_method(object_ptr, method, method_len, key TSRMLS_CC); } } } Index: ext/standard/array.c =================================================================== --- ext/standard/array.c (revision 297868) +++ ext/standard/array.c (working copy) @@ -1653,24 +1653,28 @@ high = (unsigned char *)Z_STRVAL_P(zhigh); if (*low > *high) { /* Negative Steps */ + unsigned char ch = *low; + if (lstep <= 0) { err = 1; goto err; } - for (; *low >= *high; (*low) -= (unsigned int)lstep) { - add_next_index_stringl(return_value, (const char *)low, 1, 1); - if (((signed int)*low - lstep) < 0) { + for (; ch >= *high; ch -= (unsigned int)lstep) { + add_next_index_stringl(return_value, (const char *)&ch, 1, 1); + if (((signed int)ch - lstep) < 0) { break; } } } else if (*high > *low) { /* Positive Steps */ + unsigned char ch = *low; + if (lstep <= 0) { err = 1; goto err; } - for (; *low <= *high; (*low) += (unsigned int)lstep) { - add_next_index_stringl(return_value, (const char *)low, 1, 1); - if (((signed int)*low + lstep) > 255) { + for (; ch <= *high; ch += (unsigned int)lstep) { + add_next_index_stringl(return_value, (const char *)&ch, 1, 1); + if (((signed int)ch + lstep) > 255) { break; } } Index: ext/standard/string.c =================================================================== --- ext/standard/string.c (revision 297868) +++ ext/standard/string.c (working copy) @@ -3589,7 +3589,9 @@ replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count); } - efree(Z_STRVAL_P(result)); + if (!IS_INTERNED(Z_STRVAL_P(result))) { + efree(Z_STRVAL_P(result)); + } Z_STRVAL_P(result) = Z_STRVAL(temp_result); Z_STRLEN_P(result) = Z_STRLEN(temp_result); @@ -4244,6 +4246,7 @@ char *tbuf, *buf, *p, *tp, *rp, c, lc; int br, i=0, depth=0, in_q = 0; int state = 0, pos; + char *allow_free; if (stateptr) state = *stateptr; @@ -4255,7 +4258,12 @@ rp = rbuf; br = 0; if (allow) { - php_strtolower(allow, allow_len); + if (IS_INTERNED(allow)) { + allow_free = allow = zend_str_tolower_dup(allow, allow_len); + } else { + allow_free = NULL; + php_strtolower(allow, allow_len); + } tbuf = emalloc(PHP_TAG_BUF_SIZE + 1); tp = tbuf; } else { @@ -4494,8 +4502,12 @@ *rp = '\0'; } efree(buf); - if (allow) + if (allow) { efree(tbuf); + if (allow_free) { + efree(allow_free); + } + } if (stateptr) *stateptr = state; Index: ext/standard/incomplete_class.c =================================================================== --- ext/standard/incomplete_class.c (revision 297868) +++ ext/standard/incomplete_class.c (working copy) @@ -54,7 +54,7 @@ } /* }}} */ -static zval *incomplete_class_get_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +static zval *incomplete_class_get_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(object, E_NOTICE TSRMLS_CC); @@ -66,33 +66,33 @@ } /* }}} */ -static void incomplete_class_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ +static void incomplete_class_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(object, E_NOTICE TSRMLS_CC); } /* }}} */ -static zval **incomplete_class_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **incomplete_class_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(object, E_NOTICE TSRMLS_CC); return &EG(error_zval_ptr); } /* }}} */ -static void incomplete_class_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static void incomplete_class_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(object, E_NOTICE TSRMLS_CC); } /* }}} */ -static int incomplete_class_has_property(zval *object, zval *member, int check_empty TSRMLS_DC) /* {{{ */ +static int incomplete_class_has_property(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(object, E_NOTICE TSRMLS_CC); return 0; } /* }}} */ -static union _zend_function *incomplete_class_get_method(zval **object, char *method, int method_len TSRMLS_DC) /* {{{ */ +static union _zend_function *incomplete_class_get_method(zval **object, char *method, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */ { incomplete_class_message(*object, E_ERROR TSRMLS_CC); return NULL; Index: ext/standard/user_filters.c =================================================================== --- ext/standard/user_filters.c (revision 297868) +++ ext/standard/user_filters.c (working copy) @@ -259,7 +259,7 @@ * from being destroyed properly */ INIT_ZVAL(zpropname); ZVAL_STRINGL(&zpropname, "stream", sizeof("stream")-1, 0); - Z_OBJ_HANDLER_P(obj, unset_property)(obj, &zpropname TSRMLS_CC); + Z_OBJ_HANDLER_P(obj, unset_property)(obj, &zpropname, 0 TSRMLS_CC); zval_ptr_dtor(&zclosing); zval_ptr_dtor(&zconsumed); Index: ext/standard/cyr_convert.c =================================================================== --- ext/standard/cyr_convert.c (revision 297868) +++ ext/standard/cyr_convert.c (working copy) @@ -282,7 +282,7 @@ str = (unsigned char*) estrndup(input, input_len); php_convert_cyr_string(str, input_len, fr_cs[0], to_cs[0] TSRMLS_CC); - RETVAL_STRING((char *)str, 0) + RETVAL_STRING((char *)str, 0); } /* }}} */ Index: ext/mysqli/mysqli.c =================================================================== --- ext/mysqli/mysqli.c (revision 297868) +++ ext/mysqli/mysqli.c (working copy) @@ -311,7 +311,7 @@ /* {{{ mysqli_read_property */ -zval *mysqli_read_property(zval *object, zval *member, int type TSRMLS_DC) +zval *mysqli_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { zval tmp_member; zval *retval; @@ -343,7 +343,7 @@ } } else { zend_object_handlers * std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->read_property(object, member, type TSRMLS_CC); + retval = std_hnd->read_property(object, member, type, key TSRMLS_CC); } if (member == &tmp_member) { @@ -354,7 +354,7 @@ /* }}} */ /* {{{ mysqli_write_property */ -void mysqli_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +void mysqli_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { zval tmp_member; mysqli_object *obj; @@ -382,7 +382,7 @@ } } else { zend_object_handlers * std_hnd = zend_get_std_object_handlers(); - std_hnd->write_property(object, member, value TSRMLS_CC); + std_hnd->write_property(object, member, value, key TSRMLS_CC); } if (member == &tmp_member) { @@ -403,7 +403,7 @@ } /* }}} */ -static int mysqli_object_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */ +static int mysqli_object_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { mysqli_object *obj = (mysqli_object *)zend_objects_get_address(object TSRMLS_CC); mysqli_prop_handler p; @@ -415,7 +415,7 @@ ret = 1; break; case 1: { - zval *value = mysqli_read_property(object, member, BP_VAR_IS TSRMLS_CC); + zval *value = mysqli_read_property(object, member, BP_VAR_IS, key TSRMLS_CC); if (value != EG(uninitialized_zval_ptr)) { convert_to_boolean(value); ret = Z_BVAL_P(value)? 1:0; @@ -426,7 +426,7 @@ break; } case 0:{ - zval *value = mysqli_read_property(object, member, BP_VAR_IS TSRMLS_CC); + zval *value = mysqli_read_property(object, member, BP_VAR_IS, key TSRMLS_CC); if (value != EG(uninitialized_zval_ptr)) { ret = Z_TYPE_P(value) != IS_NULL? 1:0; /* refcount is 0 */ @@ -440,7 +440,7 @@ } } else { zend_object_handlers * std_hnd = zend_get_std_object_handlers(); - ret = std_hnd->has_property(object, member, has_set_exists TSRMLS_CC); + ret = std_hnd->has_property(object, member, has_set_exists, key TSRMLS_CC); } return ret; } /* }}} */ @@ -463,7 +463,7 @@ zval *value; INIT_ZVAL(member); ZVAL_STRINGL(&member, entry->name, entry->name_len, 0); - value = mysqli_read_property(object, &member, BP_VAR_IS TSRMLS_CC); + value = mysqli_read_property(object, &member, BP_VAR_IS, 0 TSRMLS_CC); if (value != EG(uninitialized_zval_ptr)) { Z_ADDREF_P(value); zend_hash_add(retval, entry->name, entry->name_len + 1, &value, sizeof(zval *), NULL); Index: ext/dom/php_dom.c =================================================================== --- ext/dom/php_dom.c (revision 297868) +++ ext/dom/php_dom.c (working copy) @@ -302,7 +302,7 @@ } /* }}} */ -static zval **dom_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **dom_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { dom_object *obj; zval tmp_member; @@ -325,7 +325,7 @@ } if (ret == FAILURE) { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->get_property_ptr_ptr(object, member TSRMLS_CC); + retval = std_hnd->get_property_ptr_ptr(object, member, key TSRMLS_CC); } if (member == &tmp_member) { @@ -336,7 +336,7 @@ /* }}} */ /* {{{ dom_read_property */ -zval *dom_read_property(zval *object, zval *member, int type TSRMLS_DC) +zval *dom_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { dom_object *obj; zval tmp_member; @@ -371,7 +371,7 @@ } } else { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->read_property(object, member, type TSRMLS_CC); + retval = std_hnd->read_property(object, member, type, key TSRMLS_CC); } if (member == &tmp_member) { @@ -382,7 +382,7 @@ /* }}} */ /* {{{ dom_write_property */ -void dom_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +void dom_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { dom_object *obj; zval tmp_member; @@ -407,7 +407,7 @@ hnd->write_func(obj, value TSRMLS_CC); } else { std_hnd = zend_get_std_object_handlers(); - std_hnd->write_property(object, member, value TSRMLS_CC); + std_hnd->write_property(object, member, value, key TSRMLS_CC); } if (member == &tmp_member) { @@ -417,7 +417,7 @@ /* }}} */ /* {{{ dom_property_exists */ -static int dom_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) +static int dom_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) { dom_object *obj; zval tmp_member; @@ -455,7 +455,7 @@ } } else { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->has_property(object, member, check_empty TSRMLS_CC); + retval = std_hnd->has_property(object, member, check_empty, key TSRMLS_CC); } if (member == &tmp_member) { Index: ext/soap/php_encoding.c =================================================================== --- ext/soap/php_encoding.c (revision 297868) +++ ext/soap/php_encoding.c (working copy) @@ -1213,7 +1213,7 @@ ZVAL_STRING(&member, name, 0); old_scope = EG(scope); EG(scope) = Z_OBJCE_P(object); - data = Z_OBJ_HT_P(object)->read_property(object, &member, BP_VAR_IS TSRMLS_CC); + data = Z_OBJ_HT_P(object)->read_property(object, &member, BP_VAR_IS, 0 TSRMLS_CC); if (data == EG(uninitialized_zval_ptr)) { /* Hack for bug #32455 */ zend_property_info *property_info; @@ -1247,7 +1247,7 @@ ZVAL_STRING(&member, name, 0); old_scope = EG(scope); EG(scope) = Z_OBJCE_P(object); - Z_OBJ_HT_P(object)->unset_property(object, &member TSRMLS_CC); + Z_OBJ_HT_P(object)->unset_property(object, &member, 0 TSRMLS_CC); EG(scope) = old_scope; } else if (Z_TYPE_P(object) == IS_ARRAY) { zend_hash_del(Z_ARRVAL_P(object), name, strlen(name)+1); Index: ext/xsl/xsltprocessor.c =================================================================== --- ext/xsl/xsltprocessor.c (revision 297868) +++ ext/xsl/xsltprocessor.c (working copy) @@ -427,7 +427,7 @@ std_hnd = zend_get_std_object_handlers(); MAKE_STD_ZVAL(member); ZVAL_STRING(member, "cloneDocument", 0); - cloneDocu = std_hnd->read_property(id, member, BP_VAR_IS TSRMLS_CC); + cloneDocu = std_hnd->read_property(id, member, BP_VAR_IS, NULL TSRMLS_CC); if (Z_TYPE_P(cloneDocu) != IS_NULL) { convert_to_long(cloneDocu); clone_docu = Z_LVAL_P(cloneDocu); @@ -524,7 +524,7 @@ MAKE_STD_ZVAL(member); ZVAL_STRING(member, "doXInclude", 0); - doXInclude = std_hnd->read_property(id, member, BP_VAR_IS TSRMLS_CC); + doXInclude = std_hnd->read_property(id, member, BP_VAR_IS, NULL TSRMLS_CC); if (Z_TYPE_P(doXInclude) != IS_NULL) { convert_to_long(doXInclude); ctxt->xinclude = Z_LVAL_P(doXInclude); Index: ext/pdo/pdo_dbh.c =================================================================== --- ext/pdo/pdo_dbh.c (revision 297868) +++ ext/pdo/pdo_dbh.c (working copy) @@ -449,7 +449,7 @@ MAKE_STD_ZVAL(query_string); ZVAL_STRINGL(query_string, stmt->query_string, stmt->query_stringlen, 1); ZVAL_STRINGL(&z_key, "queryString", sizeof("queryString")-1, 0); - std_object_handlers.write_property(object, &z_key, query_string TSRMLS_CC); + std_object_handlers.write_property(object, &z_key, query_string, 0 TSRMLS_CC); zval_ptr_dtor(&query_string); if (dbstmt_ce->constructor) { @@ -1327,7 +1327,7 @@ #else zval *object, #endif - char *method_name, int method_len TSRMLS_DC) + char *method_name, int method_len, const zend_literal *key TSRMLS_DC) { zend_function *fbc = NULL; char *lc_method_name; @@ -1339,7 +1339,7 @@ lc_method_name = emalloc(method_len + 1); zend_str_tolower_copy(lc_method_name, method_name, method_len); - if ((fbc = std_object_handlers.get_method(object_pp, method_name, method_len TSRMLS_CC)) == NULL) { + if ((fbc = std_object_handlers.get_method(object_pp, method_name, method_len, key TSRMLS_CC)) == NULL) { /* not a pre-defined method, nor a user-defined method; check * the driver specific methods */ if (!dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) { Index: ext/pdo/pdo_stmt.c =================================================================== --- ext/pdo/pdo_stmt.c (revision 297868) +++ ext/pdo/pdo_stmt.c (working copy) @@ -2234,7 +2234,7 @@ }; /* {{{ overloaded handlers for PDOStatement class */ -static void dbstmt_prop_write(zval *object, zval *member, zval *value TSRMLS_DC) +static void dbstmt_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC); @@ -2243,11 +2243,11 @@ if(strcmp(Z_STRVAL_P(member), "queryString") == 0) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC); } else { - std_object_handlers.write_property(object, member, value TSRMLS_CC); + std_object_handlers.write_property(object, member, value, key TSRMLS_CC); } } -static void dbstmt_prop_delete(zval *object, zval *member TSRMLS_DC) +static void dbstmt_prop_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC) { pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC); @@ -2256,7 +2256,7 @@ if(strcmp(Z_STRVAL_P(member), "queryString") == 0) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC); } else { - std_object_handlers.unset_property(object, member TSRMLS_CC); + std_object_handlers.unset_property(object, member, key TSRMLS_CC); } } @@ -2266,7 +2266,7 @@ #else zval *object, #endif - char *method_name, int method_len TSRMLS_DC) + char *method_name, int method_len, const zend_literal *key TSRMLS_DC) { zend_function *fbc = NULL; char *lc_method_name; @@ -2585,7 +2585,7 @@ {NULL, NULL, NULL} }; -static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC) +static zval *row_prop_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { zval *return_value; pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC); @@ -2613,7 +2613,7 @@ } if (strcmp(Z_STRVAL_P(member), "queryString") == 0) { zval_ptr_dtor(&return_value); - return std_object_handlers.read_property(object, member, IS_STRING TSRMLS_CC); + return std_object_handlers.read_property(object, member, IS_STRING, key TSRMLS_CC); } } } @@ -2624,13 +2624,23 @@ return return_value; } -static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC) +static zval *row_dim_read(zval *object, zval *member, int type TSRMLS_DC) { + return row_prop_read(object, member, type, NULL TSRMLS_CC); +} + +static void row_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) +{ php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set"); } -static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC) +static void row_dim_write(zval *object, zval *member, zval *value TSRMLS_DC) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set"); +} + +static int row_prop_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) +{ pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC); int colno = -1; @@ -2653,11 +2663,21 @@ return 0; } -static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC) +static int row_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC) { + return row_prop_exists(object, member, check_empty, NULL TSRMLS_CC); +} + +static void row_prop_delete(zval *object, zval *offset, const zend_literal *key TSRMLS_DC) +{ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow"); } +static void row_dim_delete(zval *object, zval *offset TSRMLS_DC) +{ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow"); +} + static HashTable *row_get_properties(zval *object TSRMLS_DC) { pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC); @@ -2684,7 +2704,7 @@ #else zval *object, #endif - char *method_name, int method_len TSRMLS_DC) + char *method_name, int method_len, const zend_literal *key TSRMLS_DC) { zend_function *fbc; char *lc_method_name; @@ -2741,17 +2761,17 @@ zend_object_handlers pdo_row_object_handlers = { ZEND_OBJECTS_STORE_HANDLERS, - row_prop_or_dim_read, - row_prop_or_dim_write, - row_prop_or_dim_read, - row_prop_or_dim_write, + row_prop_read, + row_prop_write, + row_dim_read, + row_dim_write, NULL, NULL, NULL, - row_prop_or_dim_exists, - row_prop_or_dim_delete, - row_prop_or_dim_exists, - row_prop_or_dim_delete, + row_prop_exists, + row_prop_delete, + row_dim_exists, + row_dim_delete, row_get_properties, row_method_get, row_call_method, Index: ext/phar/phar.c =================================================================== --- ext/phar/phar.c (revision 297868) +++ ext/phar/phar.c (working copy) @@ -1736,32 +1736,31 @@ static int phar_analyze_path(const char *fname, const char *ext, int ext_len, int for_create TSRMLS_DC) /* {{{ */ { php_stream_statbuf ssb; - char *realpath, old, *a = (char *)(ext + ext_len); + char *realpath; + char *filename = estrndup(fname, (ext - fname) + ext_len); - old = *a; - *a = '\0'; - - if ((realpath = expand_filepath(fname, NULL TSRMLS_CC))) { + if ((realpath = expand_filepath(filename, NULL TSRMLS_CC))) { #ifdef PHP_WIN32 phar_unixify_path_separators(realpath, strlen(realpath)); #endif if (zend_hash_exists(&(PHAR_GLOBALS->phar_fname_map), realpath, strlen(realpath))) { - *a = old; efree(realpath); + efree(filename); return SUCCESS; } if (PHAR_G(manifest_cached) && zend_hash_exists(&cached_phars, realpath, strlen(realpath))) { - *a = old; efree(realpath); + efree(filename); return SUCCESS; } efree(realpath); } - if (SUCCESS == php_stream_stat_path((char *) fname, &ssb)) { - *a = old; + if (SUCCESS == php_stream_stat_path((char *) filename, &ssb)) { + efree(filename); + if (ssb.sb.st_mode & S_IFDIR) { return FAILURE; } @@ -1775,57 +1774,56 @@ char *slash; if (!for_create) { - *a = old; + efree(filename); return FAILURE; } - slash = (char *) strrchr(fname, '/'); - *a = old; + slash = (char *) strrchr(filename, '/'); if (slash) { - old = *slash; *slash = '\0'; } - if (SUCCESS != php_stream_stat_path((char *) fname, &ssb)) { - if (slash) { - *slash = old; - } else { - if (!(realpath = expand_filepath(fname, NULL TSRMLS_CC))) { + if (SUCCESS != php_stream_stat_path((char *) filename, &ssb)) { + if (!slash) { + if (!(realpath = expand_filepath(filename, NULL TSRMLS_CC))) { + efree(filename); return FAILURE; } #ifdef PHP_WIN32 phar_unixify_path_separators(realpath, strlen(realpath)); #endif - a = strstr(realpath, fname) + ((ext - fname) + ext_len); - *a = '\0'; + slash = strstr(realpath, filename) + ((ext - fname) + ext_len); + *slash = '\0'; slash = strrchr(realpath, '/'); if (slash) { *slash = '\0'; } else { efree(realpath); + efree(filename); return FAILURE; } if (SUCCESS != php_stream_stat_path(realpath, &ssb)) { efree(realpath); + efree(filename); return FAILURE; } efree(realpath); if (ssb.sb.st_mode & S_IFDIR) { + efree(filename); return SUCCESS; } } + efree(filename); return FAILURE; } - if (slash) { - *slash = old; - } + efree(filename); if (ssb.sb.st_mode & S_IFDIR) { return SUCCESS; Index: ext/com_dotnet/com_handlers.c =================================================================== --- ext/com_dotnet/com_handlers.c (revision 297868) +++ ext/com_dotnet/com_handlers.c (working copy) @@ -29,7 +29,7 @@ #include "php_com_dotnet_internal.h" #include "Zend/zend_exceptions.h" -static zval *com_property_read(zval *object, zval *member, int type TSRMLS_DC) +static zval *com_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { zval *return_value; php_com_dotnet_object *obj; @@ -64,7 +64,7 @@ return return_value; } -static void com_property_write(zval *object, zval *member, zval *value TSRMLS_DC) +static void com_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { php_com_dotnet_object *obj; VARIANT v; @@ -196,7 +196,7 @@ } #endif -static int com_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) +static int com_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) { DISPID dispid; php_com_dotnet_object *obj; @@ -222,7 +222,7 @@ return 0; } -static void com_property_delete(zval *object, zval *member TSRMLS_DC) +static void com_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object"); } @@ -259,7 +259,7 @@ INTERNAL_FUNCTION_PARAM_PASSTHRU); } -static union _zend_function *com_method_get(zval **object_ptr, char *name, int len TSRMLS_DC) +static union _zend_function *com_method_get(zval **object_ptr, char *name, int len, const zend_literal *key TSRMLS_DC) { zend_internal_function f, *fptr = NULL; php_com_dotnet_object *obj; Index: ext/com_dotnet/com_saproxy.c =================================================================== --- ext/com_dotnet/com_saproxy.c (revision 297868) +++ ext/com_dotnet/com_saproxy.c (working copy) @@ -71,7 +71,7 @@ } } -static zval *saproxy_property_read(zval *object, zval *member, int type TSRMLS_DC) +static zval *saproxy_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { zval *return_value; @@ -83,7 +83,7 @@ return return_value; } -static void saproxy_property_write(zval *object, zval *member, zval *value TSRMLS_DC) +static void saproxy_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { php_com_throw_exception(E_INVALIDARG, "safearray has no properties" TSRMLS_CC); } @@ -293,7 +293,7 @@ } #endif -static int saproxy_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) +static int saproxy_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) { /* no properties */ return 0; @@ -305,7 +305,7 @@ return 0; } -static void saproxy_property_delete(zval *object, zval *member TSRMLS_DC) +static void saproxy_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a COM object"); } @@ -321,7 +321,7 @@ return NULL; } -static union _zend_function *saproxy_method_get(zval **object, char *name, int len TSRMLS_DC) +static union _zend_function *saproxy_method_get(zval **object, char *name, int len, const zend_literal *key TSRMLS_DC) { /* no methods */ return NULL; Index: ext/date/php_date.c =================================================================== --- ext/date/php_date.c (revision 297868) +++ ext/date/php_date.c (working copy) @@ -564,8 +564,8 @@ static HashTable *date_object_get_properties(zval *object TSRMLS_DC); static HashTable *date_object_get_properties_interval(zval *object TSRMLS_DC); -zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC); -void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC); +zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC); +void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC); /* {{{ Module struct */ zend_module_entry date_module_entry = { @@ -3427,7 +3427,7 @@ } /* {{{ date_interval_read_property */ -zval *date_interval_read_property(zval *object, zval *member, int type TSRMLS_DC) +zval *date_interval_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { php_interval_obj *obj; zval *retval; @@ -3474,7 +3474,7 @@ /* }}} */ /* {{{ date_interval_write_property */ -void date_interval_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +void date_interval_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { php_interval_obj *obj; zval tmp_member, tmp_value; Index: ext/xmlreader/php_xmlreader.c =================================================================== --- ext/xmlreader/php_xmlreader.c (revision 297868) +++ ext/xmlreader/php_xmlreader.c (working copy) @@ -112,7 +112,7 @@ /* }}} */ /* {{{ xmlreader_get_property_ptr_ptr */ -zval **xmlreader_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) +zval **xmlreader_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) { xmlreader_object *obj; zval tmp_member; @@ -135,7 +135,7 @@ } if (ret == FAILURE) { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->get_property_ptr_ptr(object, member TSRMLS_CC); + retval = std_hnd->get_property_ptr_ptr(object, member, key TSRMLS_CC); } if (member == &tmp_member) { @@ -146,7 +146,7 @@ /* }}} */ /* {{{ xmlreader_read_property */ -zval *xmlreader_read_property(zval *object, zval *member, int type TSRMLS_DC) +zval *xmlreader_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { xmlreader_object *obj; zval tmp_member; @@ -178,7 +178,7 @@ } } else { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->read_property(object, member, type TSRMLS_CC); + retval = std_hnd->read_property(object, member, type, key TSRMLS_CC); } if (member == &tmp_member) { @@ -189,7 +189,7 @@ /* }}} */ /* {{{ xmlreader_write_property */ -void xmlreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +void xmlreader_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { xmlreader_object *obj; zval tmp_member; @@ -214,7 +214,7 @@ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot write to read-only property"); } else { std_hnd = zend_get_std_object_handlers(); - std_hnd->write_property(object, member, value TSRMLS_CC); + std_hnd->write_property(object, member, value, key TSRMLS_CC); } if (member == &tmp_member) { Index: ext/filter/sanitizing_filters.c =================================================================== --- ext/filter/sanitizing_filters.c (revision 297868) +++ ext/filter/sanitizing_filters.c (working copy) @@ -51,7 +51,9 @@ } smart_str_0(&str); - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = str.c; Z_STRLEN_P(value) = str.len; } @@ -102,7 +104,9 @@ s++; } *p = '\0'; - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = (char *)str; Z_STRLEN_P(value) = p - str; } @@ -131,7 +135,9 @@ } /* update zval string data */ buf[c] = '\0'; - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = (char *)buf; Z_STRLEN_P(value) = c; } @@ -169,7 +175,9 @@ } /* update zval string data */ buf[c] = '\0'; - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = (char *)buf; Z_STRLEN_P(value) = c; } @@ -254,7 +262,9 @@ quotes = ENT_NOQUOTES; } buf = php_escape_html_entities_ex(Z_STRVAL_P(value), Z_STRLEN_P(value), &len, 1, quotes, SG(default_charset), 0 TSRMLS_CC); - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = buf; Z_STRLEN_P(value) = len; } @@ -365,7 +375,9 @@ /* just call php_addslashes quotes */ buf = php_addslashes(Z_STRVAL_P(value), Z_STRLEN_P(value), &len, 0 TSRMLS_CC); - efree(Z_STRVAL_P(value)); + if (!IS_INTERNED(Z_STRVAL_P(value))) { + efree(Z_STRVAL_P(value)); + } Z_STRVAL_P(value) = buf; Z_STRLEN_P(value) = len; } Index: ext/mbstring/mbstring.c =================================================================== --- ext/mbstring/mbstring.c (revision 297868) +++ ext/mbstring/mbstring.c (working copy) @@ -3168,7 +3168,7 @@ mbfl_string_init(&result); ret = mbfl_mime_header_encode(&string, &result, charset, transenc, linefeed, indent); if (ret != NULL) { - RETVAL_STRINGL((char *)ret->val, ret->len, 0) /* the string is already strdup()'ed */ + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ } else { RETVAL_FALSE; } @@ -3192,7 +3192,7 @@ mbfl_string_init(&result); ret = mbfl_mime_header_decode(&string, &result, MBSTRG(current_internal_encoding)); if (ret != NULL) { - RETVAL_STRINGL((char *)ret->val, ret->len, 0) /* the string is already strdup()'ed */ + RETVAL_STRINGL((char *)ret->val, ret->len, 0); /* the string is already strdup()'ed */ } else { RETVAL_FALSE; } Index: ext/reflection/php_reflection.c =================================================================== --- ext/reflection/php_reflection.c (revision 297868) +++ ext/reflection/php_reflection.c (working copy) @@ -650,7 +650,7 @@ ++offset; while (op < end) { if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT) - && op->op1.u.constant.value.lval == (long)offset) + && op->op1.num == (long)offset) { return op; } @@ -690,12 +690,12 @@ } if (fptr->type == ZEND_USER_FUNCTION && offset >= required) { zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset); - if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) { + if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { zval *zv, zv_copy; int use_copy; string_write(str, " = ", sizeof(" = ")-1); ALLOC_ZVAL(zv); - *zv = precv->op2.u.constant; + *zv = *precv->op2.zv; zval_copy_ctor(zv); INIT_PZVAL(zv); zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC); @@ -2389,7 +2389,7 @@ RETURN_FALSE; } precv = _get_recv_op((zend_op_array*)param->fptr, param->offset); - if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) { RETURN_FALSE; } RETURN_TRUE; @@ -2419,12 +2419,12 @@ return; } precv = _get_recv_op((zend_op_array*)param->fptr, param->offset); - if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error"); return; } - *return_value = precv->op2.u.constant; + *return_value = *precv->op2.zv; INIT_PZVAL(return_value); if (Z_TYPE_P(return_value) != IS_CONSTANT) { zval_copy_ctor(return_value); @@ -3130,7 +3130,7 @@ GET_REFLECTION_OBJECT_PTR(ce); zend_update_class_constants(ce TSRMLS_CC); - prop = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC); + prop = zend_std_get_static_property(ce, name, name_len, 1, NULL TSRMLS_CC); if (!prop) { if (def_value) { RETURN_ZVAL(def_value, 1, 0); @@ -3164,7 +3164,7 @@ GET_REFLECTION_OBJECT_PTR(ce); zend_update_class_constants(ce TSRMLS_CC); - variable_ptr = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC); + variable_ptr = zend_std_get_static_property(ce, name, name_len, 1, NULL TSRMLS_CC); if (!variable_ptr) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a property named %s", ce->name, name); @@ -3545,7 +3545,7 @@ if (intern->obj && Z_OBJ_HANDLER_P(intern->obj, has_property)) { MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, name, name_len, 1); - if (Z_OBJ_HANDLER_P(intern->obj, has_property)(intern->obj, property, 2 TSRMLS_CC)) { + if (Z_OBJ_HANDLER_P(intern->obj, has_property)(intern->obj, property, 2, 0 TSRMLS_CC)) { zval_ptr_dtor(&property); RETURN_TRUE; } @@ -5598,7 +5598,7 @@ static zend_object_handlers *zend_std_obj_handlers; /* {{{ _reflection_write_property */ -static void _reflection_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +static void _reflection_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { if ((Z_TYPE_P(member) == IS_STRING) && zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) @@ -5610,7 +5610,7 @@ } else { - zend_std_obj_handlers->write_property(object, member, value TSRMLS_CC); + zend_std_obj_handlers->write_property(object, member, value, key TSRMLS_CC); } } /* }}} */ Index: ext/zip/php_zip.c =================================================================== --- ext/zip/php_zip.c (revision 297868) +++ ext/zip/php_zip.c (working copy) @@ -812,7 +812,7 @@ } /* }}} */ -static zval **php_zip_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **php_zip_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { ze_zip_object *obj; zval tmp_member; @@ -827,19 +827,24 @@ zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } ret = FAILURE; obj = (ze_zip_object *)zend_objects_get_address(object TSRMLS_CC); if (obj->prop_handler != NULL) { - ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + if (key) { + ret = zend_hash_quick_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, key->hash_value, (void **) &hnd); + } else { + ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + } } if (ret == FAILURE) { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->get_property_ptr_ptr(object, member TSRMLS_CC); + retval = std_hnd->get_property_ptr_ptr(object, member, key TSRMLS_CC); } if (member == &tmp_member) { @@ -849,7 +854,7 @@ } /* }}} */ -static zval* php_zip_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +static zval* php_zip_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { ze_zip_object *obj; zval tmp_member; @@ -863,13 +868,18 @@ zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } ret = FAILURE; obj = (ze_zip_object *)zend_objects_get_address(object TSRMLS_CC); if (obj->prop_handler != NULL) { - ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + if (key) { + ret = zend_hash_quick_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, key->hash_value, (void **) &hnd); + } else { + ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + } } if (ret == SUCCESS) { @@ -882,7 +892,7 @@ } } else { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->read_property(object, member, type TSRMLS_CC); + retval = std_hnd->read_property(object, member, type, key TSRMLS_CC); } if (member == &tmp_member) { @@ -892,7 +902,7 @@ } /* }}} */ -static int php_zip_has_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +static int php_zip_has_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { ze_zip_object *obj; zval tmp_member; @@ -905,13 +915,18 @@ zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } ret = FAILURE; obj = (ze_zip_object *)zend_objects_get_address(object TSRMLS_CC); if (obj->prop_handler != NULL) { - ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + if (key) { + ret = zend_hash_quick_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, key->hash_value, (void **) &hnd); + } else { + ret = zend_hash_find(obj->prop_handler, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &hnd); + } } if (ret == SUCCESS) { @@ -933,7 +948,7 @@ zval_ptr_dtor(&tmp); } else { std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->has_property(object, member, type TSRMLS_CC); + retval = std_hnd->has_property(object, member, type, key TSRMLS_CC); } if (member == &tmp_member) { Index: ext/simplexml/simplexml.c =================================================================== --- ext/simplexml/simplexml.c (revision 297868) +++ ext/simplexml/simplexml.c (working copy) @@ -389,7 +389,7 @@ /* {{{ sxe_property_read() */ -static zval * sxe_property_read(zval *object, zval *member, int type TSRMLS_DC) +static zval * sxe_property_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) { return sxe_prop_dim_read(object, member, 1, 0, type TSRMLS_CC); } @@ -680,7 +680,7 @@ /* {{{ sxe_property_write() */ -static void sxe_property_write(zval *object, zval *member, zval *value TSRMLS_DC) +static void sxe_property_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { sxe_prop_dim_write(object, member, value, 1, 0, NULL TSRMLS_CC); } @@ -694,7 +694,7 @@ } /* }}} */ -static zval** sxe_property_get_adr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval** sxe_property_get_adr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { php_sxe_object *sxe; xmlNodePtr node; @@ -846,7 +846,7 @@ /* {{{ sxe_property_exists() */ -static int sxe_property_exists(zval *object, zval *member, int check_empty TSRMLS_DC) +static int sxe_property_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC) { return sxe_prop_dim_exists(object, member, check_empty, 1, 0 TSRMLS_CC); } @@ -971,7 +971,7 @@ /* {{{ sxe_property_delete() */ -static void sxe_property_delete(zval *object, zval *member TSRMLS_DC) +static void sxe_property_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC) { sxe_prop_dim_delete(object, member, 1, 0 TSRMLS_CC); } Index: configure.in =================================================================== --- configure.in (revision 297868) +++ configure.in (working copy) @@ -1424,7 +1424,7 @@ zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ - zend_closures.c zend_float.c) + zend_closures.c zend_float.c zend_string.c) if test -r "$abs_srcdir/Zend/zend_objects.c"; then PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_default_classes.c) Index: Zend/zend.c =================================================================== --- Zend/zend.c (revision 297868) +++ Zend/zend.c (working copy) @@ -464,19 +464,19 @@ { memset(EG(exception_op), 0, sizeof(EG(exception_op))); EG(exception_op)[0].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[0].op1.op_type = IS_UNUSED; - EG(exception_op)[0].op2.op_type = IS_UNUSED; - EG(exception_op)[0].result.op_type = IS_UNUSED; + EG(exception_op)[0].op1_type = IS_UNUSED; + EG(exception_op)[0].op2_type = IS_UNUSED; + EG(exception_op)[0].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)); EG(exception_op)[1].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[1].op1.op_type = IS_UNUSED; - EG(exception_op)[1].op2.op_type = IS_UNUSED; - EG(exception_op)[1].result.op_type = IS_UNUSED; + EG(exception_op)[1].op1_type = IS_UNUSED; + EG(exception_op)[1].op2_type = IS_UNUSED; + EG(exception_op)[1].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+1); EG(exception_op)[2].opcode = ZEND_HANDLE_EXCEPTION; - EG(exception_op)[2].op1.op_type = IS_UNUSED; - EG(exception_op)[2].op2.op_type = IS_UNUSED; - EG(exception_op)[2].result.op_type = IS_UNUSED; + EG(exception_op)[2].op1_type = IS_UNUSED; + EG(exception_op)[2].op2_type = IS_UNUSED; + EG(exception_op)[2].result_type = IS_UNUSED; ZEND_VM_SET_OPCODE_HANDLER(EG(exception_op)+2); } /* }}} */ @@ -693,6 +693,7 @@ EG(user_exception_handler) = NULL; #endif + zend_interned_strings_init(TSRMLS_C); zend_startup_builtin_functions(TSRMLS_C); zend_register_standard_constants(TSRMLS_C); zend_register_auto_global("GLOBALS", sizeof("GLOBALS") - 1, NULL TSRMLS_CC); @@ -781,6 +782,8 @@ GLOBAL_CONSTANTS_TABLE = NULL; #endif zend_destroy_rsrc_list_dtors(); + + zend_interned_strings_dtor(TSRMLS_C); } /* }}} */ Index: Zend/zend_hash.c =================================================================== --- Zend/zend_hash.c (revision 297868) +++ Zend/zend_hash.c (working copy) @@ -20,6 +20,7 @@ /* $Id$ */ #include "zend.h" +#include "zend_globals.h" #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ (element)->pNext = (list_head); \ @@ -132,12 +133,18 @@ (p)->pDataPtr=NULL; \ } +#define CHECK_INIT(ht) do { \ + if(UNEXPECTED((ht)->nTableMask == 0)) { \ + (ht)->nTableMask = (ht)->nTableSize - 1; \ + (ht)->arBuckets = (Bucket **) pecalloc((ht)->nTableSize, sizeof(Bucket *), (ht)->persistent); \ + } \ +} while (0) + +static const Bucket *uninitialized_bucket = NULL; - ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) { uint i = 3; - Bucket **tmp; SET_INCONSISTENT(HT_OK); @@ -151,9 +158,9 @@ ht->nTableSize = 1 << i; } - ht->nTableMask = ht->nTableSize - 1; + ht->nTableMask = 0; /* 0 means that ht->arBuckets is uninitialized */ ht->pDestructor = pDestructor; - ht->arBuckets = NULL; + ht->arBuckets = (Bucket**)&uninitialized_bucket; ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -162,21 +169,6 @@ ht->persistent = persistent; ht->nApplyCount = 0; ht->bApplyProtection = 1; - - /* Uses ecalloc() so that Bucket* == NULL */ - if (persistent) { - tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *)); - if (!tmp) { - return FAILURE; - } - ht->arBuckets = tmp; - } else { - tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *)); - if (tmp) { - ht->arBuckets = tmp; - } - } - return SUCCESS; } @@ -212,13 +204,15 @@ return FAILURE; } + CHECK_INIT(ht); + h = zend_inline_hash_func(arKey, nKeyLength); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { if (flag & HASH_ADD) { return FAILURE; } @@ -239,16 +233,24 @@ } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; - } } p = p->pNext; } - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); - if (!p) { - return FAILURE; + if (IS_INTERNED(arKey)) { + p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (char*)arKey; + } else { + p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (char*)(p + 1); + memcpy(p->arKey, arKey, nKeyLength); } - memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; @@ -278,12 +280,13 @@ return zend_hash_index_update(ht, h, pData, nDataSize, pDest); } + CHECK_INIT(ht); nIndex = h & ht->nTableMask; p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { if (flag & HASH_ADD) { return FAILURE; } @@ -304,17 +307,25 @@ } HANDLE_UNBLOCK_INTERRUPTIONS(); return SUCCESS; - } } p = p->pNext; } - p = (Bucket *) pemalloc(sizeof(Bucket) - 1 + nKeyLength, ht->persistent); - if (!p) { - return FAILURE; + if (IS_INTERNED(arKey)) { + p = (Bucket *) pemalloc(sizeof(Bucket), ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (char*)arKey; + } else { + p = (Bucket *) pemalloc(sizeof(Bucket) + nKeyLength, ht->persistent); + if (!p) { + return FAILURE; + } + p->arKey = (char*)(p + 1); + memcpy(p->arKey, arKey, nKeyLength); } - memcpy(p->arKey, arKey, nKeyLength); p->nKeyLength = nKeyLength; INIT_DATA(ht, p, pData, nDataSize); p->h = h; @@ -350,6 +361,7 @@ Bucket *p; IS_CONSISTENT(ht); + CHECK_INIT(ht); if (flag & HASH_NEXT_INSERT) { h = ht->nNextFreeElement; @@ -385,10 +397,11 @@ } p = p->pNext; } - p = (Bucket *) pemalloc_rel(sizeof(Bucket) - 1, ht->persistent); + p = (Bucket *) pemalloc_rel(sizeof(Bucket), ht->persistent); if (!p) { return FAILURE; } + p->arKey = NULL; p->nKeyLength = 0; /* Numeric indices are marked by making the nKeyLength == 0 */ p->h = h; INIT_DATA(ht, p, pData, nDataSize); @@ -440,6 +453,9 @@ uint nIndex; IS_CONSISTENT(ht); + if(UNEXPECTED(ht->nNumOfElements == 0)) { + return SUCCESS; + } memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *)); p = ht->pListHead; @@ -530,7 +546,7 @@ } pefree(q, ht->persistent); } - pefree(ht->arBuckets, ht->persistent); + if(ht->nTableMask) pefree(ht->arBuckets, ht->persistent); SET_INCONSISTENT(HT_DESTROYED); } @@ -556,7 +572,7 @@ } pefree(q, ht->persistent); } - memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); + if(ht->nTableMask) memset(ht->arBuckets, 0, ht->nTableSize*sizeof(Bucket *)); ht->pListHead = NULL; ht->pListTail = NULL; ht->nNumOfElements = 0; @@ -630,7 +646,7 @@ while (p != NULL) { p = zend_hash_apply_deleter(ht, p); } - pefree(ht->arBuckets, ht->persistent); + if(ht->nTableMask) pefree(ht->arBuckets, ht->persistent); SET_INCONSISTENT(HT_DESTROYED); } @@ -647,7 +663,7 @@ p = ht->pListTail; } - pefree(ht->arBuckets, ht->persistent); + if(ht->nTableMask) pefree(ht->arBuckets, ht->persistent); SET_INCONSISTENT(HT_DESTROYED); } @@ -879,11 +895,10 @@ p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { *pData = p->pData; return SUCCESS; - } } p = p->pNext; } @@ -906,11 +921,10 @@ p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { *pData = p->pData; return SUCCESS; - } } p = p->pNext; } @@ -931,10 +945,9 @@ p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { return 1; - } } p = p->pNext; } @@ -957,10 +970,9 @@ p = ht->arBuckets[nIndex]; while (p != NULL) { - if ((p->h == h) && (p->nKeyLength == nKeyLength)) { - if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (p->arKey == arKey || + ((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) { return 1; - } } p = p->pNext; } @@ -1177,6 +1189,7 @@ p = pos ? (*pos) : ht->pInternalPointer; IS_CONSISTENT(ht); + CHECK_INIT(ht); if (p) { if (key_type == HASH_KEY_IS_LONG) { @@ -1283,7 +1296,7 @@ } if (p->nKeyLength != str_length) { - Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent); + Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) + str_length, ht->persistent); q->nKeyLength = str_length; if (p->pData == &p->pDataPtr) { @@ -1317,6 +1330,7 @@ if (key_type == HASH_KEY_IS_LONG) { p->h = num_index; } else { + p->arKey = (char*)(p+1); memcpy(p->arKey, str_index, str_length); p->h = zend_inline_hash_func(str_index, str_length); } @@ -1533,6 +1547,10 @@ Bucket *p; uint i; + if(UNEXPECTED(ht->nNumOfElements == 0)) { + zend_output_debug_string(0, "The hash is empty"); + return; + } for (i = 0; i < ht->nTableSize; i++) { p = ht->arBuckets[i]; while (p != NULL) { Index: Zend/zend.h =================================================================== --- Zend/zend.h (revision 297868) +++ Zend/zend.h (working copy) @@ -22,7 +22,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "2.3.0" +#define ZEND_VERSION "2.4.0" #define ZEND_ENGINE_2 @@ -237,6 +237,7 @@ #include "zend_alloc.h" #include "zend_types.h" +#include "zend_string.h" #ifdef HAVE_LIMITS_H # include @@ -351,17 +352,21 @@ #if defined(__GNUC__) #if __GNUC__ >= 3 #define zend_always_inline inline __attribute__((always_inline)) +#define zend_never_inline __attribute__((noinline)) #else #define zend_always_inline inline +#define zend_never_inline #endif #elif defined(_MSC_VER) #define zend_always_inline __forceinline +#define zend_never_inline #else #define zend_always_inline inline +#define zend_never_inline #endif -#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) +#if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX) # define EXPECTED(condition) __builtin_expect(condition, 1) # define UNEXPECTED(condition) __builtin_expect(condition, 0) #else @@ -599,8 +604,8 @@ /* FIXME: Check if we can save if (ptr) too */ -#define STR_FREE(ptr) if (ptr) { efree(ptr); } -#define STR_FREE_REL(ptr) if (ptr) { efree_rel(ptr); } +#define STR_FREE(ptr) if (ptr && !IS_INTERNED(ptr)) { efree(ptr); } +#define STR_FREE_REL(ptr) if (ptr && !IS_INTERNED(ptr)) { efree_rel(ptr); } #define STR_EMPTY_ALLOC() estrndup("", sizeof("")-1) @@ -676,20 +681,31 @@ #define PZVAL_IS_REF(z) Z_ISREF_P(z) -#define SEPARATE_ZVAL(ppzv) \ - { \ - zval *orig_ptr = *(ppzv); \ - \ - if (Z_REFCOUNT_P(orig_ptr) > 1) { \ - Z_DELREF_P(orig_ptr); \ - ALLOC_ZVAL(*(ppzv)); \ - **(ppzv) = *orig_ptr; \ - zval_copy_ctor(*(ppzv)); \ - Z_SET_REFCOUNT_PP(ppzv, 1); \ - Z_UNSET_ISREF_PP((ppzv)); \ - } \ - } +#define ZVAL_COPY_VALUE(z, v) \ + do { \ + (z)->value = (v)->value; \ + Z_TYPE_P(z) = Z_TYPE_P(v); \ + } while (0) +#define INIT_PZVAL_COPY(z, v) \ + do { \ + ZVAL_COPY_VALUE(z, v); \ + Z_SET_REFCOUNT_P(z, 1); \ + Z_UNSET_ISREF_P(z); \ + } while (0) + +#define SEPARATE_ZVAL(ppzv) \ + do { \ + if (Z_REFCOUNT_PP((ppzv)) > 1) { \ + zval *new_zv; \ + Z_DELREF_PP(ppzv); \ + ALLOC_ZVAL(new_zv); \ + INIT_PZVAL_COPY(new_zv, *(ppzv)); \ + *(ppzv) = new_zv; \ + zval_copy_ctor(new_zv); \ + } \ + } while (0) + #define SEPARATE_ZVAL_IF_NOT_REF(ppzv) \ if (!PZVAL_IS_REF(*ppzv)) { \ SEPARATE_ZVAL(ppzv); \ @@ -711,10 +727,9 @@ } \ INIT_PZVAL(&(zv)); -#define MAKE_COPY_ZVAL(ppzv, pzv) \ - *(pzv) = **(ppzv); \ - zval_copy_ctor((pzv)); \ - INIT_PZVAL((pzv)); +#define MAKE_COPY_ZVAL(ppzv, pzv) \ + INIT_PZVAL_COPY(pzv, *(ppzv)); \ + zval_copy_ctor((pzv)); #define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) { \ int is_ref, refcount; \ @@ -723,7 +738,7 @@ is_ref = Z_ISREF_PP(ppzv_dest); \ refcount = Z_REFCOUNT_PP(ppzv_dest); \ zval_dtor(*ppzv_dest); \ - **ppzv_dest = *pzv_src; \ + ZVAL_COPY_VALUE(*ppzv_dest, pzv_src); \ if (copy) { \ zval_copy_ctor(*ppzv_dest); \ } \ @@ -735,10 +750,7 @@ if (PZVAL_IS_REF(varptr)) { \ zval *original_var = varptr; \ ALLOC_ZVAL(varptr); \ - varptr->value = original_var->value; \ - Z_TYPE_P(varptr) = Z_TYPE_P(original_var); \ - Z_UNSET_ISREF_P(varptr); \ - Z_SET_REFCOUNT_P(varptr, 1); \ + INIT_PZVAL_COPY(varptr, original_var); \ zval_copy_ctor(varptr); \ } else { \ Z_ADDREF_P(varptr); \ Index: Zend/zend_hash.h =================================================================== --- Zend/zend_hash.h (revision 297868) +++ Zend/zend_hash.h (working copy) @@ -60,7 +60,7 @@ struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; - char arKey[1]; /* Must be last element */ + char *arKey; } Bucket; typedef struct _hashtable { @@ -304,7 +304,7 @@ #define ZEND_INIT_SYMTABLE_EX(ht, n, persistent) \ zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent) -#define ZEND_HANDLE_NUMERIC(key, length, func) do { \ +#define ZEND_HANDLE_NUMERIC_EX(key, length, idx, func) do { \ register const char *tmp = key; \ \ if (*tmp == '-') { \ @@ -312,7 +312,6 @@ } \ if (*tmp >= '0' && *tmp <= '9') { /* possibly a numeric index */ \ const char *end = key + length - 1; \ - long idx; \ \ if ((*end != '\0') /* not a null terminated string */ \ || (*tmp == '0' && length > 2) /* numbers with leading zeros */ \ @@ -335,11 +334,17 @@ } else if (idx < 0) { /* overflow */ \ break; \ } \ - return func; \ + func; \ } \ } \ } while (0) +#define ZEND_HANDLE_NUMERIC(key, length, func) do { \ + long idx; \ + \ + ZEND_HANDLE_NUMERIC_EX(key, length, idx, return func); \ +} while (0) + static inline int zend_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) \ { ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest)); Index: Zend/zend_execute.c =================================================================== --- Zend/zend_execute.c (revision 297868) +++ Zend/zend_execute.c (working copy) @@ -48,20 +48,20 @@ typedef int (*incdec_t)(zval *); -#define get_zval_ptr(node, Ts, should_free, type) _get_zval_ptr(node, Ts, should_free, type TSRMLS_CC) -#define get_zval_ptr_ptr(node, Ts, should_free, type) _get_zval_ptr_ptr(node, Ts, should_free, type TSRMLS_CC) -#define get_obj_zval_ptr(node, Ts, should_free, type) _get_obj_zval_ptr(node, Ts, should_free, type TSRMLS_CC) -#define get_obj_zval_ptr_ptr(node, Ts, should_free, type) _get_obj_zval_ptr_ptr(node, Ts, should_free, type TSRMLS_CC) +#define get_zval_ptr(op_type, node, Ts, should_free, type) _get_zval_ptr(op_type, node, Ts, should_free, type TSRMLS_CC) +#define get_zval_ptr_ptr(op_type, node, Ts, should_free, type) _get_zval_ptr_ptr(op_type, node, Ts, should_free, type TSRMLS_CC) +#define get_obj_zval_ptr(op_type, node, Ts, should_free, type) _get_obj_zval_ptr(op_type, node, Ts, should_free, type TSRMLS_CC) +#define get_obj_zval_ptr_ptr(op_type, node, Ts, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, Ts, should_free, type TSRMLS_CC) /* Prototypes */ static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC); static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC); static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC); -#define RETURN_VALUE_USED(opline) (!((opline)->result.u.EA.type & EXT_TYPE_UNUSED)) +#define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED)) -#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset)) #define T(offset) (*(temp_variable *)((char *) Ts + offset)) +#define CV(var) CVs[var] #define TEMP_VAR_STACK_LIMIT 2000 @@ -92,24 +92,37 @@ } } +static zend_never_inline void __zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) +{ + __zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_RELAY_CC); +} + +#undef zval_ptr_dtor +#define zval_ptr_dtor(pzv) i_zval_ptr_dtor(*(pzv) ZEND_FILE_LINE_CC) + #define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC) #define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC) #define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC) #define PZVAL_LOCK(z) Z_ADDREF_P((z)) -#define RETURN_VALUE_UNUSED(pzn) (((pzn)->u.EA.type & EXT_TYPE_UNUSED)) -#define SELECTIVE_PZVAL_LOCK(pzv, pzn) if (!RETURN_VALUE_UNUSED(pzn)) { PZVAL_LOCK(pzv); } +#define SELECTIVE_PZVAL_LOCK(pzv, opline) if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); } -#define AI_USE_PTR(ai) \ - if ((ai).ptr_ptr) { \ - (ai).ptr = *((ai).ptr_ptr); \ - (ai).ptr_ptr = &((ai).ptr); \ - } else { \ - (ai).ptr = NULL; \ - } +#define EXTRACT_ZVAL_PTR(t) do { \ + temp_variable *__t = (t); \ + if (__t->var.ptr_ptr) { \ + __t->var.ptr = *__t->var.ptr_ptr; \ + __t->var.ptr_ptr = &__t->var.ptr; \ + if (!PZVAL_IS_REF(__t->var.ptr) && \ + Z_REFCOUNT_P(__t->var.ptr) > 2) { \ + SEPARATE_ZVAL(__t->var.ptr_ptr); \ + } \ + } \ + } while (0) -#define AI_SET_PTR(ai, val) \ - (ai).ptr = (val); \ - (ai).ptr_ptr = &((ai).ptr); +#define AI_SET_PTR(t, val) do { \ + temp_variable *__t = (t); \ + __t->var.ptr = (val); \ + __t->var.ptr_ptr = &__t->var.ptr; \ + } while (0) #define FREE_OP(should_free) \ if (should_free.var) { \ @@ -134,21 +147,12 @@ #define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L) -#define INIT_PZVAL_COPY(z,v) \ - (z)->value = (v)->value; \ - Z_TYPE_P(z) = Z_TYPE_P(v); \ - Z_SET_REFCOUNT_P(z, 1); \ - Z_UNSET_ISREF_P(z); - #define MAKE_REAL_ZVAL_PTR(val) \ do { \ zval *_tmp; \ ALLOC_ZVAL(_tmp); \ - _tmp->value = (val)->value; \ - Z_TYPE_P(_tmp) = Z_TYPE_P(val); \ - Z_SET_REFCOUNT_P(_tmp, 1); \ - Z_UNSET_ISREF_P(_tmp); \ - val = _tmp; \ + INIT_PZVAL_COPY(_tmp, (val)); \ + (val) = _tmp; \ } while (0) /* End of zend_execute_locks.h */ @@ -172,14 +176,14 @@ return execute_data_ptr->CVs[var]; } -static zend_always_inline zval *_get_zval_ptr_tmp(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) +static zend_always_inline zval *_get_zval_ptr_tmp(zend_uint var, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) { - return should_free->var = &T(node->u.var).tmp_var; + return should_free->var = &T(var).tmp_var; } -static zval *_get_zval_ptr_var_string_offset(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) +static zval *_get_zval_ptr_var_string_offset(zend_uint var, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) { - temp_variable *T = &T(node->u.var); + temp_variable *T = &T(var); zval *str = T->str_offset.str; zval *ptr; @@ -204,18 +208,18 @@ return ptr; } -static zend_always_inline zval *_get_zval_ptr_var(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) +static zend_always_inline zval *_get_zval_ptr_var(zend_uint var, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) { - zval *ptr = T(node->u.var).var.ptr; + zval *ptr = T(var).var.ptr; if (EXPECTED(ptr != NULL)) { PZVAL_UNLOCK(ptr, should_free); return ptr; } else { - return _get_zval_ptr_var_string_offset(node, Ts, should_free TSRMLS_CC); + return _get_zval_ptr_var_string_offset(var, Ts, should_free TSRMLS_CC); } } -static zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC) +static zend_never_inline zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC) { zend_compiled_variable *cv = &CV_DEF_OF(var); @@ -246,30 +250,147 @@ return *ptr; } -static zend_always_inline zval *_get_zval_ptr_cv(const znode *node, const temp_variable *Ts, int type TSRMLS_DC) +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_R(zval ***ptr, zend_uint var TSRMLS_DC) { - zval ***ptr = &CV_OF(node->u.var); + zend_compiled_variable *cv = &CV_DEF_OF(var); + if (!EG(active_symbol_table) || + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + return &EG(uninitialized_zval_ptr); + } + return *ptr; +} + +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_UNSET(zval ***ptr, zend_uint var TSRMLS_DC) +{ + zend_compiled_variable *cv = &CV_DEF_OF(var); + + if (!EG(active_symbol_table) || + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + return &EG(uninitialized_zval_ptr); + } + return *ptr; +} + +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_IS(zval ***ptr, zend_uint var TSRMLS_DC) +{ + zend_compiled_variable *cv = &CV_DEF_OF(var); + + if (!EG(active_symbol_table) || + zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + return &EG(uninitialized_zval_ptr); + } + return *ptr; +} + +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_RW(zval ***ptr, zend_uint var TSRMLS_DC) +{ + zend_compiled_variable *cv = &CV_DEF_OF(var); + + if (!EG(active_symbol_table)) { + Z_ADDREF(EG(uninitialized_zval)); + *ptr = (zval**)EG(current_execute_data)->CVs + (EG(active_op_array)->last_var + var); + **ptr = &EG(uninitialized_zval); + zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + } else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + Z_ADDREF(EG(uninitialized_zval)); + zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr); + zend_error(E_NOTICE, "Undefined variable: %s", cv->name); + } + return *ptr; +} + +static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zval ***ptr, zend_uint var TSRMLS_DC) +{ + zend_compiled_variable *cv = &CV_DEF_OF(var); + + if (!EG(active_symbol_table)) { + Z_ADDREF(EG(uninitialized_zval)); + *ptr = (zval**)EG(current_execute_data)->CVs + (EG(active_op_array)->last_var + var); + **ptr = &EG(uninitialized_zval); + } else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) { + Z_ADDREF(EG(uninitialized_zval)); + zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr); + } + return *ptr; +} + +static zend_always_inline zval *_get_zval_ptr_cv(zend_uint var, int type TSRMLS_DC) +{ + zval ***ptr = &CV_OF(var); + if (UNEXPECTED(*ptr == NULL)) { - return *_get_zval_cv_lookup(ptr, node->u.var, type TSRMLS_CC); + return *_get_zval_cv_lookup(ptr, var, type TSRMLS_CC); } return **ptr; } -static inline zval *_get_zval_ptr(znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(zval ***CVs, zend_uint var TSRMLS_DC) { + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return *_get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC); + } + return **ptr; +} + +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return *_get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC); + } + return **ptr; +} + +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return *_get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC); + } + return **ptr; +} + +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return *_get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC); + } + return **ptr; +} + +static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return *_get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC); + } + return **ptr; +} + +static inline zval *_get_zval_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +{ /* should_free->is_var = 0; */ - switch (node->op_type) { + switch (op_type) { case IS_CONST: should_free->var = 0; - return &node->u.constant; + return node->zv; break; case IS_TMP_VAR: - should_free->var = TMP_FREE(&T(node->u.var).tmp_var); - return &T(node->u.var).tmp_var; + should_free->var = TMP_FREE(&T(node->var).tmp_var); + return &T(node->var).tmp_var; break; case IS_VAR: - return _get_zval_ptr_var(node, Ts, should_free TSRMLS_CC); + return _get_zval_ptr_var(node->var, Ts, should_free TSRMLS_CC); break; case IS_UNUSED: should_free->var = 0; @@ -277,43 +398,93 @@ break; case IS_CV: should_free->var = 0; - return _get_zval_ptr_cv(node, Ts, type TSRMLS_CC); + return _get_zval_ptr_cv(node->var, type TSRMLS_CC); break; EMPTY_SWITCH_DEFAULT_CASE() } return NULL; } -static zend_always_inline zval **_get_zval_ptr_ptr_var(const znode *node, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) +static zend_always_inline zval **_get_zval_ptr_ptr_var(zend_uint var, const temp_variable *Ts, zend_free_op *should_free TSRMLS_DC) { - zval** ptr_ptr = T(node->u.var).var.ptr_ptr; + zval** ptr_ptr = T(var).var.ptr_ptr; if (EXPECTED(ptr_ptr != NULL)) { PZVAL_UNLOCK(*ptr_ptr, should_free); } else { /* string offset */ - PZVAL_UNLOCK(T(node->u.var).str_offset.str, should_free); + PZVAL_UNLOCK(T(var).str_offset.str, should_free); } return ptr_ptr; } -static zend_always_inline zval **_get_zval_ptr_ptr_cv(const znode *node, const temp_variable *Ts, int type TSRMLS_DC) +static zend_always_inline zval **_get_zval_ptr_ptr_cv(zend_uint var, int type TSRMLS_DC) { - zval ***ptr = &CV_OF(node->u.var); + zval ***ptr = &CV_OF(var); if (UNEXPECTED(*ptr == NULL)) { - return _get_zval_cv_lookup(ptr, node->u.var, type TSRMLS_CC); + return _get_zval_cv_lookup(ptr, var, type TSRMLS_CC); } return *ptr; } -static inline zval **_get_zval_ptr_ptr(const znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_R(zval ***CVs, zend_uint var TSRMLS_DC) { - if (node->op_type == IS_CV) { + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return _get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC); + } + return *ptr; +} + +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_UNSET(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return _get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC); + } + return *ptr; +} + +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_IS(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return _get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC); + } + return *ptr; +} + +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_RW(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return _get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC); + } + return *ptr; +} + +static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_W(zval ***CVs, zend_uint var TSRMLS_DC) +{ + zval ***ptr = &CV(var); + + if (UNEXPECTED(*ptr == NULL)) { + return _get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC); + } + return *ptr; +} + +static inline zval **_get_zval_ptr_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +{ + if (op_type == IS_CV) { should_free->var = 0; - return _get_zval_ptr_ptr_cv(node, Ts, type TSRMLS_CC); - } else if (node->op_type == IS_VAR) { - return _get_zval_ptr_ptr_var(node, Ts, should_free TSRMLS_CC); + return _get_zval_ptr_ptr_cv(node->var, type TSRMLS_CC); + } else if (op_type == IS_VAR) { + return _get_zval_ptr_ptr_var(node->var, Ts, should_free TSRMLS_CC); } else { should_free->var = 0; return NULL; @@ -330,9 +501,9 @@ } } -static inline zval **_get_obj_zval_ptr_ptr(const znode *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +static inline zval **_get_obj_zval_ptr_ptr(int op_type, const znode_op *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { - if (op->op_type == IS_UNUSED) { + if (op_type == IS_UNUSED) { if (EXPECTED(EG(This) != NULL)) { /* this should actually never be modified, _ptr_ptr is modified only when the object is empty */ @@ -342,7 +513,7 @@ zend_error_noreturn(E_ERROR, "Using $this when not in object context"); } } - return get_zval_ptr_ptr(op, Ts, should_free, type); + return get_zval_ptr_ptr(op_type, op, Ts, should_free, type); } static zend_always_inline zval **_get_obj_zval_ptr_ptr_unused(TSRMLS_D) @@ -355,9 +526,9 @@ } } -static inline zval *_get_obj_zval_ptr(znode *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) +static inline zval *_get_obj_zval_ptr(int op_type, znode_op *op, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { - if (op->op_type == IS_UNUSED) { + if (op_type == IS_UNUSED) { if (EXPECTED(EG(This) != NULL)) { should_free->var = 0; return EG(This); @@ -365,7 +536,7 @@ zend_error_noreturn(E_ERROR, "Using $this when not in object context"); } } - return get_zval_ptr(op, Ts, should_free, type); + return get_zval_ptr(op_type, op, Ts, should_free, type); } static inline void zend_switch_free(temp_variable *T, int extended_value TSRMLS_DC) @@ -388,7 +559,7 @@ zval *variable_ptr = *variable_ptr_ptr; zval *value_ptr = *value_ptr_ptr; - if (variable_ptr == EG(error_zval_ptr) || value_ptr==EG(error_zval_ptr)) { + if (variable_ptr == &EG(error_zval) || value_ptr == &EG(error_zval)) { variable_ptr_ptr = &EG(uninitialized_zval_ptr); } else if (variable_ptr != value_ptr) { if (!PZVAL_IS_REF(value_ptr)) { @@ -396,7 +567,7 @@ Z_DELREF_P(value_ptr); if (Z_REFCOUNT_P(value_ptr)>0) { ALLOC_ZVAL(*value_ptr_ptr); - **value_ptr_ptr = *value_ptr; + ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr); value_ptr = *value_ptr_ptr; zendi_zval_copy_ctor(*value_ptr); } @@ -411,12 +582,12 @@ } else if (!Z_ISREF_P(variable_ptr)) { if (variable_ptr_ptr == value_ptr_ptr) { SEPARATE_ZVAL(variable_ptr_ptr); - } else if (variable_ptr==EG(uninitialized_zval_ptr) + } else if (variable_ptr==&EG(uninitialized_zval) || Z_REFCOUNT_P(variable_ptr)>2) { /* we need to separate */ Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2); ALLOC_ZVAL(*variable_ptr_ptr); - **variable_ptr_ptr = *variable_ptr; + ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr); zval_copy_ctor(*variable_ptr_ptr); *value_ptr_ptr = *variable_ptr_ptr; Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2); @@ -452,7 +623,7 @@ } } -static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const zend_arg_info *cur_arg_info, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind TSRMLS_DC) +static inline int zend_verify_arg_error(const zend_function *zf, zend_uint arg_num, const char *need_msg, const char *need_kind, const char *given_msg, char *given_kind TSRMLS_DC) { zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data; char *fname = zf->common.function_name; @@ -493,40 +664,38 @@ if (!arg) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "none", "" TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC); } if (Z_TYPE_P(arg) == IS_OBJECT) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) { - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC); } } else if (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null) { need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC); - return zend_verify_arg_error(zf, arg_num, cur_arg_info, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC); } } else if (cur_arg_info->array_type_hint) { if (!arg) { - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", "none", "" TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, "be an array", "", "none", "" TSRMLS_CC); } if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !cur_arg_info->allow_null)) { - return zend_verify_arg_error(zf, arg_num, cur_arg_info, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC); + return zend_verify_arg_error(zf, arg_num, "be an array", "", zend_zval_type_name(arg), "" TSRMLS_CC); } } return 1; } -static inline void zend_assign_to_object(znode *result, zval **object_ptr, zval *property_name, znode *value_op, const temp_variable *Ts, int opcode TSRMLS_DC) - +static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval *property_name, int value_type, znode_op *value_op, const temp_variable *Ts, int opcode, const zend_literal *key TSRMLS_DC) { zval *object = *object_ptr; zend_free_op free_value; - zval *value = get_zval_ptr(value_op, Ts, &free_value, BP_VAR_R); - zval **retval = &T(result->u.var).var.ptr; + zval *value = get_zval_ptr(value_type, value_op, Ts, &free_value, BP_VAR_R); if (Z_TYPE_P(object) != IS_OBJECT) { - if (object == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(result)) { - *retval = EG(uninitialized_zval_ptr); + if (object == &EG(error_zval)) { + if (retval) { + *retval = &EG(uninitialized_zval); PZVAL_LOCK(*retval); } FREE_OP(free_value); @@ -542,8 +711,8 @@ zend_error(E_STRICT, "Creating default object from empty value"); } else { zend_error(E_WARNING, "Attempt to assign property of non-object"); - if (!RETURN_VALUE_UNUSED(result)) { - *retval = EG(uninitialized_zval_ptr); + if (retval) { + *retval = &EG(uninitialized_zval); PZVAL_LOCK(*retval); } FREE_OP(free_value); @@ -552,18 +721,18 @@ } /* separate our value if necessary */ - if (value_op->op_type == IS_TMP_VAR) { + if (value_type == IS_TMP_VAR) { zval *orig_value = value; ALLOC_ZVAL(value); - *value = *orig_value; + ZVAL_COPY_VALUE(value, orig_value); Z_UNSET_ISREF_P(value); Z_SET_REFCOUNT_P(value, 0); - } else if (value_op->op_type == IS_CONST) { + } else if (value_type == IS_CONST) { zval *orig_value = value; ALLOC_ZVAL(value); - *value = *orig_value; + ZVAL_COPY_VALUE(value, orig_value); Z_UNSET_ISREF_P(value); Z_SET_REFCOUNT_P(value, 0); zval_copy_ctor(value); @@ -574,19 +743,19 @@ if (opcode == ZEND_ASSIGN_OBJ) { if (!Z_OBJ_HT_P(object)->write_property) { zend_error(E_WARNING, "Attempt to assign property of non-object"); - if (!RETURN_VALUE_UNUSED(result)) { - *retval = EG(uninitialized_zval_ptr); - PZVAL_LOCK(*retval); + if (retval) { + *retval = &EG(uninitialized_zval); + PZVAL_LOCK(&EG(uninitialized_zval)); } - if (value_op->op_type == IS_TMP_VAR) { + if (value_type == IS_TMP_VAR) { FREE_ZVAL(value); - } else if (value_op->op_type == IS_CONST) { + } else if (value_type == IS_CONST) { zval_ptr_dtor(&value); } FREE_OP(free_value); return; } - Z_OBJ_HT_P(object)->write_property(object, property_name, value TSRMLS_CC); + Z_OBJ_HT_P(object)->write_property(object, property_name, value, key TSRMLS_CC); } else { /* Note: property_name in this case is really the array index! */ if (!Z_OBJ_HT_P(object)->write_dimension) { @@ -595,8 +764,8 @@ Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC); } - if (!RETURN_VALUE_UNUSED(result) && !EG(exception)) { - AI_SET_PTR(T(result->u.var).var, value); + if (retval && !EG(exception)) { + *retval = value; PZVAL_LOCK(value); } zval_ptr_dtor(&value); @@ -613,17 +782,30 @@ } if (T->str_offset.offset >= Z_STRLEN_P(T->str_offset.str)) { - Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1); + if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) { + char *tmp = (char *) emalloc(T->str_offset.offset+1+1); + + memcpy(tmp, Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1); + Z_STRVAL_P(T->str_offset.str) = tmp; + } else { + Z_STRVAL_P(T->str_offset.str) = (char *) erealloc(Z_STRVAL_P(T->str_offset.str), T->str_offset.offset+1+1); + } memset(Z_STRVAL_P(T->str_offset.str) + Z_STRLEN_P(T->str_offset.str), ' ', T->str_offset.offset - Z_STRLEN_P(T->str_offset.str)); Z_STRVAL_P(T->str_offset.str)[T->str_offset.offset+1] = 0; Z_STRLEN_P(T->str_offset.str) = T->str_offset.offset+1; + } else if (IS_INTERNED(Z_STRVAL_P(T->str_offset.str))) { + char *tmp = (char *) emalloc(Z_STRLEN_P(T->str_offset.str) + 1); + + memcpy(tmp, Z_STRVAL_P(T->str_offset.str), Z_STRLEN_P(T->str_offset.str) + 1); + Z_STRVAL_P(T->str_offset.str) = tmp; } if (Z_TYPE_P(value) != IS_STRING) { - zval tmp = *value; - + zval tmp; + + ZVAL_COPY_VALUE(&tmp, value); if (value_type != IS_TMP_VAR) { zval_copy_ctor(&tmp); } @@ -647,88 +829,104 @@ return 1; } -static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value, int is_tmp_var TSRMLS_DC) + +static inline zval* zend_assign_tmp_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC) { zval *variable_ptr = *variable_ptr_ptr; zval garbage; - if (variable_ptr == EG(error_zval_ptr)) { - if (is_tmp_var) { - zval_dtor(value); - } - return EG(uninitialized_zval_ptr); - } - - if (Z_TYPE_P(variable_ptr) == IS_OBJECT && Z_OBJ_HANDLER_P(variable_ptr, set)) { + if (Z_TYPE_P(variable_ptr) == IS_OBJECT && + UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) { Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC); return variable_ptr; } - if (PZVAL_IS_REF(variable_ptr)) { - if (variable_ptr!=value) { + if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) { + if (Z_DELREF_P(variable_ptr)==0) { + ZVAL_COPY_VALUE(&garbage, variable_ptr); + INIT_PZVAL_COPY(variable_ptr, value); + zendi_zval_dtor(garbage); + return variable_ptr; + } else { /* we need to split */ + ALLOC_ZVAL(variable_ptr); + INIT_PZVAL_COPY(variable_ptr, value); + *variable_ptr_ptr = variable_ptr; + return variable_ptr; + } + } else { + if (EXPECTED(variable_ptr != value)) { zend_uint refcount = Z_REFCOUNT_P(variable_ptr); - garbage = *variable_ptr; - *variable_ptr = *value; + ZVAL_COPY_VALUE(&garbage, variable_ptr); + ZVAL_COPY_VALUE(variable_ptr, value); Z_SET_REFCOUNT_P(variable_ptr, refcount); Z_SET_ISREF_P(variable_ptr); - if (!is_tmp_var) { - zendi_zval_copy_ctor(*variable_ptr); - } zendi_zval_dtor(garbage); - return variable_ptr; } - } else { + return variable_ptr; + } +} + + +static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC) +{ + zval *variable_ptr = *variable_ptr_ptr; + zval garbage; + + if (Z_TYPE_P(variable_ptr) == IS_OBJECT && + UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) { + Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC); + return variable_ptr; + } + + if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) { if (Z_DELREF_P(variable_ptr)==0) { - if (!is_tmp_var) { - if (variable_ptr==value) { - Z_ADDREF_P(variable_ptr); - } else if (PZVAL_IS_REF(value)) { - garbage = *variable_ptr; - *variable_ptr = *value; - INIT_PZVAL(variable_ptr); - zval_copy_ctor(variable_ptr); - zendi_zval_dtor(garbage); - return variable_ptr; - } else { - Z_ADDREF_P(value); - *variable_ptr_ptr = value; - if (variable_ptr != &EG(uninitialized_zval)) { - GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr); - zval_dtor(variable_ptr); - efree(variable_ptr); - } - return value; - } - } else { - garbage = *variable_ptr; - *variable_ptr = *value; - INIT_PZVAL(variable_ptr); + if (variable_ptr==value) { + Z_ADDREF_P(variable_ptr); + return variable_ptr; + } else if (PZVAL_IS_REF(value)) { + ZVAL_COPY_VALUE(&garbage, variable_ptr); + INIT_PZVAL_COPY(variable_ptr, value); + zval_copy_ctor(variable_ptr); zendi_zval_dtor(garbage); return variable_ptr; + } else { + Z_ADDREF_P(value); + *variable_ptr_ptr = value; + if (variable_ptr != &EG(uninitialized_zval)) { + GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr); + zval_dtor(variable_ptr); + efree(variable_ptr); + } + return value; } } else { /* we need to split */ - if (!is_tmp_var) { - if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) { - ALLOC_ZVAL(variable_ptr); - *variable_ptr_ptr = variable_ptr; - *variable_ptr = *value; - zval_copy_ctor(variable_ptr); - Z_SET_REFCOUNT_P(variable_ptr, 1); - } else { - *variable_ptr_ptr = value; - Z_ADDREF_P(value); - } + if (PZVAL_IS_REF(value) && Z_REFCOUNT_P(value) > 0) { + ALLOC_ZVAL(variable_ptr); + INIT_PZVAL_COPY(variable_ptr, value); + zval_copy_ctor(variable_ptr); + *variable_ptr_ptr = variable_ptr; + return variable_ptr; } else { - ALLOC_ZVAL(*variable_ptr_ptr); - Z_SET_REFCOUNT_P(value, 1); - **variable_ptr_ptr = *value; + *variable_ptr_ptr = value; + Z_ADDREF_P(value); + Z_UNSET_ISREF_P(value); + return value; } } - Z_UNSET_ISREF_PP(variable_ptr_ptr); + } else { + if (EXPECTED(variable_ptr != value)) { + zend_uint refcount = Z_REFCOUNT_P(variable_ptr); + + ZVAL_COPY_VALUE(&garbage, variable_ptr); + ZVAL_COPY_VALUE(variable_ptr, value); + Z_SET_REFCOUNT_P(variable_ptr, refcount); + Z_SET_ISREF_P(variable_ptr); + zendi_zval_copy_ctor(*variable_ptr); + zendi_zval_dtor(garbage); + } + return variable_ptr; } - - return *variable_ptr_ptr; } @@ -757,9 +955,9 @@ } -static inline HashTable *zend_get_target_symbol_table(const zend_op *opline, const temp_variable *Ts, int type, const zval *variable TSRMLS_DC) +static inline HashTable *zend_get_target_symbol_table(int fetch_type TSRMLS_DC) { - switch (opline->op2.u.EA.type) { + switch (fetch_type) { case ZEND_FETCH_LOCAL: if (!EG(active_symbol_table)) { zend_rebuild_symbol_table(TSRMLS_C); @@ -782,26 +980,38 @@ return NULL; } -static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int type TSRMLS_DC) +static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type TSRMLS_DC) { zval **retval; char *offset_key; int offset_key_length; long index; + ulong hval; switch (dim->type) { case IS_NULL: offset_key = ""; offset_key_length = 0; + hval = zend_inline_hash_func("", 1); goto fetch_string_dim; case IS_STRING: offset_key = dim->value.str.val; offset_key_length = dim->value.str.len; - + + if (dim_type == IS_CONST) { + hval = Z_HASH_P(dim); + } else { + ZEND_HANDLE_NUMERIC_EX(offset_key, offset_key_length+1, index, goto num_index); + if (IS_INTERNED(offset_key)) { + hval = INTERNED_HASH(offset_key); + } else { + hval = zend_hash_func(offset_key, offset_key_length+1); + } + } fetch_string_dim: - if (zend_symtable_find(ht, offset_key, offset_key_length+1, (void **) &retval) == FAILURE) { + if (zend_hash_quick_find(ht, offset_key, offset_key_length+1, hval, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: zend_error(E_NOTICE, "Undefined index: %s", offset_key); @@ -817,7 +1027,7 @@ zval *new_zval = &EG(uninitialized_zval); Z_ADDREF_P(new_zval); - zend_symtable_update(ht, offset_key, offset_key_length+1, &new_zval, sizeof(zval *), (void **) &retval); + zend_hash_quick_update(ht, offset_key, offset_key_length+1, hval, &new_zval, sizeof(zval *), (void **) &retval); } break; } @@ -864,7 +1074,7 @@ return retval; } -static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC) +static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_type, int type TSRMLS_DC) { zval *container = *container_ptr; zval **retval; @@ -887,7 +1097,7 @@ Z_DELREF_P(new_zval); } } else { - retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, type TSRMLS_CC); + retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC); } result->var.ptr_ptr = retval; PZVAL_LOCK(*retval); @@ -895,7 +1105,7 @@ break; case IS_NULL: - if (container == EG(error_zval_ptr)) { + if (container == &EG(error_zval)) { result->var.ptr_ptr = &EG(error_zval_ptr); PZVAL_LOCK(EG(error_zval_ptr)); } else if (type != BP_VAR_UNSET) { @@ -963,7 +1173,7 @@ } else { zval *overloaded_result; - if (dim_is_tmp_var) { + if (dim_type == IS_TMP_VAR) { zval *orig = dim; MAKE_REAL_ZVAL_PTR(dim); ZVAL_NULL(orig); @@ -976,7 +1186,7 @@ zval *tmp = overloaded_result; ALLOC_ZVAL(overloaded_result); - *overloaded_result = *tmp; + ZVAL_COPY_VALUE(overloaded_result, tmp); zval_copy_ctor(overloaded_result); Z_UNSET_ISREF_P(overloaded_result); Z_SET_REFCOUNT_P(overloaded_result, 0); @@ -990,9 +1200,9 @@ } else { retval = &EG(error_zval_ptr); } - AI_SET_PTR(result->var, *retval); + AI_SET_PTR(result, *retval); PZVAL_LOCK(*retval); - if (dim_is_tmp_var) { + if (dim_type == IS_TMP_VAR) { zval_ptr_dtor(&dim); } } @@ -1008,8 +1218,8 @@ default: if (type == BP_VAR_UNSET) { zend_error(E_WARNING, "Cannot unset offset in a non-array variable"); - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + AI_SET_PTR(result, &EG(uninitialized_zval)); + PZVAL_LOCK(&EG(uninitialized_zval)); } else { zend_error(E_WARNING, "Cannot use a scalar value as an array"); result->var.ptr_ptr = &EG(error_zval_ptr); @@ -1019,7 +1229,7 @@ } } -static void zend_fetch_dimension_address_read(temp_variable *result, zval **container_ptr, zval *dim, int dim_is_tmp_var, int type TSRMLS_DC) +static void zend_fetch_dimension_address_read(temp_variable *result, zval **container_ptr, zval *dim, int dim_type, int type TSRMLS_DC) { zval *container = *container_ptr; zval **retval; @@ -1027,9 +1237,9 @@ switch (Z_TYPE_P(container)) { case IS_ARRAY: - retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, type TSRMLS_CC); + retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC); if (result) { - AI_SET_PTR(result->var, *retval); + AI_SET_PTR(result, *retval); PZVAL_LOCK(*retval); } return; @@ -1037,8 +1247,8 @@ case IS_NULL: if (result) { - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + AI_SET_PTR(result, &EG(uninitialized_zval)); + PZVAL_LOCK(&EG(uninitialized_zval)); } return; break; @@ -1060,7 +1270,7 @@ break; } - tmp = *dim; + ZVAL_COPY_VALUE(&tmp, dim); zval_copy_ctor(&tmp); convert_to_long(&tmp); dim = &tmp; @@ -1085,7 +1295,7 @@ } else { zval *overloaded_result; - if (dim_is_tmp_var) { + if (dim_type == IS_TMP_VAR) { zval *orig = dim; MAKE_REAL_ZVAL_PTR(dim); ZVAL_NULL(orig); @@ -1094,7 +1304,7 @@ if (overloaded_result) { if (result) { - AI_SET_PTR(result->var, overloaded_result); + AI_SET_PTR(result, overloaded_result); PZVAL_LOCK(overloaded_result); } else if (Z_REFCOUNT_P(overloaded_result) == 0) { /* Destroy unused result from offsetGet() magic method */ @@ -1102,10 +1312,10 @@ zval_ptr_dtor(&overloaded_result); } } else if (result) { - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + AI_SET_PTR(result, &EG(uninitialized_zval)); + PZVAL_LOCK(&EG(uninitialized_zval)); } - if (dim_is_tmp_var) { + if (dim_type == IS_TMP_VAR) { zval_ptr_dtor(&dim); } } @@ -1114,22 +1324,22 @@ default: if (result) { - AI_SET_PTR(result->var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + AI_SET_PTR(result, &EG(uninitialized_zval)); + PZVAL_LOCK(&EG(uninitialized_zval)); } return; break; } } -static void zend_fetch_property_address(temp_variable *result, zval **container_ptr, zval *prop_ptr, int type TSRMLS_DC) +static void zend_fetch_property_address(temp_variable *result, zval **container_ptr, zval *prop_ptr, const zend_literal *key, int type TSRMLS_DC) { zval *container = *container_ptr;; if (Z_TYPE_P(container) != IS_OBJECT) { - if (container == EG(error_zval_ptr)) { + if (container == &EG(error_zval)) { result->var.ptr_ptr = &EG(error_zval_ptr); - PZVAL_LOCK(*result->var.ptr_ptr); + PZVAL_LOCK(EG(error_zval_ptr)); return; } @@ -1152,13 +1362,13 @@ } if (Z_OBJ_HT_P(container)->get_property_ptr_ptr) { - zval **ptr_ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr TSRMLS_CC); + zval **ptr_ptr = Z_OBJ_HT_P(container)->get_property_ptr_ptr(container, prop_ptr, key TSRMLS_CC); if (NULL == ptr_ptr) { zval *ptr; if (Z_OBJ_HT_P(container)->read_property && - (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC)) != NULL) { - AI_SET_PTR(result->var, ptr); + (ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC)) != NULL) { + AI_SET_PTR(result, ptr); PZVAL_LOCK(ptr); } else { zend_error_noreturn(E_ERROR, "Cannot access undefined property for object with overloaded property access"); @@ -1168,9 +1378,9 @@ PZVAL_LOCK(*ptr_ptr); } } else if (Z_OBJ_HT_P(container)->read_property) { - zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type TSRMLS_CC); + zval *ptr = Z_OBJ_HT_P(container)->read_property(container, prop_ptr, type, key TSRMLS_CC); - AI_SET_PTR(result->var, ptr); + AI_SET_PTR(result, ptr); PZVAL_LOCK(ptr); } else { zend_error(E_WARNING, "This object doesn't support property references"); @@ -1179,7 +1389,7 @@ } } -static inline zend_brk_cont_element* zend_brk_cont(const zval *nest_levels_zval, int array_offset, const zend_op_array *op_array, const temp_variable *Ts TSRMLS_DC) +static inline zend_brk_cont_element* zend_brk_cont(zval *nest_levels_zval, int array_offset, const zend_op_array *op_array, const temp_variable *Ts TSRMLS_DC) { zval tmp; int nest_levels, original_nest_levels; @@ -1204,13 +1414,13 @@ switch (brk_opline->opcode) { case ZEND_SWITCH_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zend_switch_free(&T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zend_switch_free(&T(brk_opline->op1.var), brk_opline->extended_value TSRMLS_CC); } break; case ZEND_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zendi_zval_dtor(T(brk_opline->op1.u.var).tmp_var); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zendi_zval_dtor(T(brk_opline->op1.var).tmp_var); } break; } @@ -1256,29 +1466,36 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC) { - zval **return_value_ptr = &(*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.u.var)).var.ptr; + zval **return_value_ptr = &(*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.var)).var.ptr; ((zend_internal_function *) execute_data_ptr->function_state.function)->handler(execute_data_ptr->opline->extended_value, *return_value_ptr, execute_data_ptr->function_state.function->common.return_reference?return_value_ptr:NULL, execute_data_ptr->object, return_value_used TSRMLS_CC); } #define ZEND_VM_NEXT_OPCODE() \ CHECK_SYMBOL_TABLES() \ - EX(opline)++; \ + ZEND_VM_INC_OPCODE(); \ ZEND_VM_CONTINUE() #define ZEND_VM_SET_OPCODE(new_op) \ CHECK_SYMBOL_TABLES() \ - EX(opline) = new_op + OPLINE = new_op #define ZEND_VM_JMP(new_op) \ - CHECK_SYMBOL_TABLES() \ if (EXPECTED(!EG(exception))) { \ - EX(opline) = new_op; \ + ZEND_VM_SET_OPCODE(new_op); \ + } else { \ + LOAD_OPLINE(); \ } \ ZEND_VM_CONTINUE() #define ZEND_VM_INC_OPCODE() \ - EX(opline)++ + OPLINE++ +#ifdef __GNUC__ +# define ZEND_VM_GUARD(name) __asm__("#" #name) +#else +# define ZEND_VM_GUARD(name) +#endif + #include "zend_vm_execute.h" ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler) @@ -1296,12 +1513,12 @@ return zend_user_opcode_handlers[opcode]; } -ZEND_API zval *zend_get_zval_ptr(znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { - return get_zval_ptr(node, Ts, should_free, type); +ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { + return get_zval_ptr(op_type, node, Ts, should_free, type); } -ZEND_API zval **zend_get_zval_ptr_ptr(const znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { - return get_zval_ptr_ptr(node, Ts, should_free, type); +ZEND_API zval **zend_get_zval_ptr_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC) { + return get_zval_ptr_ptr(op_type, node, Ts, should_free, type); } /* Index: Zend/zend_extensions.h =================================================================== --- Zend/zend_extensions.h (revision 297868) +++ Zend/zend_extensions.h (working copy) @@ -28,7 +28,7 @@ /* The first number is the engine version and the rest is the date. * This way engine 2/3 API no. is always greater than engine 1 API no.. */ -#define ZEND_EXTENSION_API_NO 220090626 +#define ZEND_EXTENSION_API_NO 220100409 typedef struct _zend_extension_version_info { int zend_extension_api_no; Index: Zend/zend_execute.h =================================================================== --- Zend/zend_execute.h (revision 297868) +++ Zend/zend_execute.h (working copy) @@ -62,7 +62,7 @@ ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC); ZEND_API int zend_is_true(zval *op); #define safe_free_zval_ptr(p) safe_free_zval_ptr_rel(p ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC) -static inline void safe_free_zval_ptr_rel(zval *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) +static zend_always_inline void safe_free_zval_ptr_rel(zval *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { TSRMLS_FETCH(); @@ -71,14 +71,35 @@ } } ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC); -ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_autoload, zend_class_entry ***ce TSRMLS_DC); +ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC); ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_stringl(char *str, int str_len, zval *retval_ptr, char *string_name TSRMLS_DC); ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); ZEND_API int zend_eval_stringl_ex(char *str, int str_len, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC); -static inline int i_zend_is_true(zval *op) +static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) { + if (!Z_DELREF_P(zval_ptr)) { + TSRMLS_FETCH(); + + if (zval_ptr != &EG(uninitialized_zval)) { + GC_REMOVE_ZVAL_FROM_BUFFER(zval_ptr); + zval_dtor(zval_ptr); + efree_rel(zval_ptr); + } + } else { + TSRMLS_FETCH(); + + if (Z_REFCOUNT_P(zval_ptr) == 1) { + Z_UNSET_ISREF_P(zval_ptr); + } + + GC_ZVAL_CHECK_POSSIBLE_ROOT(zval_ptr); + } +} + +static zend_always_inline int i_zend_is_true(zval *op) +{ int result; switch (Z_TYPE_P(op)) { @@ -157,7 +178,7 @@ } \ } while (0) -static inline zend_vm_stack zend_vm_stack_new_page(int count) { +static zend_always_inline zend_vm_stack zend_vm_stack_new_page(int count) { zend_vm_stack page = (zend_vm_stack)emalloc(ZEND_MM_ALIGNED_SIZE(sizeof(*page)) + sizeof(void*) * count); page->top = ZEND_VM_STACK_ELEMETS(page); @@ -166,12 +187,12 @@ return page; } -static inline void zend_vm_stack_init(TSRMLS_D) +static zend_always_inline void zend_vm_stack_init(TSRMLS_D) { EG(argument_stack) = zend_vm_stack_new_page(ZEND_VM_STACK_PAGE_SIZE); } -static inline void zend_vm_stack_destroy(TSRMLS_D) +static zend_always_inline void zend_vm_stack_destroy(TSRMLS_D) { zend_vm_stack stack = EG(argument_stack); @@ -182,30 +203,30 @@ } } -static inline void zend_vm_stack_extend(int count TSRMLS_DC) +static zend_always_inline void zend_vm_stack_extend(int count TSRMLS_DC) { zend_vm_stack p = zend_vm_stack_new_page(count >= ZEND_VM_STACK_PAGE_SIZE ? count : ZEND_VM_STACK_PAGE_SIZE); p->prev = EG(argument_stack); EG(argument_stack) = p; } -static inline void **zend_vm_stack_top(TSRMLS_D) +static zend_always_inline void **zend_vm_stack_top(TSRMLS_D) { return EG(argument_stack)->top; } -static inline void zend_vm_stack_push(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_push(void *ptr TSRMLS_DC) { ZEND_VM_STACK_GROW_IF_NEEDED(1); *(EG(argument_stack)->top++) = ptr; } -static inline void zend_vm_stack_push_nocheck(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_push_nocheck(void *ptr TSRMLS_DC) { *(EG(argument_stack)->top++) = ptr; } -static inline void *zend_vm_stack_pop(TSRMLS_D) +static zend_always_inline void *zend_vm_stack_pop(TSRMLS_D) { void *el = *(--EG(argument_stack)->top); @@ -217,7 +238,7 @@ return el; } -static inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) +static zend_always_inline void *zend_vm_stack_alloc(size_t size TSRMLS_DC) { void *ret; @@ -246,7 +267,7 @@ return ret; } -static inline void zend_vm_stack_free_int(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free_int(void *ptr TSRMLS_DC) { if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (void**)ptr)) { zend_vm_stack p = EG(argument_stack); @@ -258,7 +279,7 @@ } } -static inline void zend_vm_stack_free(void *ptr TSRMLS_DC) +static zend_always_inline void zend_vm_stack_free(void *ptr TSRMLS_DC) { if (UNEXPECTED(ZEND_VM_STACK_ELEMETS(EG(argument_stack)) == (void**)ptr)) { zend_vm_stack p = EG(argument_stack); @@ -276,7 +297,7 @@ } } -static inline void** zend_vm_stack_push_args(int count TSRMLS_DC) +static zend_always_inline void** zend_vm_stack_push_args(int count TSRMLS_DC) { if (UNEXPECTED(EG(argument_stack)->top - ZEND_VM_STACK_ELEMETS(EG(argument_stack)) < count) || @@ -305,7 +326,7 @@ return EG(argument_stack)->top++; } -static inline void zend_vm_stack_clear_multiple(TSRMLS_D) +static zend_always_inline void zend_vm_stack_clear_multiple(TSRMLS_D) { void **p = EG(argument_stack)->top - 1; int delete_count = (int)(zend_uintptr_t) *p; @@ -313,12 +334,12 @@ while (--delete_count>=0) { zval *q = *(zval **)(--p); *p = NULL; - zval_ptr_dtor(&q); + i_zval_ptr_dtor(q ZEND_FILE_LINE_CC); } zend_vm_stack_free_int(p TSRMLS_CC); } -static inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) +static zend_always_inline zval** zend_vm_stack_get_arg(int requested_arg TSRMLS_DC) { void **p = EG(current_execute_data)->prev_execute_data->function_state.arguments; int arg_count = (int)(zend_uintptr_t) *p; @@ -329,7 +350,7 @@ return (zval**)p - arg_count + requested_arg - 1; } -static inline void zend_arg_types_stack_2_pop(zend_ptr_stack *stack, zval **object, zend_function **fbc) +static zend_always_inline void zend_arg_types_stack_2_pop(zend_ptr_stack *stack, zval **object, zend_function **fbc) { void *a, *b; @@ -339,7 +360,7 @@ *fbc = (zend_function *) b; } -static inline void zend_arg_types_stack_3_pop(zend_ptr_stack *stack, zend_class_entry **called_scope, zval **object, zend_function **fbc) +static zend_always_inline void zend_arg_types_stack_3_pop(zend_ptr_stack *stack, zend_class_entry **called_scope, zval **object, zend_function **fbc) { void *a, *b, *c; @@ -364,6 +385,7 @@ ZEND_API void zend_unset_timeout(TSRMLS_D); ZEND_API void zend_timeout(int dummy); ZEND_API zend_class_entry *zend_fetch_class(const char *class_name, uint class_name_len, int fetch_type TSRMLS_DC); +ZEND_API zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC); void zend_verify_abstract_class(zend_class_entry *ce TSRMLS_DC); #ifdef ZEND_WIN32 @@ -402,8 +424,8 @@ /* int is_var; */ } zend_free_op; -ZEND_API zval *zend_get_zval_ptr(znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC); -ZEND_API zval **zend_get_zval_ptr_ptr(const znode *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC); +ZEND_API zval *zend_get_zval_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC); +ZEND_API zval **zend_get_zval_ptr_ptr(int op_type, const znode_op *node, const temp_variable *Ts, zend_free_op *should_free, int type TSRMLS_DC); ZEND_API int zend_do_fcall(ZEND_OPCODE_HANDLER_ARGS); Index: Zend/zend_variables.c =================================================================== --- Zend/zend_variables.c (revision 297868) +++ Zend/zend_variables.c (working copy) @@ -77,7 +77,9 @@ case IS_STRING: case IS_CONSTANT: CHECK_ZVAL_STRING_REL(zvalue); - free(zvalue->value.str.val); + if (!IS_INTERNED(zvalue->value.str.val)) { + free(zvalue->value.str.val); + } break; case IS_ARRAY: case IS_CONSTANT_ARRAY: @@ -117,7 +119,9 @@ case IS_CONSTANT: case IS_STRING: CHECK_ZVAL_STRING_REL(zvalue); - zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len); + if (!IS_INTERNED(zvalue->value.str.val)) { + zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len); + } break; case IS_ARRAY: case IS_CONSTANT_ARRAY: { Index: Zend/zend_modules.h =================================================================== --- Zend/zend_modules.h (revision 297868) +++ Zend/zend_modules.h (working copy) @@ -33,7 +33,7 @@ #define ZEND_MODULE_INFO_FUNC_ARGS zend_module_entry *zend_module TSRMLS_DC #define ZEND_MODULE_INFO_FUNC_ARGS_PASSTHRU zend_module TSRMLS_CC -#define ZEND_MODULE_API_NO 20090626 +#define ZEND_MODULE_API_NO 20100409 #ifdef ZTS #define USING_ZTS 1 #else Index: Zend/zend_variables.h =================================================================== --- Zend/zend_variables.h (revision 297868) +++ Zend/zend_variables.h (working copy) @@ -27,7 +27,7 @@ ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC); -static inline void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC) +static zend_always_inline void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC) { if (zvalue->type <= IS_BOOL) { return; @@ -37,7 +37,7 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC); -static inline void _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC) +static zend_always_inline void _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC) { if (zvalue->type <= IS_BOOL) { return; Index: Zend/zend_objects_API.c =================================================================== --- Zend/zend_objects_API.c (revision 297868) +++ Zend/zend_objects_API.c (working copy) @@ -353,7 +353,7 @@ zend_proxy_object *probj = zend_object_store_get_object(*property TSRMLS_CC); if (Z_OBJ_HT_P(probj->object) && Z_OBJ_HT_P(probj->object)->write_property) { - Z_OBJ_HT_P(probj->object)->write_property(probj->object, probj->property, value TSRMLS_CC); + Z_OBJ_HT_P(probj->object)->write_property(probj->object, probj->property, value, 0 TSRMLS_CC); } else { zend_error(E_WARNING, "Cannot write property of object - no write handler defined"); } @@ -364,7 +364,7 @@ zend_proxy_object *probj = zend_object_store_get_object(property TSRMLS_CC); if (Z_OBJ_HT_P(probj->object) && Z_OBJ_HT_P(probj->object)->read_property) { - return Z_OBJ_HT_P(probj->object)->read_property(probj->object, probj->property, BP_VAR_R TSRMLS_CC); + return Z_OBJ_HT_P(probj->object)->read_property(probj->object, probj->property, BP_VAR_R, 0 TSRMLS_CC); } else { zend_error(E_WARNING, "Cannot read property of object - no read handler defined"); } Index: Zend/zend_objects_API.h =================================================================== --- Zend/zend_objects_API.h (revision 297868) +++ Zend/zend_objects_API.h (working copy) @@ -68,7 +68,7 @@ ZEND_API void zend_objects_store_del_ref(zval *object TSRMLS_DC); ZEND_API void zend_objects_store_add_ref_by_handle(zend_object_handle handle TSRMLS_DC); ZEND_API void zend_objects_store_del_ref_by_handle_ex(zend_object_handle handle, const zend_object_handlers *handlers TSRMLS_DC); -static inline void zend_objects_store_del_ref_by_handle(zend_object_handle handle TSRMLS_DC) { +static zend_always_inline void zend_objects_store_del_ref_by_handle(zend_object_handle handle TSRMLS_DC) { zend_objects_store_del_ref_by_handle_ex(handle, NULL TSRMLS_CC); } ZEND_API zend_uint zend_objects_store_get_refcount(zval *object TSRMLS_DC); Index: Zend/micro_bench.php =================================================================== --- Zend/micro_bench.php (revision 0) +++ Zend/micro_bench.php (revision 0) @@ -0,0 +1,275 @@ +b; + } + } + + function write_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b = 0; + } + } + + function assign_add_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b += 2; + } + } + + function pre_inc_prop($n) { + for ($i = 0; $i < $n; ++$i) { + ++$this->b; + } + } + + function pre_dec_prop($n) { + for ($i = 0; $i < $n; ++$i) { + --$this->b; + } + } + + function post_inc_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b++; + } + } + + function post_dec_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $this->b--; + } + } + + function isset_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $x = isset($this->b); + } + } + + function empty_prop($n) { + for ($i = 0; $i < $n; ++$i) { + $x = empty($this->b); + } + } + + function g() { + } + + function call($n) { + for ($i = 0; $i < $n; ++$i) { + $this->g(); + } + } + + function read_const($n) { + for ($i = 0; $i < $n; ++$i) { + $x = $this::TEST; + } + } + +} + +function read_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = Foo::$a; + } +} + +function write_static($n) { + for ($i = 0; $i < $n; ++$i) { + Foo::$a = 0; + } +} + +function isset_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = isset(Foo::$a); + } +} + +function empty_static($n) { + for ($i = 0; $i < $n; ++$i) { + $x = empty(Foo::$a); + } +} + +function call_static($n) { + for ($i = 0; $i < $n; ++$i) { + Foo::f(); + } +} + +function create_object($n) { + for ($i = 0; $i < $n; ++$i) { + $x = new Foo(); + } +} + +/*****/ + +function empty_loop($n) { + for ($i = 0; $i < $n; ++$i) { + } +} + +function getmicrotime() +{ + $t = gettimeofday(); + return ($t['sec'] + $t['usec'] / 1000000); +} + +function start_test() +{ + ob_start(); + return getmicrotime(); +} + +function end_test($start, $name, $overhead = null) +{ + global $total; + global $last_time; + $end = getmicrotime(); + ob_end_clean(); + $last_time = $end-$start; + $total += $last_time; + $num = number_format($last_time,3); + $pad = str_repeat(" ", 24-strlen($name)-strlen($num)); + if (is_null($overhead)) { + echo $name.$pad.$num."\n"; + } else { + $num2 = number_format($last_time - $overhead,3); + echo $name.$pad.$num." ".$num2."\n"; + } + ob_start(); + return getmicrotime(); +} + +function total() +{ + global $total; + $pad = str_repeat("-", 24); + echo $pad."\n"; + $num = number_format($total,3); + $pad = str_repeat(" ", 24-strlen("Total")-strlen($num)); + echo "Total".$pad.$num."\n"; +} + +const N = 5000000; + +$t0 = $t = start_test(); +empty_loop(N); +$t = end_test($t, 'empty_loop'); +$overhead = $last_time; +simpleucall(N); +$t = end_test($t, 'func()', $overhead); +simpleudcall(N); +$t = end_test($t, 'undef_func()', $overhead); +simpleicall(N); +$t = end_test($t, 'int_func()', $overhead); +Foo::read_static(N); +$t = end_test($t, '$x = self::$x', $overhead); +Foo::write_static(N); +$t = end_test($t, 'self::$x = 0', $overhead); +Foo::isset_static(N); +$t = end_test($t, 'isset(self::$x)', $overhead); +Foo::empty_static(N); +$t = end_test($t, 'empty(self::$x)', $overhead); +read_static(N); +$t = end_test($t, '$x = Foo::$x', $overhead); +write_static(N); +$t = end_test($t, 'Foo::$x = 0', $overhead); +isset_static(N); +$t = end_test($t, 'isset(Foo::$x)', $overhead); +empty_static(N); +$t = end_test($t, 'empty(Foo::$x)', $overhead); +Foo::call_static(N); +$t = end_test($t, 'self::f()', $overhead); +call_static(N); +$t = end_test($t, 'Foo::f()', $overhead); +$x = new Foo(); +$x->read_prop(N); +$t = end_test($t, '$x = $this->x', $overhead); +$x->write_prop(N); +$t = end_test($t, '$this->x = 0', $overhead); +$x->assign_add_prop(N); +$t = end_test($t, '$this->x += 2', $overhead); +$x->pre_inc_prop(N); +$t = end_test($t, '++$this->x', $overhead); +$x->pre_dec_prop(N); +$t = end_test($t, '--$this->x', $overhead); +$x->post_inc_prop(N); +$t = end_test($t, '$this->x++', $overhead); +$x->post_dec_prop(N); +$t = end_test($t, '$this->x--', $overhead); +$x->isset_prop(N); +$t = end_test($t, 'isset($this->x)', $overhead); +$x->empty_prop(N); +$t = end_test($t, 'empty($this->x)', $overhead); +$x->call(N); +$t = end_test($t, '$this->f()', $overhead); +$x->read_const(N); +$t = end_test($t, '$x = Foo::TEST', $overhead); +create_object(N); +$t = end_test($t, 'new Foo()', $overhead); +total($t0, "Total"); Index: Zend/zend_builtin_functions.c =================================================================== --- Zend/zend_builtin_functions.c (revision 297868) +++ Zend/zend_builtin_functions.c (working copy) @@ -681,7 +681,7 @@ zval_ptr_dtor(&val_free); } c.flags = case_sensitive; /* non persistent */ - c.name = zend_strndup(name, name_len); + c.name = IS_INTERNED(name) ? name : zend_strndup(name, name_len); c.name_len = name_len+1; c.module_number = PHP_USER_CONSTANT; if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) { @@ -839,7 +839,7 @@ RETURN_FALSE; } - if (zend_lookup_class_ex(class_name, class_name_len, 0, &ce TSRMLS_CC) == FAILURE) { + if (zend_lookup_class_ex(class_name, class_name_len, NULL, 0, &ce TSRMLS_CC) == FAILURE) { retval = 0; } else { if (only_subclass) { @@ -1102,7 +1102,7 @@ if (Z_TYPE_P(klass) == IS_OBJECT && Z_OBJ_HT_P(klass)->get_method != NULL - && (func = Z_OBJ_HT_P(klass)->get_method(&klass, method_name, method_len TSRMLS_CC)) != NULL + && (func = Z_OBJ_HT_P(klass)->get_method(&klass, method_name, method_len, NULL TSRMLS_CC)) != NULL ) { if (func->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)func)->handler == zend_std_call_user_call @@ -1160,7 +1160,7 @@ if (Z_TYPE_P(object) == IS_OBJECT && Z_OBJ_HANDLER_P(object, has_property) && - Z_OBJ_HANDLER_P(object, has_property)(object, &property_z, 2 TSRMLS_CC)) { + Z_OBJ_HANDLER_P(object, has_property)(object, &property_z, 2, 0 TSRMLS_CC)) { RETURN_TRUE; } RETURN_FALSE; @@ -2021,7 +2021,7 @@ function_name = "unknown"; build_filename_arg = 0; } else - switch (Z_LVAL(ptr->opline->op2.u.constant)) { + switch (ptr->opline->extended_value) { case ZEND_EVAL: function_name = "eval"; build_filename_arg = 0; @@ -2204,7 +2204,7 @@ function_name = "unknown"; build_filename_arg = 0; } else - switch (ptr->opline->op2.u.constant.value.lval) { + switch (ptr->opline->extended_value) { case ZEND_EVAL: function_name = "eval"; build_filename_arg = 0; Index: Zend/zend_closures.c =================================================================== --- Zend/zend_closures.c (revision 297868) +++ Zend/zend_closures.c (working copy) @@ -111,7 +111,7 @@ } /* }}} */ -static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */ +static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */ { char *lc_name; ALLOCA_FLAG(use_heap) @@ -129,7 +129,7 @@ } /* }}} */ -static zval *zend_closure_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +static zval *zend_closure_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { ZEND_CLOSURE_PROPERTY_ERROR(); Z_ADDREF(EG(uninitialized_zval)); @@ -137,20 +137,20 @@ } /* }}} */ -static void zend_closure_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ +static void zend_closure_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ { ZEND_CLOSURE_PROPERTY_ERROR(); } /* }}} */ -static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { ZEND_CLOSURE_PROPERTY_ERROR(); return NULL; } /* }}} */ -static int zend_closure_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */ +static int zend_closure_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { if (has_set_exists != 2) { ZEND_CLOSURE_PROPERTY_ERROR(); @@ -159,7 +159,7 @@ } /* }}} */ -static void zend_closure_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static void zend_closure_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { ZEND_CLOSURE_PROPERTY_ERROR(); } @@ -245,7 +245,7 @@ MAKE_STD_ZVAL(val); array_init(val); zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*)); - zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL); + zend_hash_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL); } if (arg_info) { @@ -272,7 +272,7 @@ efree(name); arg_info++; } - zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL); + zend_hash_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL); } } Index: Zend/zend_language_scanner.l =================================================================== --- Zend/zend_language_scanner.l (revision 297868) +++ Zend/zend_language_scanner.l (working copy) @@ -408,7 +408,13 @@ ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_DC) { /* enforce two trailing NULLs for flex... */ - str->value.str.val = safe_erealloc(str->value.str.val, 1, str->value.str.len, ZEND_MMAP_AHEAD); + if (IS_INTERNED(str->value.str.val)) { + char *tmp = safe_emalloc(1, str->value.str.len, ZEND_MMAP_AHEAD); + memcpy(tmp, str->value.str.val, str->value.str.len + ZEND_MMAP_AHEAD); + str->value.str.val = tmp; + } else { + str->value.str.val = safe_erealloc(str->value.str.val, 1, str->value.str.len, ZEND_MMAP_AHEAD); + } memset(str->value.str.val + str->value.str.len, 0, ZEND_MMAP_AHEAD); Index: Zend/zend_string.c =================================================================== --- Zend/zend_string.c (revision 0) +++ Zend/zend_string.c (revision 0) @@ -0,0 +1,229 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov | + +----------------------------------------------------------------------+ +*/ + +/* $Id: $ */ + +#include "zend.h" +#include "zend_globals.h" + +#if ZEND_DEBUG && 1 +# define ZEND_DEBUG_INTERNED_STRINGS 1 +#endif + +#if ZEND_DEBUG_INTERNED_STRINGS +# include +#endif + +static char *zend_new_interned_string(char *str, int len, int free_src TSRMLS_DC); +static void zend_interned_strings_snapshot(TSRMLS_D); +static void zend_interned_strings_restore(TSRMLS_D); + +void zend_interned_strings_init(TSRMLS_D) +{ +#ifndef ZTS + size_t size = 1024 * 1024; + +#if ZEND_DEBUG_INTERNED_STRINGS + CG(interned_strings_start) = valloc(size); +#else + CG(interned_strings_start) = malloc(size); +#endif + + CG(interned_strings_top) = CG(interned_strings_start); + CG(interned_strings_snapshot_top) = CG(interned_strings_start); + CG(interned_strings_end) = CG(interned_strings_start) + size; + + zend_hash_init(&CG(interned_strings), 0, NULL, NULL, 1); + + CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1; + CG(interned_strings).arBuckets = (Bucket **) pecalloc(CG(interned_strings).nTableSize, sizeof(Bucket *), CG(interned_strings).persistent); + +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ); +#endif + +#endif + + CG(new_interned_string) = zend_new_interned_string; + CG(interned_strings_snapshot) = zend_interned_strings_snapshot; + CG(interned_strings_restore) = zend_interned_strings_restore; +} + +void zend_interned_strings_dtor(TSRMLS_D) +{ +#ifndef ZTS +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ); +#endif + free(CG(interned_strings).arBuckets); + free(CG(interned_strings_start)); +#endif +} + +static char *zend_new_interned_string(char *arKey, int nKeyLength, int free_src TSRMLS_DC) +{ +#ifndef ZTS + ulong h; + uint nIndex; + Bucket *p; + + if (IS_INTERNED(arKey)) { + return arKey; + } + + h = zend_inline_hash_func(arKey, nKeyLength); + nIndex = h & CG(interned_strings).nTableMask; + p = CG(interned_strings).arBuckets[nIndex]; + while (p != NULL) { + if ((p->h == h) && (p->nKeyLength == nKeyLength)) { + if (!memcmp(p->arKey, arKey, nKeyLength)) { + if (free_src) { + efree(arKey); + } + return p->arKey; + } + } + p = p->pNext; + } + + if (CG(interned_strings_top) + ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength) >= + CG(interned_strings_end)) { + /* no memory */ + return arKey; + } + + p = (Bucket *) CG(interned_strings_top); + CG(interned_strings_top) += ZEND_MM_ALIGNED_SIZE(sizeof(Bucket) + nKeyLength); + +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ | PROT_WRITE); +#endif + + p->arKey = (char*)(p+1); + memcpy(p->arKey, arKey, nKeyLength); + if (free_src) { + efree(arKey); + } + p->nKeyLength = nKeyLength; + p->h = h; + p->pData = &p->pDataPtr; + p->pDataPtr = p; + + p->pNext = CG(interned_strings).arBuckets[nIndex]; + p->pLast = NULL; + if (p->pNext) { + p->pNext->pLast = p; + } + + HANDLE_BLOCK_INTERRUPTIONS(); + + p->pListLast = CG(interned_strings).pListTail; + CG(interned_strings).pListTail = p; + p->pListNext = NULL; + if (p->pListLast != NULL) { + p->pListLast->pListNext = p; + } + if (!CG(interned_strings).pListHead) { + CG(interned_strings).pListHead = p; + } + + CG(interned_strings).arBuckets[nIndex] = p; + + HANDLE_UNBLOCK_INTERRUPTIONS(); + + CG(interned_strings).nNumOfElements++; + + if (CG(interned_strings).nNumOfElements > CG(interned_strings).nTableSize) { + if ((CG(interned_strings).nTableSize << 1) > 0) { /* Let's double the table size */ + Bucket **t = (Bucket **) perealloc_recoverable(CG(interned_strings).arBuckets, (CG(interned_strings).nTableSize << 1) * sizeof(Bucket *), CG(interned_strings).persistent); + + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + CG(interned_strings).arBuckets = t; + CG(interned_strings).nTableSize = (CG(interned_strings).nTableSize << 1); + CG(interned_strings).nTableMask = CG(interned_strings).nTableSize - 1; + zend_hash_rehash(&CG(interned_strings)); + HANDLE_UNBLOCK_INTERRUPTIONS(); + } + } + } + +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ); +#endif + + return p->arKey; +#else + return arKey; +#endif +} + +static void zend_interned_strings_snapshot(TSRMLS_D) +{ + CG(interned_strings_snapshot_top) = CG(interned_strings_top); +} + +static void zend_interned_strings_restore(TSRMLS_D) +{ +#ifndef ZTS + Bucket *p; + int i; +#endif + + CG(interned_strings_top) = CG(interned_strings_snapshot_top); + +#ifndef ZTS +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_WRITE | PROT_READ); +#endif + + for (i = 0; i < CG(interned_strings).nTableSize; i++) { + p = CG(interned_strings).arBuckets[i]; + while (p && p->arKey > CG(interned_strings_top)) { + CG(interned_strings).nNumOfElements--; + if (p->pListLast != NULL) { + p->pListLast->pListNext = p->pListNext; + } else { + CG(interned_strings).pListHead = p->pListNext; + } + if (p->pListNext != NULL) { + p->pListNext->pListLast = p->pListLast; + } else { + CG(interned_strings).pListTail = p->pListLast; + } + p = p->pNext; + } + if (p) { + p->pLast = NULL; + } + CG(interned_strings).arBuckets[i] = p; + } + +#if ZEND_DEBUG_INTERNED_STRINGS + mprotect(CG(interned_strings_start), CG(interned_strings_end) - CG(interned_strings_start), PROT_READ); +#endif +#endif +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ Index: Zend/zend_string.h =================================================================== --- Zend/zend_string.h (revision 0) +++ Zend/zend_string.h (revision 0) @@ -0,0 +1,55 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Dmitry Stogov | + +----------------------------------------------------------------------+ +*/ + +/* $Id: $ */ + +#ifndef ZEND_STRING_H +#define ZEND_STRING_H + +#include "zend.h" + +void zend_interned_strings_init(TSRMLS_D); +void zend_interned_strings_dtor(TSRMLS_D); + +#ifndef ZTS + +#define IS_INTERNED(s) \ + (((s) >= CG(interned_strings_start)) && ((s) < CG(interned_strings_end))) + +#else + +#define IS_INTERNED(s) \ + (0) + +#endif + +#define INTERNED_LEN(s) \ + (((Bucket*)(((char*)(s))-sizeof(Bucket)))->nKeyLength) + +#define INTERNED_HASH(s) \ + (((Bucket*)(((char*)(s))-sizeof(Bucket)))->h) + +#endif /* ZEND_STRING_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ Index: Zend/zend_constants.c =================================================================== --- Zend/zend_constants.c (revision 297868) +++ Zend/zend_constants.c (working copy) @@ -32,13 +32,17 @@ if (!(c->flags & CONST_PERSISTENT)) { zval_dtor(&c->value); } - free(c->name); + if (!IS_INTERNED(c->name)) { + free(c->name); + } } void copy_zend_constant(zend_constant *c) { - c->name = zend_strndup(c->name, c->name_len - 1); + if (!IS_INTERNED(c->name)) { + c->name = zend_strndup(c->name, c->name_len - 1); + } if (!(c->flags & CONST_PERSISTENT)) { zval_copy_ctor(&c->value); } @@ -422,12 +426,14 @@ /* keep in mind that c->name_len already contains the '\0' */ lowercase_name = estrndup(c->name, c->name_len-1); zend_str_tolower(lowercase_name, c->name_len-1); + lowercase_name = CG(new_interned_string)(lowercase_name, c->name_len, 1 TSRMLS_CC); name = lowercase_name; } else { char *slash = strrchr(c->name, '\\'); if(slash) { lowercase_name = estrndup(c->name, c->name_len-1); zend_str_tolower(lowercase_name, slash-c->name); + lowercase_name = CG(new_interned_string)(lowercase_name, c->name_len, 1 TSRMLS_CC); name = lowercase_name; } else { name = c->name; @@ -437,13 +443,15 @@ if ((strncmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1) == 0) || zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE) { zend_error(E_NOTICE,"Constant %s already defined", name); - free(c->name); + if (!IS_INTERNED(c->name)) { + free(c->name); + } if (!(c->flags & CONST_PERSISTENT)) { zval_dtor(&c->value); } ret = FAILURE; } - if (lowercase_name) { + if (lowercase_name && !IS_INTERNED(lowercase_name)) { efree(lowercase_name); } return ret; Index: Zend/zend_object_handlers.c =================================================================== --- Zend/zend_object_handlers.c (revision 297868) +++ Zend/zend_object_handlers.c (working copy) @@ -191,12 +191,11 @@ } /* }}} */ -ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC) /* {{{ */ +static struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, ulong h TSRMLS_DC) /* {{{ */ { zend_property_info *property_info = NULL; zend_property_info *scope_property_info; zend_bool denied_access = 0; - ulong h; if (Z_STRVAL_P(member)[0] == '\0') { if (!silent) { @@ -208,7 +207,6 @@ } return NULL; } - h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1); if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) { if(property_info->flags & ZEND_ACC_SHADOW) { /* if it's a shadow - go to access it's private */ @@ -261,6 +259,14 @@ } /* }}} */ +ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC) /* {{{ */ +{ + zend_ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1); + + return zend_get_property_info_quick(ce, member, silent, h TSRMLS_CC); +} +/* }}} */ + ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name, int prop_info_name_len TSRMLS_DC) /* {{{ */ { zend_property_info *property_info; @@ -311,7 +317,7 @@ } /* }}} */ -zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ +zval *zend_std_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; zval *tmp_member = NULL; @@ -330,6 +336,7 @@ zval_copy_ctor(tmp_member); convert_to_string(tmp_member); member = tmp_member; + key = NULL; } #if DEBUG_OBJECT_HANDLERS @@ -337,7 +344,11 @@ #endif /* make zend_get_property_info silent if we have getter - we may want to use it */ - property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); + if (key) { + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key->hash_value TSRMLS_CC); + } else { + property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); + } if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { zend_guard *guard; @@ -388,7 +399,7 @@ } /* }}} */ -static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ +static void zend_std_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; zval *tmp_member = NULL; @@ -404,9 +415,14 @@ zval_copy_ctor(tmp_member); convert_to_string(tmp_member); member = tmp_member; + key = NULL; } - property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC); + if (key) { + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__set != NULL), key->hash_value TSRMLS_CC); + } else { + property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC); + } if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) { /* if we already have this value there, we don't actually need to do anything */ @@ -552,7 +568,7 @@ } /* }}} */ -static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; zval tmp_member; @@ -566,13 +582,18 @@ zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); member = &tmp_member; + key = NULL; } #if DEBUG_OBJECT_HANDLERS fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); #endif - property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); + if (key) { + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key->hash_value TSRMLS_CC); + } else { + property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC); + } if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) { zval *new_zval; @@ -599,7 +620,7 @@ } /* }}} */ -static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */ +static void zend_std_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; zval *tmp_member = NULL; @@ -614,9 +635,14 @@ zval_copy_ctor(tmp_member); convert_to_string(tmp_member); member = tmp_member; + key = NULL; } - property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC); + if (key) { + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__unset != NULL), key->hash_value TSRMLS_CC); + } else { + property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC); + } if (!property_info || zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE) { zend_guard *guard; @@ -702,7 +728,7 @@ * Returns the function address that should be called, or NULL * if no such function exists. */ -static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ +static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen, ulong hash_value TSRMLS_DC) /* {{{ */ { if (!ce) { return 0; @@ -724,7 +750,7 @@ ce = ce->parent; while (ce) { if (ce == EG(scope)) { - if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS + if (zend_hash_quick_find(&ce->function_table, function_name_strval, function_name_strlen+1, hash_value, (void **) &fbc)==SUCCESS && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE && fbc->common.scope == EG(scope)) { return fbc; @@ -739,7 +765,7 @@ ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ { - return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL; + return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen, zend_hash_func(function_name_strval, function_name_strlen+1) TSRMLS_CC) != NULL; } /* }}} */ @@ -796,21 +822,29 @@ } /* }}} */ -static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */ +static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */ { - zend_object *zobj; zend_function *fbc; + zval *object = *object_ptr; + zend_object *zobj = Z_OBJ_P(object); + ulong hash_value; char *lc_method_name; - zval *object = *object_ptr; ALLOCA_FLAG(use_heap) - lc_method_name = do_alloca(method_len+1, use_heap); - /* Create a zend_copy_str_tolower(dest, src, src_length); */ - zend_str_tolower_copy(lc_method_name, method_name, method_len); + if (key) { + lc_method_name = Z_STRVAL(key->constant); + hash_value = key->hash_value; + } else { + lc_method_name = do_alloca(method_len+1, use_heap); + /* Create a zend_copy_str_tolower(dest, src, src_length); */ + zend_str_tolower_copy(lc_method_name, method_name, method_len); + hash_value = zend_hash_func(lc_method_name, method_len+1); + } - zobj = Z_OBJ_P(object); - if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) { - free_alloca(lc_method_name, use_heap); + if (zend_hash_quick_find(&zobj->ce->function_table, lc_method_name, method_len+1, hash_value, (void **)&fbc) == FAILURE) { + if (!key) { + free_alloca(lc_method_name, use_heap); + } if (zobj->ce->__call) { return zend_get_user_call_function(zobj->ce, method_name, method_len); } else { @@ -825,7 +859,7 @@ /* Ensure that if we're calling a private function, we're allowed to do so. * If we're not and __call() handler exists, invoke it, otherwise error out. */ - updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC); + updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len, hash_value TSRMLS_CC); if (updated_fbc) { fbc = updated_fbc; } else { @@ -844,7 +878,7 @@ fbc->op_array.fn_flags & ZEND_ACC_CHANGED) { zend_function *priv_fbc; - if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS + if (zend_hash_quick_find(&EG(scope)->function_table, lc_method_name, method_len+1, hash_value, (void **) &priv_fbc)==SUCCESS && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE && priv_fbc->common.scope == EG(scope)) { fbc = priv_fbc; @@ -864,7 +898,9 @@ } } - free_alloca(lc_method_name, use_heap); + if (!key) { + free_alloca(lc_method_name, use_heap); + } return fbc; } /* }}} */ @@ -933,13 +969,23 @@ /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */ -ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */ +ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_function *fbc = NULL; char *lc_class_name, *lc_function_name = NULL; + ulong hash_value; + ALLOCA_FLAG(use_heap) + + if (key) { + lc_function_name = Z_STRVAL(key->constant); + hash_value = key->hash_value; + } else { + lc_function_name = do_alloca(function_name_strlen+1, use_heap); + /* Create a zend_copy_str_tolower(dest, src, src_length); */ + zend_str_tolower_copy(lc_function_name, function_name_strval, function_name_strlen); + hash_value = zend_hash_func(lc_function_name, function_name_strlen+1); + } - lc_function_name = zend_str_tolower_dup(function_name_strval, function_name_strlen); - if (function_name_strlen == ce->name_length && ce->constructor) { lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length); /* Only change the method to the constructor if the constructor isn't called __construct @@ -950,8 +996,10 @@ } efree(lc_class_name); } - if (!fbc && zend_hash_find(&ce->function_table, lc_function_name, function_name_strlen+1, (void **) &fbc)==FAILURE) { - efree(lc_function_name); + if (!fbc && zend_hash_quick_find(&ce->function_table, lc_function_name, function_name_strlen+1, hash_value, (void **) &fbc)==FAILURE) { + if (!key) { + free_alloca(lc_function_name, use_heap); + } if (ce->__callstatic) { return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); @@ -964,7 +1012,6 @@ return NULL; } } - efree(lc_function_name); #if MBO_0 /* right now this function is used for non static method lookup too */ @@ -980,42 +1027,55 @@ /* Ensure that if we're calling a private function, we're allowed to do so. */ - updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC); + updated_fbc = zend_check_private_int(fbc, EG(scope), lc_function_name, function_name_strlen, hash_value TSRMLS_CC); if (updated_fbc) { fbc = updated_fbc; } else { if (ce->__callstatic) { - return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); + fbc = zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); + } else { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); } - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); } } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) { if (ce->__callstatic) { - return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); + fbc = zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen); + } else { + zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); } - zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : ""); } } + if (!key) { + free_alloca(lc_function_name, use_heap); + } + return fbc; } /* }}} */ -ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC) /* {{{ */ +ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent, const zend_literal *key TSRMLS_DC) /* {{{ */ { zval **retval = NULL; zend_class_entry *tmp_ce = ce; zend_property_info *property_info; zend_property_info std_property_info; + ulong hash_value; + + if (key) { + hash_value = key->hash_value; + } else { + hash_value = zend_hash_func(property_name, property_name_len+1); + } - if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE) { + if (zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE) { std_property_info.flags = ZEND_ACC_PUBLIC; std_property_info.name = property_name; std_property_info.name_length = property_name_len; - std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1); + std_property_info.h = hash_value; std_property_info.ce = ce; property_info = &std_property_info; } @@ -1047,7 +1107,7 @@ } /* }}} */ -ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC) /* {{{ */ +ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name); return 0; @@ -1107,7 +1167,7 @@ } /* }}} */ -static int zend_std_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */ +static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; int result; @@ -1124,13 +1184,18 @@ zval_copy_ctor(tmp_member); convert_to_string(tmp_member); member = tmp_member; + key = NULL; } #if DEBUG_OBJECT_HANDLERS fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); #endif - property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC); + if (key) { + property_info = zend_get_property_info_quick(zobj->ce, member, 1, key->hash_value TSRMLS_CC); + } else { + property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC); + } if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) { zend_guard *guard; Index: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 297868) +++ Zend/zend_compile.c (working copy) @@ -32,6 +32,37 @@ #include "zend_multibyte.h" #endif /* ZEND_MULTIBYTE */ +#define CONSTANT_EX(op_array, op) \ + (op_array)->literals[op].constant + +#define CONSTANT(op) \ + CONSTANT_EX(CG(active_op_array), op) + +#define SET_NODE(target, src) do { \ + target ## _type = (src)->op_type; \ + if ((src)->op_type == IS_CONST) { \ + target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant); \ + } else { \ + target = (src)->u.op; \ + } \ + } while (0) + +#define GET_NODE(target, src) do { \ + (target)->op_type = src ## _type; \ + if ((target)->op_type == IS_CONST) { \ + (target)->u.constant = CONSTANT(src.constant); \ + } else { \ + (target)->u.op = src; \ + (target)->EA = 0; \ + } \ + } while (0) + +#define COPY_NODE(target, src) do { \ + target ## _type = src ## _type; \ + target = src; \ + } while (0) + + ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC); @@ -42,7 +73,9 @@ static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */ { - property_info->name = estrndup(property_info->name, property_info->name_length); + if (!IS_INTERNED(property_info->name)) { + property_info->name = estrndup(property_info->name, property_info->name_length); + } if (property_info->doc_comment) { property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len); } @@ -52,14 +85,18 @@ static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */ { - property_info->name = zend_strndup(property_info->name, property_info->name_length); + if (!IS_INTERNED(property_info->name)) { + property_info->name = zend_strndup(property_info->name, property_info->name_length); + } } /* }}} */ static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ */ { - efree(property_info->name); + if (!IS_INTERNED(property_info->name)) { + efree(property_info->name); + } if (property_info->doc_comment) { efree(property_info->doc_comment); } @@ -69,7 +106,9 @@ static void zend_destroy_property_info_internal(zend_property_info *property_info) /* {{{ */ { - free(property_info->name); + if (!IS_INTERNED(property_info->name)) { + free(property_info->name); + } } /* }}} */ @@ -261,17 +300,20 @@ } /* }}} */ -static int lookup_cv(zend_op_array *op_array, char* name, int name_len) /* {{{ */ +static int lookup_cv(zend_op_array *op_array, char* name, int name_len TSRMLS_DC) /* {{{ */ { int i = 0; ulong hash_value = zend_inline_hash_func(name, name_len+1); while (i < op_array->last_var) { - if (op_array->vars[i].hash_value == hash_value && - op_array->vars[i].name_len == name_len && - strcmp(op_array->vars[i].name, name) == 0) { - efree(name); - return i; + if (op_array->vars[i].name == name || + (op_array->vars[i].hash_value == hash_value && + op_array->vars[i].name_len == name_len && + memcmp(op_array->vars[i].name, name, name_len) == 0)) { + if (!IS_INTERNED(name)) { + efree(name); + } + return i; } i++; } @@ -281,24 +323,80 @@ op_array->size_var += 16; /* FIXME */ op_array->vars = erealloc(op_array->vars, op_array->size_var*sizeof(zend_compiled_variable)); } - op_array->vars[i].name = name; /* estrndup(name, name_len); */ + op_array->vars[i].name = CG(new_interned_string)(name, name_len + 1, 1 TSRMLS_CC); op_array->vars[i].name_len = name_len; op_array->vars[i].hash_value = hash_value; return i; } /* }}} */ +void zend_del_literal(zend_op_array *op_array, int n) /* {{{ */ +{ + zval_dtor(&CONSTANT_EX(op_array, n)); + if (n + 1 == op_array->last_literal) { + op_array->last_literal--; + } else { + Z_TYPE(CONSTANT_EX(op_array, n)) = IS_NULL; + } +} +/* }}} */ +int zend_add_literal(zend_op_array *op_array, const zval *zv) /* {{{ */ +{ + int i = op_array->last_literal; + op_array->last_literal++; + if (i >= op_array->size_literal) { + op_array->size_literal += 16; /* FIXME */ + op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->size_literal * sizeof(zend_literal)); + } + if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) { + zval *z = (zval*)zv; + TSRMLS_FETCH(); + + Z_STRVAL_P(z) = + CG(new_interned_string)(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + 1, 1 TSRMLS_CC); + } + CONSTANT_EX(op_array, i) = *zv; + Z_SET_REFCOUNT(CONSTANT_EX(op_array, i), 2); + Z_SET_ISREF(CONSTANT_EX(op_array, i)); + return i; +} +/* }}} */ + +#define LITERAL_STRINGL(op, str, len, copy) do { \ + zval _c; \ + ZVAL_STRINGL(&_c, str, len, copy); \ + op.constant = zend_add_literal(CG(active_op_array), &_c); \ + } while (0) + +#define LITERAL_LONG(op, val) do { \ + zval _c; \ + ZVAL_LONG(&_c, val); \ + op.constant = zend_add_literal(CG(active_op_array), &_c); \ + } while (0) + +#define LITERAL_LONG_EX(op_array, op, val) do { \ + zval _c; \ + ZVAL_LONG(&_c, val); \ + op.constant = zend_add_literal(op_array, &_c); \ + } while (0) + +#define LITERAL_NULL(op) do { \ + zval _c; \ + INIT_ZVAL( _c); \ + op.constant = zend_add_literal(CG(active_op_array), &_c); \ + } while (0) + void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *op1; - opline->op2 = *op2; - *result = opline->result; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, op1); + SET_NODE(opline->op2, op2); + GET_NODE(result, opline->result); } /* }}} */ @@ -307,21 +405,21 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *op1; - *result = opline->result; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, op1); + GET_NODE(result, opline->result); SET_UNUSED(opline->op2); } /* }}} */ -#define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(znode)); memset(&opline->op1,0,sizeof(znode)); memset(&opline->op2,0,sizeof(znode)); opline->result.op_type=opline->op1.op_type=opline->op2.op_type=IS_UNUSED; } +#define MAKE_NOP(opline) { opline->opcode = ZEND_NOP; memset(&opline->result,0,sizeof(opline->result)); memset(&opline->op1,0,sizeof(opline->op1)); memset(&opline->op2,0,sizeof(opline->op2)); opline->result_type=opline->op1_type=opline->op2_type=IS_UNUSED; } static void zend_do_op_data(zend_op *data_op, const znode *value TSRMLS_DC) /* {{{ */ { data_op->opcode = ZEND_OP_DATA; - data_op->op1 = *value; + SET_NODE(data_op->op1, value); SET_UNUSED(data_op->op2); } /* }}} */ @@ -341,18 +439,17 @@ zend_do_op_data(opline, op2 TSRMLS_CC); SET_UNUSED(opline->result); - *result = last_op->result; + GET_NODE(result, last_op->result); return; case ZEND_FETCH_DIM_RW: last_op->opcode = op; last_op->extended_value = ZEND_ASSIGN_DIM; zend_do_op_data(opline, op2 TSRMLS_CC); - opline->op2.u.var = get_temporary_variable(CG(active_op_array)); - opline->op2.u.EA.type = 0; - opline->op2.op_type = IS_VAR; + opline->op2.var = get_temporary_variable(CG(active_op_array)); + opline->op2_type = IS_VAR; SET_UNUSED(opline->result); - *result = last_op->result; + GET_NODE(result,last_op->result); return; default: break; @@ -360,12 +457,11 @@ } opline->opcode = op; - opline->op1 = *op1; - opline->op2 = *op2; - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + SET_NODE(opline->op1, op1); + SET_NODE(opline->op2, op2); + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } /* }}} */ @@ -385,8 +481,9 @@ (CG(active_op_array)->last == 0 || CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) { result->op_type = IS_CV; - result->u.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len); - result->u.EA.type = 0; + result->u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC); + varname->u.constant.value.str.val = CG(active_op_array)->vars[result->u.op.var].name; + result->EA = 0; return; } } @@ -399,17 +496,17 @@ } opline_ptr->opcode = op; - opline_ptr->result.op_type = IS_VAR; - opline_ptr->result.u.EA.type = 0; - opline_ptr->result.u.var = get_temporary_variable(CG(active_op_array)); - opline_ptr->op1 = *varname; - *result = opline_ptr->result; + opline_ptr->result_type = IS_VAR; + opline_ptr->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline_ptr->op1, varname); + GET_NODE(result, opline_ptr->result); SET_UNUSED(opline_ptr->op2); + opline_ptr->extended_value = ZEND_FETCH_LOCAL; - opline_ptr->op2.u.EA.type = ZEND_FETCH_LOCAL; - if (varname->op_type == IS_CONST && varname->u.constant.type == IS_STRING) { + if (varname->op_type == IS_CONST) { + Z_HASH_P(&CONSTANT(opline_ptr->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline_ptr->op1.constant)), Z_STRLEN(CONSTANT(opline_ptr->op1.constant))+1); if (zend_is_auto_global(varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC)) { - opline_ptr->op2.u.EA.type = ZEND_FETCH_GLOBAL; + opline_ptr->extended_value = ZEND_FETCH_GLOBAL; } } @@ -441,42 +538,39 @@ init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_W; - opline.result.op_type = IS_VAR; - opline.result.u.EA.type = 0; - opline.result.u.var = get_temporary_variable(CG(active_op_array)); - opline.op1.op_type = IS_CONST; - opline.op1.u.constant.type = IS_STRING; - opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[result->u.var].name); - opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[result->u.var].name_len; + opline.result_type = IS_VAR; + opline.result.var = get_temporary_variable(CG(active_op_array)); + opline.op1_type = IS_CONST; + LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0); + Z_HASH_P(&CONSTANT(opline.op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline.op1.constant)), Z_STRLEN(CONSTANT(opline.op1.constant))+1); SET_UNUSED(opline.op2); - opline.op2 = class_node; - opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; - *result = opline.result; + SET_NODE(opline.op2, &class_node); + GET_NODE(result,opline.result); + opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; + opline_ptr = &opline; zend_llist_add_element(fetch_list_ptr, &opline); } else { le = fetch_list_ptr->head; opline_ptr = (zend_op *)le->data; - if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1.op_type == IS_CV) { + if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) { init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_W; - opline.result.op_type = IS_VAR; - opline.result.u.EA.type = 0; - opline.result.u.var = get_temporary_variable(CG(active_op_array)); - opline.op1.op_type = IS_CONST; - opline.op1.u.constant.type = IS_STRING; - opline.op1.u.constant.value.str.val = estrdup(CG(active_op_array)->vars[opline_ptr->op1.u.var].name); - opline.op1.u.constant.value.str.len = CG(active_op_array)->vars[opline_ptr->op1.u.var].name_len; + opline.result_type = IS_VAR; + opline.result.var = get_temporary_variable(CG(active_op_array)); + opline.op1_type = IS_CONST; + LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0); + Z_HASH_P(&CONSTANT(opline.op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline.op1.constant)), Z_STRLEN(CONSTANT(opline.op1.constant))+1); SET_UNUSED(opline.op2); - opline.op2 = class_node; - opline.op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; - opline_ptr->op1 = opline.result; + SET_NODE(opline.op2, &class_node); + opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; + COPY_NODE(opline_ptr->op1, opline.result); zend_llist_prepend_element(fetch_list_ptr, &opline); } else { - opline_ptr->op2 = class_node; - opline_ptr->op2.u.EA.type = ZEND_FETCH_STATIC_MEMBER; + SET_NODE(opline_ptr->op2, &class_node); + opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER; } } } @@ -497,14 +591,25 @@ init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */ - opline.result.op_type = IS_VAR; - opline.result.u.EA.type = 0; - opline.result.u.var = get_temporary_variable(CG(active_op_array)); - opline.op1 = *parent; - opline.op2 = *dim; - opline.extended_value = ZEND_FETCH_STANDARD; - *result = opline.result; + opline.result_type = IS_VAR; + opline.result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline.op1, parent); + SET_NODE(opline.op2, dim); + if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) { + long index; + int numeric = 0; + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1); + if (numeric) { + zval_dtor(&CONSTANT(opline.op2.constant)); + ZVAL_LONG(&CONSTANT(opline.op2.constant), index); + } else { + Z_HASH_P(&CONSTANT(opline.op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1); + } + } + + GET_NODE(result, opline.result); + zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); zend_llist_add_element(fetch_list_ptr, &opline); } @@ -520,12 +625,12 @@ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); opline->opcode = ZEND_PRINT; - opline->op1 = *arg; + SET_NODE(opline->op1, arg); SET_UNUSED(opline->op2); - *result = opline->result; + GET_NODE(result, opline->result); } /* }}} */ @@ -534,7 +639,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ECHO; - opline->op1 = *arg; + SET_NODE(opline->op1, arg); SET_UNUSED(opline->op2); } /* }}} */ @@ -574,10 +679,10 @@ static zend_bool opline_is_fetch_this(const zend_op *opline TSRMLS_DC) /* {{{ */ { - if ((opline->opcode == ZEND_FETCH_W) && (opline->op1.op_type == IS_CONST) - && (opline->op1.u.constant.type == IS_STRING) - && (opline->op1.u.constant.value.str.len == (sizeof("this")-1)) - && !memcmp(opline->op1.u.constant.value.str.val, "this", sizeof("this"))) { + if ((opline->opcode == ZEND_FETCH_W) && (opline->op1_type == IS_CONST) + && (Z_TYPE(CONSTANT(opline->op1.constant)) == IS_STRING) + && (Z_STRLEN(CONSTANT(opline->op1.constant)) == (sizeof("this")-1)) + && !memcmp(Z_STRVAL(CONSTANT(opline->op1.constant)), "this", sizeof("this"))) { return 1; } else { return 0; @@ -585,7 +690,7 @@ } /* }}} */ -void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC) /* {{{ */ +void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */ { int last_op_number; zend_op *opline; @@ -598,21 +703,21 @@ opline = (zend_op *)fetch_list_ptr->head->data; if (opline->opcode == ZEND_FETCH_DIM_W && - opline->op1.op_type == IS_CV && - opline->op1.u.var == value->u.var) { + opline->op1_type == IS_CV && + opline->op1.var == value->u.op.var) { opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_R; - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1.op_type = IS_CONST; - ZVAL_STRINGL(&opline->op1.u.constant, - CG(active_op_array)->vars[value->u.var].name, - CG(active_op_array)->vars[value->u.var].name_len, 1); + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->op1_type = IS_CONST; + LITERAL_STRINGL(opline->op1, + CG(active_op_array)->vars[value->u.op.var].name, + CG(active_op_array)->vars[value->u.op.var].name_len, 1); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); SET_UNUSED(opline->op2); - opline->op2.u.EA.type = ZEND_FETCH_LOCAL; - value = &opline->result; + opline->extended_value = ZEND_FETCH_LOCAL; + GET_NODE(value, opline->result); } } } @@ -623,7 +728,7 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); if (variable->op_type == IS_CV) { - if (variable->u.var == CG(active_op_array)->this_var) { + if (variable->u.op.var == CG(active_op_array)->this_var) { zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); } } else if (variable->op_type == IS_VAR) { @@ -634,8 +739,8 @@ last_op = &CG(active_op_array)->opcodes[last_op_number-n-1]; - if (last_op->result.op_type == IS_VAR && - last_op->result.u.var == variable->u.var) { + if (last_op->result_type == IS_VAR && + last_op->result.var == variable->u.op.var) { if (last_op->opcode == ZEND_FETCH_OBJ_W) { if (n > 0) { int opline_no = (opline-CG(active_op_array)->opcodes)/sizeof(*opline); @@ -649,7 +754,7 @@ last_op->opcode = ZEND_ASSIGN_OBJ; zend_do_op_data(opline, value TSRMLS_CC); SET_UNUSED(opline->result); - *result = last_op->result; + GET_NODE(result, last_op->result); return; } else if (last_op->opcode == ZEND_FETCH_DIM_W) { if (n > 0) { @@ -664,11 +769,10 @@ } last_op->opcode = ZEND_ASSIGN_DIM; zend_do_op_data(opline, value TSRMLS_CC); - opline->op2.u.var = get_temporary_variable(CG(active_op_array)); - opline->op2.u.EA.type = 0; - opline->op2.op_type = IS_VAR; + opline->op2.var = get_temporary_variable(CG(active_op_array)); + opline->op2_type = IS_VAR; SET_UNUSED(opline->result); - *result = last_op->result; + GET_NODE(result, last_op->result); return; } else if (opline_is_fetch_this(last_op TSRMLS_CC)) { zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); @@ -681,18 +785,17 @@ } opline->opcode = ZEND_ASSIGN; - opline->op1 = *variable; - opline->op2 = *value; - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + SET_NODE(opline->op1, variable); + SET_NODE(opline->op2, value); + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } /* }}} */ static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */ { - zend_uint type = variable->u.EA.type; + zend_uint type = variable->EA; return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); } @@ -703,7 +806,7 @@ zend_op *opline; if (lvar->op_type == IS_CV) { - if (lvar->u.var == CG(active_op_array)->this_var) { + if (lvar->u.op.var == CG(active_op_array)->this_var) { zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); } } else if (lvar->op_type == IS_VAR) { @@ -721,22 +824,20 @@ opline->opcode = ZEND_ASSIGN_REF; if (zend_is_function_or_method_call(rvar)) { opline->extended_value = ZEND_RETURNS_FUNCTION; - } else if (rvar->u.EA.type & ZEND_PARSED_NEW) { + } else if (rvar->EA & ZEND_PARSED_NEW) { opline->extended_value = ZEND_RETURNS_NEW; } else { opline->extended_value = 0; } if (result) { - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } else { - /* SET_UNUSED(opline->result); */ - opline->result.u.EA.type |= EXT_TYPE_UNUSED; + opline->result_type = IS_UNUSED | EXT_TYPE_UNUSED; } - opline->op1 = *lvar; - opline->op2 = *rvar; + SET_NODE(opline->op1, lvar); + SET_NODE(opline->op2, rvar); } /* }}} */ @@ -773,8 +874,8 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZ; - opline->op1 = *expr; - close_bracket_token->u.opline_num = while_cond_op_number; + SET_NODE(opline->op1, expr); + close_bracket_token->u.op.opline_num = while_cond_op_number; SET_UNUSED(opline->op2); do_begin_loop(TSRMLS_C); @@ -788,14 +889,14 @@ /* add unconditional jump */ opline->opcode = ZEND_JMP; - opline->op1.u.opline_num = while_token->u.opline_num; + opline->op1.opline_num = while_token->u.op.opline_num; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); /* update while's conditional jmp */ - CG(active_op_array)->opcodes[close_bracket_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[close_bracket_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); - do_end_loop(while_token->u.opline_num, 0 TSRMLS_CC); + do_end_loop(while_token->u.op.opline_num, 0 TSRMLS_CC); DEC_BPC(CG(active_op_array)); } @@ -807,8 +908,8 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZNZ; - opline->op1 = *expr; /* the conditional expression */ - second_semicolon_token->u.opline_num = for_cond_op_number; + SET_NODE(opline->op1, expr); /* the conditional expression */ + second_semicolon_token->u.op.opline_num = for_cond_op_number; SET_UNUSED(opline->op2); } /* }}} */ @@ -818,8 +919,8 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP; - opline->op1.u.opline_num = cond_start->u.opline_num; - CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].extended_value = get_next_op_number(CG(active_op_array)); + opline->op1.opline_num = cond_start->u.op.opline_num; + CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); @@ -834,12 +935,12 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP; - opline->op1.u.opline_num = second_semicolon_token->u.opline_num+1; - CG(active_op_array)->opcodes[second_semicolon_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + opline->op1.opline_num = second_semicolon_token->u.op.opline_num+1; + CG(active_op_array)->opcodes[second_semicolon_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - do_end_loop(second_semicolon_token->u.opline_num+1, 0 TSRMLS_CC); + do_end_loop(second_semicolon_token->u.op.opline_num+1, 0 TSRMLS_CC); DEC_BPC(CG(active_op_array)); } @@ -855,22 +956,20 @@ if (last_op->opcode == ZEND_FETCH_OBJ_RW) { last_op->opcode = (op==ZEND_PRE_INC)?ZEND_PRE_INC_OBJ:ZEND_PRE_DEC_OBJ; - last_op->result.op_type = IS_VAR; - last_op->result.u.EA.type = 0; - last_op->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = last_op->result; + last_op->result_type = IS_VAR; + last_op->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, last_op->result); return; } } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->op1 = *op1; + SET_NODE(opline->op1, op1); SET_UNUSED(opline->op2); - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } /* }}} */ @@ -879,25 +978,25 @@ int last_op_number = get_next_op_number(CG(active_op_array)); zend_op *opline; - if (last_op_number > 0) { + if (last_op_number > 0) { zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1]; if (last_op->opcode == ZEND_FETCH_OBJ_RW) { last_op->opcode = (op==ZEND_POST_INC)?ZEND_POST_INC_OBJ:ZEND_POST_DEC_OBJ; - last_op->result.op_type = IS_TMP_VAR; - last_op->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = last_op->result; + last_op->result_type = IS_TMP_VAR; + last_op->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, last_op->result); return; } } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->op1 = *op1; + SET_NODE(opline->op1, op1); SET_UNUSED(opline->op2); - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } /* }}} */ @@ -907,8 +1006,8 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZ; - opline->op1 = *cond; - closing_bracket_token->u.opline_num = if_cond_op_number; + SET_NODE(opline->op1, cond); + closing_bracket_token->u.op.opline_num = if_cond_op_number; SET_UNUSED(opline->op2); INC_BPC(CG(active_op_array)); } @@ -931,7 +1030,7 @@ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); zend_llist_add_element(jmp_list_ptr, &if_end_op_number); - CG(active_op_array)->opcodes[closing_bracket_token->u.opline_num].op2.u.opline_num = if_end_op_number+1; + CG(active_op_array)->opcodes[closing_bracket_token->u.op.opline_num].op2.opline_num = if_end_op_number+1; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); } @@ -945,7 +1044,7 @@ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); for (le=jmp_list_ptr->head; le; le = le->next) { - CG(active_op_array)->opcodes[*((int *) le->data)].op1.u.opline_num = next_op_number; + CG(active_op_array)->opcodes[*((int *) le->data)].op1.opline_num = next_op_number; } zend_llist_destroy(jmp_list_ptr); zend_stack_del_top(&CG(bp_stack)); @@ -955,7 +1054,7 @@ void zend_check_writable_variable(const znode *variable) /* {{{ */ { - zend_uint type = variable->u.EA.type; + zend_uint type = variable->EA; if (type & ZEND_PARSED_METHOD_CALL) { zend_error(E_COMPILE_ERROR, "Can't use method return value in write context"); @@ -996,20 +1095,21 @@ if (CG(active_op_array)->last == 0 || CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) { - this_var = opline_ptr->result.u.var; + this_var = opline_ptr->result.var; if (CG(active_op_array)->this_var == -1) { - CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(opline_ptr->op1.u.constant), Z_STRLEN(opline_ptr->op1.u.constant)); + CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(CONSTANT(opline_ptr->op1.constant)), Z_STRLEN(CONSTANT(opline_ptr->op1.constant)) TSRMLS_CC); + Z_TYPE(CONSTANT(opline_ptr->op1.constant)) = IS_NULL; } else { - efree(Z_STRVAL(opline_ptr->op1.u.constant)); + zend_del_literal(CG(active_op_array), opline_ptr->op1.constant); } le = le->next; if (variable->op_type == IS_VAR && - variable->u.var == this_var) { + variable->u.op.var == this_var) { variable->op_type = IS_CV; - variable->u.var = CG(active_op_array)->this_var; + variable->u.op.var = CG(active_op_array)->this_var; } } else if (CG(active_op_array)->this_var == -1) { - CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1); + CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1 TSRMLS_CC); } } @@ -1017,14 +1117,14 @@ opline_ptr = (zend_op *)le->data; opline = get_next_op(CG(active_op_array) TSRMLS_CC); memcpy(opline, opline_ptr, sizeof(zend_op)); - if (opline->op1.op_type == IS_VAR && - opline->op1.u.var == this_var) { - opline->op1.op_type = IS_CV; - opline->op1.u.var = CG(active_op_array)->this_var; + if (opline->op1_type == IS_VAR && + opline->op1.var == this_var) { + opline->op1_type = IS_CV; + opline->op1.var = CG(active_op_array)->this_var; } switch (type) { case BP_VAR_R: - if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) { + if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); } opline->opcode -= 3; @@ -1035,17 +1135,17 @@ opline->opcode += 3; break; case BP_VAR_IS: - if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) { + if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); } opline->opcode += 6; /* 3+3 */ break; case BP_VAR_FUNC_ARG: opline->opcode += 9; /* 3+3+3 */ - opline->extended_value = arg_offset; + opline->extended_value |= arg_offset; break; case BP_VAR_UNSET: - if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) { + if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2_type == IS_UNUSED) { zend_error(E_COMPILE_ERROR, "Cannot use [] for unsetting"); } opline->opcode += 12; /* 3+3+3+3 */ @@ -1054,7 +1154,7 @@ le = le->next; } if (opline && type == BP_VAR_W && arg_offset) { - opline->extended_value = ZEND_FETCH_MAKE_REF; + opline->extended_value |= ZEND_FETCH_MAKE_REF; } } zend_llist_destroy(fetch_list_ptr); @@ -1083,15 +1183,15 @@ } if (op1) { - opline->op1 = *op1; - opline->result = *op1; + SET_NODE(opline->op1, op1); + SET_NODE(opline->result, op1); } else { SET_UNUSED(opline->op1); - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); } - opline->op2 = *op2; - *result = opline->result; + SET_NODE(opline->op2, op2); + GET_NODE(result, opline->result); } /* }}} */ @@ -1102,15 +1202,15 @@ opline->opcode = ZEND_ADD_VAR; if (op1) { - opline->op1 = *op1; - opline->result = *op1; + SET_NODE(opline->op1, op1); + SET_NODE(opline->result, op1); } else { SET_UNUSED(opline->op1); - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); } - opline->op2 = *op2; - *result = opline->result; + SET_NODE(opline->op2, op2); + GET_NODE(result, opline->result); } /* }}} */ @@ -1120,7 +1220,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FREE; - opline->op1 = *op1; + SET_NODE(opline->op1, op1); SET_UNUSED(opline->op2); } else if (op1->op_type==IS_VAR) { zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; @@ -1128,23 +1228,23 @@ while (opline->opcode == ZEND_END_SILENCE || opline->opcode == ZEND_EXT_FCALL_END || opline->opcode == ZEND_OP_DATA) { opline--; } - if (opline->result.op_type == IS_VAR - && opline->result.u.var == op1->u.var) { - opline->result.u.EA.type |= EXT_TYPE_UNUSED; + if (opline->result_type == IS_VAR + && opline->result.var == op1->u.op.var) { + opline->result_type |= EXT_TYPE_UNUSED; } else { while (opline>CG(active_op_array)->opcodes) { if (opline->opcode == ZEND_FETCH_DIM_R - && opline->op1.op_type == IS_VAR - && opline->op1.u.var == op1->u.var) { + && opline->op1_type == IS_VAR + && opline->op1.var == op1->u.op.var) { /* This should the end of a list() construct * Mark its result as unused */ opline->extended_value = ZEND_FETCH_STANDARD; break; - } else if (opline->result.op_type==IS_VAR - && opline->result.u.var == op1->u.var) { + } else if (opline->result_type==IS_VAR + && opline->result.var == op1->u.op.var) { if (opline->opcode == ZEND_NEW) { - opline->result.u.EA.type |= EXT_TYPE_UNUSED; + opline->result_type |= EXT_TYPE_UNUSED; } break; } @@ -1187,7 +1287,7 @@ zend_op_array op_array; char *name = function_name->u.constant.value.str.val; int name_len = function_name->u.constant.value.str.len; - int function_begin_line = function_token->u.opline_num; + int function_begin_line = function_token->u.op.opline_num; zend_uint fn_flags; char *lcname; zend_bool orig_interactive; @@ -1209,7 +1309,6 @@ } function_token->u.op_array = CG(active_op_array); - lcname = zend_str_tolower_dup(name, name_len); orig_interactive = CG(interactive); CG(interactive) = 0; @@ -1227,6 +1326,8 @@ op_array.line_start = zend_get_compiled_lineno(TSRMLS_C); if (is_method) { + lcname = CG(new_interned_string)(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC); + if (zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name); } @@ -1332,9 +1433,12 @@ free_alloca(class_lcname, use_heap); } - efree(lcname); + if (!IS_INTERNED(lcname)) { + efree(lcname); + } } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); + zval key; if (CG(current_namespace)) { /* Prefix function name with current namespcae name */ @@ -1344,21 +1448,22 @@ zval_copy_ctor(&tmp.u.constant); zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC); op_array.function_name = Z_STRVAL(tmp.u.constant); - efree(lcname); name_len = Z_STRLEN(tmp.u.constant); lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len); + } else { + lcname = zend_str_tolower_dup(name, name_len); } opline->opcode = ZEND_DECLARE_FUNCTION; - opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC); - opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_STRING; - opline->op2.u.constant.value.str.val = lcname; - opline->op2.u.constant.value.str.len = name_len; - Z_SET_REFCOUNT(opline->op2.u.constant, 1); + opline->op1_type = IS_CONST; + build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC); + opline->op1.constant = zend_add_literal(CG(active_op_array), &key); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); + opline->op2_type = IS_CONST; + LITERAL_STRINGL(opline->op2, lcname, name_len, 0); + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); opline->extended_value = ZEND_DECLARE_FUNCTION; - zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); + zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); } if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { @@ -1384,8 +1489,8 @@ /* Foreach stack separator */ zend_op dummy_opline; - dummy_opline.result.op_type = IS_UNUSED; - dummy_opline.op1.op_type = IS_UNUSED; + dummy_opline.result_type = IS_UNUSED; + dummy_opline.op1_type = IS_UNUSED; zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op)); } @@ -1416,13 +1521,13 @@ zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC); result->op_type = IS_TMP_VAR; - result->u.var = get_temporary_variable(current_op_array); + result->u.op.var = get_temporary_variable(current_op_array); current_op = ¤t_op_array->opcodes[current_op_number]; current_op->opcode = ZEND_DECLARE_LAMBDA_FUNCTION; - zval_dtor(¤t_op->op2.u.constant); - ZVAL_LONG(¤t_op->op2.u.constant, zend_hash_func(Z_STRVAL(current_op->op1.u.constant), Z_STRLEN(current_op->op1.u.constant))); - current_op->result = *result; + zend_del_literal(current_op_array, current_op->op2.constant); + SET_UNUSED(current_op->op2); + SET_NODE(current_op->result, result); CG(active_op_array)->fn_flags |= ZEND_ACC_CLOSURE; } /* }}} */ @@ -1471,10 +1576,11 @@ } /* }}} */ -void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */ +void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */ { zend_op *opline; zend_arg_info *cur_arg_info; + znode var; if (class_type->op_type == IS_CONST && Z_TYPE(class_type->u.constant) == IS_STRING && @@ -1485,33 +1591,37 @@ return; } - if (var->op_type == IS_CV && - var->u.var == CG(active_op_array)->this_var && - (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) { - zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); - } else if (var->op_type == IS_VAR && - CG(active_op_array)->scope && - ((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) && - (Z_TYPE(varname->u.constant) == IS_STRING) && - (Z_STRLEN(varname->u.constant) == sizeof("this")-1) && - (memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")) == 0)) { - zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + if (zend_is_auto_global(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant) TSRMLS_CC)) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s", Z_STRVAL(varname->u.constant)); + } else { + var.op_type = IS_CV; + var.u.op.var = lookup_cv(CG(active_op_array), varname->u.constant.value.str.val, varname->u.constant.value.str.len TSRMLS_CC); + varname->u.constant.value.str.val = CG(active_op_array)->vars[var.u.op.var].name; + var.EA = 0; + if (Z_STRLEN(varname->u.constant) == sizeof("this")-1 && + !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")-1)) { + if (CG(active_op_array)->scope && + (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + CG(active_op_array)->this_var = var.u.op.var; + } } opline = get_next_op(CG(active_op_array) TSRMLS_CC); CG(active_op_array)->num_args++; opline->opcode = op; - opline->result = *var; - opline->op1 = *offset; + SET_NODE(opline->result, &var); + SET_NODE(opline->op1, offset); if (op == ZEND_RECV_INIT) { - opline->op2 = *initialization; + SET_NODE(opline->op2, initialization); } else { CG(active_op_array)->required_num_args = CG(active_op_array)->num_args; SET_UNUSED(opline->op2); } CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args)); cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1]; - cur_arg_info->name = estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len); + cur_arg_info->name = CG(new_interned_string)(estrndup(varname->u.constant.value.str.val, varname->u.constant.value.str.len), varname->u.constant.value.str.len + 1, 1 TSRMLS_CC); cur_arg_info->name_len = varname->u.constant.value.str.len; cur_arg_info->array_type_hint = 0; cur_arg_info->allow_null = 1; @@ -1525,6 +1635,7 @@ if (ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_type->u.constant), Z_STRLEN(class_type->u.constant))) { zend_resolve_class_name(class_type, &opline->extended_value, 1 TSRMLS_CC); } + class_type->u.constant.value.str.val = CG(new_interned_string)(class_type->u.constant.value.str.val, class_type->u.constant.value.str.len + 1, 1 TSRMLS_CC); cur_arg_info->class_name = class_type->u.constant.value.str.val; cur_arg_info->class_name_len = class_type->u.constant.value.str.len; if (op == ZEND_RECV_INIT) { @@ -1547,7 +1658,6 @@ } } } - opline->result.u.EA.type |= EXT_TYPE_UNUSED; } /* }}} */ @@ -1586,6 +1696,53 @@ } /* }}} */ +static void add_lowercased_name(int literal TSRMLS_DC) /* {{{ */ +{ + /* Hack: the literal folowing to the name is the same lowercased name */ + char *lc_name; + zval c; + int lc_literal; + +if (literal + 1 != CG(active_op_array)->last_literal) { +zend_error(E_ERROR, "Internal error 1 ???"); +} + lc_name = zend_str_tolower_dup(Z_STRVAL(CONSTANT(literal)), Z_STRLEN(CONSTANT(literal))); + ZVAL_STRINGL(&c, lc_name, Z_STRLEN(CONSTANT(literal)), 0); + lc_literal = zend_add_literal(CG(active_op_array), &c); + Z_HASH_P(&CONSTANT(lc_literal)) = zend_hash_func(Z_STRVAL(c), Z_STRLEN(c)+1); +if (literal + 1 != lc_literal) { +zend_error(E_ERROR, "Internal error 2 ???"); +} +} +/* }}} */ + +static void add_lowercased_class_name(int literal TSRMLS_DC) /* {{{ */ +{ + /* Hack: the literal folowing to the name is the same lowercased name */ + char *lc_name; + int lc_len; + zval c; + int lc_literal; + +if (literal + 1 != CG(active_op_array)->last_literal) { +zend_error(E_ERROR, "Internal error 3 ???"); +} + if (Z_STRVAL(CONSTANT(literal))[0] == '\\') { + lc_len = Z_STRLEN(CONSTANT(literal)) - 1; + lc_name = zend_str_tolower_dup(Z_STRVAL(CONSTANT(literal)) + 1, lc_len); + } else { + lc_len = Z_STRLEN(CONSTANT(literal)); + lc_name = zend_str_tolower_dup(Z_STRVAL(CONSTANT(literal)), lc_len); + } + ZVAL_STRINGL(&c, lc_name, lc_len, 0); + lc_literal = zend_add_literal(CG(active_op_array), &c); + Z_HASH_P(&CONSTANT(lc_literal)) = zend_hash_func(Z_STRVAL(c), Z_STRLEN(c)+1); +if (literal + 1 != lc_literal) { +zend_error(E_ERROR, "Internal error 4 ???"); +} +} +/* }}} */ + void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */ { zend_op *last_op; @@ -1598,27 +1755,27 @@ last_op_number = get_next_op_number(CG(active_op_array))-1; last_op = &CG(active_op_array)->opcodes[last_op_number]; - if ((last_op->op2.op_type == IS_CONST) && (last_op->op2.u.constant.type == IS_STRING) && (last_op->op2.u.constant.value.str.len == sizeof(ZEND_CLONE_FUNC_NAME)-1) - && !zend_binary_strcasecmp(last_op->op2.u.constant.value.str.val, last_op->op2.u.constant.value.str.len, ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) { + if ((last_op->op2_type == IS_CONST) && (Z_TYPE(CONSTANT(last_op->op2.constant)) == IS_STRING) && (Z_STRLEN(CONSTANT(last_op->op2.constant)) == sizeof(ZEND_CLONE_FUNC_NAME)-1) + && !zend_binary_strcasecmp(Z_STRVAL(CONSTANT(last_op->op2.constant)), Z_STRLEN(CONSTANT(last_op->op2.constant)), ZEND_CLONE_FUNC_NAME, sizeof(ZEND_CLONE_FUNC_NAME)-1)) { zend_error(E_COMPILE_ERROR, "Cannot call __clone() method on objects - use 'clone $obj' instead"); } if (last_op->opcode == ZEND_FETCH_OBJ_R) { + if (last_op->op2_type == IS_CONST) { + add_lowercased_name(last_op->op2.constant TSRMLS_CC); + } last_op->opcode = ZEND_INIT_METHOD_CALL; SET_UNUSED(last_op->result); Z_LVAL(left_bracket->u.constant) = ZEND_INIT_FCALL_BY_NAME; } else { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->op2 = *left_bracket; - if (opline->op2.op_type == IS_CONST) { - opline->op1.op_type = IS_CONST; - Z_TYPE(opline->op1.u.constant) = IS_STRING; - Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)); - Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(opline->op2.u.constant); - opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); + SET_NODE(opline->op2, left_bracket); + if (opline->op2_type == IS_CONST) { + opline->op1_type = IS_CONST; + LITERAL_STRINGL(opline->op1, zend_str_tolower_dup(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))), Z_STRLEN(CONSTANT(opline->op2.constant)), 0); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); } else { - opline->extended_value = 0; SET_UNUSED(opline->op1); } } @@ -1633,11 +1790,11 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CLONE; - opline->op1 = *expr; + SET_NODE(opline->op1, expr); SET_UNUSED(opline->op2); - opline->result.op_type = IS_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); } /* }}} */ @@ -1653,39 +1810,32 @@ /* In run-time PHP will check for function with full name and internal function with short name */ opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME; - opline->op2 = *function_name; - opline->extended_value = 0; - opline->op1.op_type = IS_CONST; - Z_TYPE(opline->op1.u.constant) = IS_STRING; - Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)); - Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(opline->op2.u.constant); - opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); - slash = zend_memrchr(Z_STRVAL(opline->op1.u.constant), '\\', Z_STRLEN(opline->op1.u.constant)); - prefix_len = slash-Z_STRVAL(opline->op1.u.constant)+1; - name_len = Z_STRLEN(opline->op1.u.constant)-prefix_len; + SET_NODE(opline->op2, function_name); + opline->op1_type = IS_CONST; + LITERAL_STRINGL(opline->op1, zend_str_tolower_dup(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))), Z_STRLEN(CONSTANT(opline->op2.constant)), 0); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); + slash = zend_memrchr(Z_STRVAL(CONSTANT(opline->op1.constant)), '\\', Z_STRLEN(CONSTANT(opline->op1.constant))); + prefix_len = slash-Z_STRVAL(CONSTANT(opline->op1.constant))+1; + name_len = Z_STRLEN(CONSTANT(opline->op1.constant))-prefix_len; opline2 = get_next_op(CG(active_op_array) TSRMLS_CC); opline2->opcode = ZEND_OP_DATA; - opline2->op1.op_type = IS_CONST; - Z_TYPE(opline2->op1.u.constant) = IS_LONG; + SET_UNUSED(opline2->op1); if(!slash) { - zend_error(E_CORE_ERROR, "Namespaced name %s should contain slash", Z_STRVAL(opline->op1.u.constant)); + zend_error(E_CORE_ERROR, "Namespaced name %s should contain slash", Z_STRVAL(CONSTANT(opline->op1.constant))); } /* this is the length of namespace prefix */ - Z_LVAL(opline2->op1.u.constant) = prefix_len; + opline2->op1.num = prefix_len; /* this is the hash of the non-prefixed part, lowercased */ opline2->extended_value = zend_hash_func(slash+1, name_len+1); SET_UNUSED(opline2->op2); } else { opline->opcode = ZEND_INIT_FCALL_BY_NAME; - opline->op2 = *function_name; - if (opline->op2.op_type == IS_CONST) { - opline->op1.op_type = IS_CONST; - Z_TYPE(opline->op1.u.constant) = IS_STRING; - Z_STRVAL(opline->op1.u.constant) = zend_str_tolower_dup(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)); - Z_STRLEN(opline->op1.u.constant) = Z_STRLEN(opline->op2.u.constant); - opline->extended_value = zend_hash_func(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant) + 1); + SET_NODE(opline->op2, function_name); + if (opline->op2_type == IS_CONST) { + opline->op1_type = IS_CONST; + LITERAL_STRINGL(opline->op1, zend_str_tolower_dup(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))), Z_STRLEN(CONSTANT(opline->op2.constant)), 0); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); } else { - opline->extended_value = 0; SET_UNUSED(opline->op1); } } @@ -1855,16 +2005,17 @@ break; default: zend_resolve_class_name(class_name, &opline->extended_value, 0 TSRMLS_CC); - opline->op2 = *class_name; + SET_NODE(opline->op2, class_name); + add_lowercased_class_name(opline->op2.constant TSRMLS_CC); break; } } else { - opline->op2 = *class_name; + SET_NODE(opline->op2, class_name); } - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.u.EA.type = opline->extended_value; - opline->result.op_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ - *result = opline->result; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */ + GET_NODE(result, opline->result); + result->EA = opline->extended_value; } /* }}} */ @@ -1894,15 +2045,21 @@ { zend_label *dest; long current, distance; + zval *label; + if (pass2) { + label = opline->op2.zv; + } else { + label = &CONSTANT_EX(op_array, opline->op2.constant); + } if (CG(labels) == NULL || - zend_hash_find(CG(labels), Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void**)&dest) == FAILURE) { + zend_hash_find(CG(labels), Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) { if (pass2) { CG(in_compilation) = 1; CG(active_op_array) = op_array; CG(zend_lineno) = opline->lineno; - zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL(opline->op2.u.constant)); + zend_error(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label)); } else { /* Label is not defined. Delay to pass 2. */ INC_BPC(op_array); @@ -1910,8 +2067,9 @@ } } - opline->op1.u.opline_num = dest->opline_num; - zval_dtor(&opline->op2.u.constant); + opline->op1.opline_num = dest->opline_num; + zval_dtor(label); + Z_TYPE_P(label) = IS_NULL; /* Check that we are not moving into loop or switch */ current = opline->extended_value; @@ -1934,7 +2092,7 @@ SET_UNUSED(opline->op2); } else { /* Set real break distance */ - ZVAL_LONG(&opline->op2.u.constant, distance); + ZVAL_LONG(label, distance); } if (pass2) { @@ -1950,7 +2108,7 @@ opline->opcode = ZEND_GOTO; opline->extended_value = CG(active_op_array)->current_brk_cont; SET_UNUSED(opline->op1); - opline->op2 = *label; + SET_NODE(opline->op2, label); zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC); } /* }}} */ @@ -2013,7 +2171,7 @@ if ((sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == Z_STRLEN(method_name->u.constant) && memcmp(lcname, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1) == 0) { zval_dtor(&method_name->u.constant); - SET_UNUSED(*method_name); + method_name->op_type = IS_UNUSED; } efree(lcname); } @@ -2023,13 +2181,21 @@ fetch_type = ZEND_FETCH_CLASS_GLOBAL; zend_resolve_class_name(class_name, &fetch_type, 1 TSRMLS_CC); class_node = *class_name; + opline = get_next_op(CG(active_op_array) TSRMLS_CC); } else { zend_do_fetch_class(&class_node, class_name TSRMLS_CC); + opline = get_next_op(CG(active_op_array) TSRMLS_CC); + opline->extended_value = class_node.EA ; } - opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; - opline->op1 = class_node; - opline->op2 = *method_name; + SET_NODE(opline->op1, &class_node); + if (opline->op1_type == IS_CONST) { + add_lowercased_class_name(opline->op1.constant TSRMLS_CC); + } + SET_NODE(opline->op2, method_name); + if (opline->op2_type == IS_CONST) { + add_lowercased_name(opline->op2.constant TSRMLS_CC); + } zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); zend_do_extended_fcall_begin(TSRMLS_C); @@ -2051,17 +2217,17 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) { opline->opcode = ZEND_DO_FCALL; - opline->op1 = *function_name; - ZVAL_LONG(&opline->op2.u.constant, zend_hash_func(Z_STRVAL(function_name->u.constant), Z_STRLEN(function_name->u.constant) + 1)); + SET_NODE(opline->op1, function_name); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); } else { opline->opcode = ZEND_DO_FCALL_BY_NAME; SET_UNUSED(opline->op1); } } - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_VAR; - *result = opline->result; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_VAR; + GET_NODE(result, opline->result) ; SET_UNUSED(opline->op2); zend_stack_del_top(&CG(function_call_stack)); @@ -2170,8 +2336,8 @@ } } opline->opcode = op; - opline->op1 = *param; - opline->op2.u.opline_num = offset; + SET_NODE(opline->op1, param); + opline->op2.opline_num = offset; SET_UNUSED(opline->op2); } /* }}} */ @@ -2187,7 +2353,7 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = (switch_entry->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; - opline->op1 = switch_entry->cond; + SET_NODE(opline->op1, &switch_entry->cond); SET_UNUSED(opline->op2); opline->extended_value = 0; return 0; @@ -2199,22 +2365,22 @@ zend_op *opline; /* If we reach the seperator then stop applying the stack */ - if (foreach_copy->result.op_type == IS_UNUSED && foreach_copy->op1.op_type == IS_UNUSED) { + if (foreach_copy->result_type == IS_UNUSED && foreach_copy->op1_type == IS_UNUSED) { return 1; } opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = (foreach_copy->result.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; - opline->op1 = foreach_copy->result; + opline->opcode = (foreach_copy->result_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; + COPY_NODE(opline->op1, foreach_copy->result); SET_UNUSED(opline->op2); opline->extended_value = 1; - if (foreach_copy->op1.op_type != IS_UNUSED) { + if (foreach_copy->op1_type != IS_UNUSED) { opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = (foreach_copy->op1.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; - opline->op1 = foreach_copy->op1; + opline->opcode = (foreach_copy->op1_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; + COPY_NODE(opline->op1, foreach_copy->op1); SET_UNUSED(opline->op2); opline->extended_value = 0; } @@ -2248,7 +2414,7 @@ end_op_number = get_next_op_number(CG(active_op_array)); while (start_op_number < end_op_number) { - CG(active_op_array)->opcodes[start_op_number].op1.u.EA.type = EXT_TYPE_FREE_ON_RETURN; + CG(active_op_array)->opcodes[start_op_number].extended_value |= EXT_TYPE_FREE_ON_RETURN; start_op_number++; } @@ -2257,14 +2423,14 @@ opline->opcode = ZEND_RETURN; if (expr) { - opline->op1 = *expr; + SET_NODE(opline->op1, expr); if (do_end_vparse && zend_is_function_or_method_call(expr)) { opline->extended_value = ZEND_RETURNS_FUNCTION; } } else { - opline->op1.op_type = IS_CONST; - INIT_ZVAL(opline->op1.u.constant); + opline->op1_type = IS_CONST; + LITERAL_NULL(opline->op1); } SET_UNUSED(opline->op2); @@ -2289,7 +2455,7 @@ void zend_do_first_catch(znode *open_parentheses TSRMLS_DC) /* {{{ */ { - open_parentheses->u.opline_num = get_next_op_number(CG(active_op_array)); + open_parentheses->u.op.opline_num = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -2310,7 +2476,7 @@ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); zend_llist_add_element(jmp_list_ptr, &jmp_op_number); - zend_add_catch_element(try_token->u.opline_num, get_next_op_number(CG(active_op_array)) TSRMLS_CC); + zend_add_catch_element(try_token->u.op.opline_num, get_next_op_number(CG(active_op_array)) TSRMLS_CC); } /* }}} */ @@ -2318,12 +2484,12 @@ { CG(active_op_array)->last--; zend_do_if_end(TSRMLS_C); - if (last_additional_catch->u.opline_num == -1) { - CG(active_op_array)->opcodes[first_catch->u.opline_num].op1.u.EA.type = 1; - CG(active_op_array)->opcodes[first_catch->u.opline_num].extended_value = get_next_op_number(CG(active_op_array)); + if (last_additional_catch->u.op.opline_num == -1) { + CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1; + CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); } else { - CG(active_op_array)->opcodes[last_additional_catch->u.opline_num].op1.u.EA.type = 1; - CG(active_op_array)->opcodes[last_additional_catch->u.opline_num].extended_value = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].result.num = 1; + CG(active_op_array)->opcodes[last_additional_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); } DEC_BPC(CG(active_op_array)); } @@ -2331,41 +2497,42 @@ void zend_do_try(znode *try_token TSRMLS_DC) /* {{{ */ { - try_token->u.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC); + try_token->u.op.opline_num = zend_add_try_element(get_next_op_number(CG(active_op_array)) TSRMLS_CC); INC_BPC(CG(active_op_array)); } /* }}} */ -void zend_do_begin_catch(znode *try_token, znode *class_name, const znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */ +void zend_do_begin_catch(znode *try_token, znode *class_name, znode *catch_var, znode *first_catch TSRMLS_DC) /* {{{ */ { long catch_op_number; zend_op *opline; znode catch_class; - zend_do_fetch_class(&catch_class, class_name TSRMLS_CC); + if (class_name->op_type == IS_CONST && + ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) { + ulong fetch_type = ZEND_FETCH_CLASS_GLOBAL; - catch_op_number = get_next_op_number(CG(active_op_array)); - if (catch_op_number > 0) { - opline = &CG(active_op_array)->opcodes[catch_op_number-1]; - if (opline->opcode == ZEND_FETCH_CLASS) { - opline->extended_value |= ZEND_FETCH_CLASS_NO_AUTOLOAD; - } + zend_resolve_class_name(class_name, &fetch_type, 1 TSRMLS_CC); + catch_class = *class_name; + } else { + zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement"); } + catch_op_number = get_next_op_number(CG(active_op_array)); if (first_catch) { - first_catch->u.opline_num = catch_op_number; + first_catch->u.op.opline_num = catch_op_number; } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CATCH; - opline->op1 = catch_class; -/* SET_UNUSED(opline->op1); */ /* FIXME: Define IS_CLASS or something like that */ - opline->op2.op_type = IS_CV; - opline->op2.u.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len); - opline->op2.u.EA.type = 0; - opline->op1.u.EA.type = 0; /* 1 means it's the last catch in the block */ + SET_NODE(opline->op1, &catch_class); + add_lowercased_class_name(opline->op1.constant TSRMLS_CC); + opline->op2_type = IS_CV; + opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len TSRMLS_CC); + catch_var->u.constant.value.str.val = CG(active_op_array)->vars[opline->op2.var].name; + opline->result.num = 0; /* 1 means it's the last catch in the block */ - try_token->u.opline_num = catch_op_number; + try_token->u.op.opline_num = catch_op_number; } /* }}} */ @@ -2383,7 +2550,7 @@ zend_stack_top(&CG(bp_stack), (void **) &jmp_list_ptr); zend_llist_add_element(jmp_list_ptr, &jmp_op_number); - CG(active_op_array)->opcodes[try_token->u.opline_num].extended_value = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[try_token->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -2393,7 +2560,7 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_THROW; - opline->op1 = *expr; + SET_NODE(opline->op1, expr); SET_UNUSED(opline->op2); } /* }}} */ @@ -2926,16 +3093,25 @@ } /* }}} */ -ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */ +ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */ { zend_function *function; + zval *op1, *op2; - zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function); - if (zend_hash_add(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, function, sizeof(zend_function), NULL)==FAILURE) { + if (compile_time) { + op1 = &CONSTANT_EX(op_array, opline->op1.constant); + op2 = &CONSTANT_EX(op_array, opline->op2.constant); + } else { + op1 = opline->op1.zv; + op2 = opline->op2.zv; + } + + zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function); + if (zend_hash_quick_add(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), function, sizeof(zend_function), NULL)==FAILURE) { int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR; zend_function *old_function; - if (zend_hash_find(function_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, (void *) &old_function)==SUCCESS + if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), (void *) &old_function)==SUCCESS && old_function->type == ZEND_USER_FUNCTION && old_function->op_array.last > 0) { zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)", @@ -2954,18 +3130,26 @@ } /* }}} */ -ZEND_API zend_class_entry *do_bind_class(const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */ +ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */ { zend_class_entry *ce, **pce; + zval *op1, *op2; - if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { - zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); + if (compile_time) { + op1 = &CONSTANT_EX(op_array, opline->op1.constant); + op2 = &CONSTANT_EX(op_array, opline->op2.constant); + } else { + op1 = opline->op1.zv; + op2 = opline->op2.zv; + } + if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) { + zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1)); return NULL; } else { ce = *pce; } ce->refcount++; - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { + if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { ce->refcount--; if (!compile_time) { /* If we're in compile time, in practice, it's quite possible @@ -2985,13 +3169,22 @@ } /* }}} */ -ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */ +ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */ { zend_class_entry *ce, **pce; int found_ce; + zval *op1, *op2; - found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce); + if (compile_time) { + op1 = &CONSTANT_EX(op_array, opline->op1.constant); + op2 = &CONSTANT_EX(op_array, opline->op2.constant); + } else { + op1 = opline->op1.zv; + op2 = opline->op2.zv; + } + found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce); + if (found_ce == FAILURE) { if (!compile_time) { /* If we're in compile time, in practice, it's quite possible @@ -2999,7 +3192,7 @@ * so we shut up about it. This allows the if (!defined('FOO')) { return; } * approach to work. */ - zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2)); } return NULL; } else { @@ -3015,7 +3208,7 @@ ce->refcount++; /* Register the derived class */ - if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) { + if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), pce, sizeof(zend_class_entry *), NULL)==FAILURE) { zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name); } return ce; @@ -3033,13 +3226,13 @@ switch (opline->opcode) { case ZEND_DECLARE_FUNCTION: - if (do_bind_function(opline, CG(function_table), 1) == FAILURE) { + if (do_bind_function(CG(active_op_array), opline, CG(function_table), 1) == FAILURE) { return; } table = CG(function_table); break; case ZEND_DECLARE_CLASS: - if (do_bind_class(opline, CG(class_table), 1 TSRMLS_CC) == NULL) { + if (do_bind_class(CG(active_op_array), opline, CG(class_table), 1 TSRMLS_CC) == NULL) { return; } table = CG(class_table); @@ -3047,9 +3240,10 @@ case ZEND_DECLARE_INHERITED_CLASS: { zend_op *fetch_class_opline = opline-1; - zval *parent_name = &fetch_class_opline->op2.u.constant; + zval *parent_name; zend_class_entry **pce; + parent_name = &CONSTANT(fetch_class_opline->op2.constant); if ((zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) || ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES) && ((*pce)->type == ZEND_INTERNAL_CLASS))) { @@ -3057,20 +3251,20 @@ zend_uint *opline_num = &CG(active_op_array)->early_binding; while (*opline_num != -1) { - opline_num = &CG(active_op_array)->opcodes[*opline_num].result.u.opline_num; + opline_num = &CG(active_op_array)->opcodes[*opline_num].result.opline_num; } *opline_num = opline - CG(active_op_array)->opcodes; opline->opcode = ZEND_DECLARE_INHERITED_CLASS_DELAYED; - opline->result.op_type = IS_UNUSED; - opline->result.u.opline_num = -1; + opline->result_type = IS_UNUSED; + opline->result.opline_num = -1; } return; } - if (do_bind_inherited_class(opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) { + if (do_bind_inherited_class(CG(active_op_array), opline, CG(class_table), *pce, 1 TSRMLS_CC) == NULL) { return; } /* clear unnecessary ZEND_FETCH_CLASS opcode */ - zval_dtor(&fetch_class_opline->op2.u.constant); + zend_del_literal(CG(active_op_array), fetch_class_opline->op2.constant); MAKE_NOP(fetch_class_opline); table = CG(class_table); @@ -3085,9 +3279,9 @@ return; } - zend_hash_del(table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); - zval_dtor(&opline->op1.u.constant); - zval_dtor(&opline->op2.u.constant); + zend_hash_quick_del(table, Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)), Z_HASH_P(&CONSTANT(opline->op1.constant))); + zend_del_literal(CG(active_op_array), opline->op1.constant); + zend_del_literal(CG(active_op_array), opline->op2.constant); MAKE_NOP(opline); } /* }}} */ @@ -3101,10 +3295,10 @@ CG(in_compilation) = 1; while (opline_num != -1) { - if (zend_lookup_class(Z_STRVAL(op_array->opcodes[opline_num-1].op2.u.constant), Z_STRLEN(op_array->opcodes[opline_num-1].op2.u.constant), &pce TSRMLS_CC) == SUCCESS) { - do_bind_inherited_class(&op_array->opcodes[opline_num], EG(class_table), *pce, 1 TSRMLS_CC); + if (zend_lookup_class(Z_STRVAL_P(op_array->opcodes[opline_num-1].op2.zv), Z_STRLEN_P(op_array->opcodes[opline_num-1].op2.zv), &pce TSRMLS_CC) == SUCCESS) { + do_bind_inherited_class(op_array, &op_array->opcodes[opline_num], EG(class_table), *pce, 0 TSRMLS_CC); } - opline_num = op_array->opcodes[opline_num].result.u.opline_num; + opline_num = op_array->opcodes[opline_num].result.opline_num; } CG(in_compilation) = orig_in_compilation; } @@ -3118,17 +3312,17 @@ opline->opcode = ZEND_JMPNZ_EX; if (expr1->op_type == IS_TMP_VAR) { - opline->result = *expr1; + SET_NODE(opline->result, expr1); } else { - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; } - opline->op1 = *expr1; + SET_NODE(opline->op1, expr1); SET_UNUSED(opline->op2); - op_token->u.opline_num = next_op_number; + op_token->u.op.opline_num = next_op_number; - *expr1 = opline->result; + GET_NODE(expr1, opline->result); } /* }}} */ @@ -3138,11 +3332,11 @@ *result = *expr1; /* we saved the original result in expr1 */ opline->opcode = ZEND_BOOL; - opline->result = *result; - opline->op1 = *expr2; + SET_NODE(opline->result, result); + SET_NODE(opline->op1, expr2); SET_UNUSED(opline->op2); - CG(active_op_array)->opcodes[op_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -3153,17 +3347,17 @@ opline->opcode = ZEND_JMPZ_EX; if (expr1->op_type == IS_TMP_VAR) { - opline->result = *expr1; + SET_NODE(opline->result, expr1); } else { - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; } - opline->op1 = *expr1; + SET_NODE(opline->op1, expr1); SET_UNUSED(opline->op2); - op_token->u.opline_num = next_op_number; + op_token->u.op.opline_num = next_op_number; - *expr1 = opline->result; + GET_NODE(expr1, opline->result); } /* }}} */ @@ -3173,11 +3367,11 @@ *result = *expr1; /* we saved the original result in expr1 */ opline->opcode = ZEND_BOOL; - opline->result = *result; - opline->op1 = *expr2; + SET_NODE(opline->result, result); + SET_NODE(opline->op1, expr2); SET_UNUSED(opline->op2); - CG(active_op_array)->opcodes[op_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[op_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); } /* }}} */ @@ -3193,11 +3387,11 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPNZ; - opline->op1 = *expr; - opline->op2.u.opline_num = do_token->u.opline_num; + SET_NODE(opline->op1, expr); + opline->op2.opline_num = do_token->u.op.opline_num; SET_UNUSED(opline->op2); - do_end_loop(expr_open_bracket->u.opline_num, 0 TSRMLS_CC); + do_end_loop(expr_open_bracket->u.op.opline_num, 0 TSRMLS_CC); DEC_BPC(CG(active_op_array)); } @@ -3208,15 +3402,13 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->op1.u.opline_num = CG(active_op_array)->current_brk_cont; + opline->op1.opline_num = CG(active_op_array)->current_brk_cont; SET_UNUSED(opline->op1); if (expr) { - opline->op2 = *expr; + SET_NODE(opline->op2, expr); } else { - Z_TYPE(opline->op2.u.constant) = IS_LONG; - Z_LVAL(opline->op2.u.constant) = 1; - INIT_PZVAL(&opline->op2.u.constant); - opline->op2.op_type = IS_CONST; + LITERAL_LONG(opline->op2, 1); + opline->op2_type = IS_CONST; } } /* }}} */ @@ -3249,13 +3441,13 @@ opline->opcode = ZEND_JMP; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - opline->op1.u.opline_num = switch_entry_ptr->default_case; + opline->op1.opline_num = switch_entry_ptr->default_case; } if (case_list->op_type != IS_UNUSED) { /* non-empty switch */ int next_op_number = get_next_op_number(CG(active_op_array)); - - CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number; + + CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number; } /* remember break/continue loop information */ @@ -3266,7 +3458,7 @@ /* emit free for the switch condition*/ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = (switch_entry_ptr->cond.op_type == IS_TMP_VAR) ? ZEND_FREE : ZEND_SWITCH_FREE; - opline->op1 = switch_entry_ptr->cond; + SET_NODE(opline->op1, &switch_entry_ptr->cond); SET_UNUSED(opline->op2); } if (switch_entry_ptr->cond.op_type == IS_CONST) { @@ -3292,27 +3484,27 @@ switch_entry_ptr->control_var = get_temporary_variable(CG(active_op_array)); } opline->opcode = ZEND_CASE; - opline->result.u.var = switch_entry_ptr->control_var; - opline->result.op_type = IS_TMP_VAR; - opline->op1 = switch_entry_ptr->cond; - opline->op2 = *case_expr; - if (opline->op1.op_type == IS_CONST) { - zval_copy_ctor(&opline->op1.u.constant); + opline->result.var = switch_entry_ptr->control_var; + opline->result_type = IS_TMP_VAR; + SET_NODE(opline->op1, &switch_entry_ptr->cond); + SET_NODE(opline->op2, case_expr); + if (opline->op1_type == IS_CONST) { + zval_copy_ctor(&CONSTANT(opline->op1.constant)); } - result = opline->result; + GET_NODE(&result, opline->result); next_op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZ; - opline->op1 = result; + SET_NODE(opline->op1, &result); SET_UNUSED(opline->op2); - case_token->u.opline_num = next_op_number; + case_token->u.op.opline_num = next_op_number; if (case_list->op_type==IS_UNUSED) { return; } next_op_number = get_next_op_number(CG(active_op_array)); - CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number; + CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number; } /* }}} */ @@ -3324,14 +3516,14 @@ opline->opcode = ZEND_JMP; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - result->u.opline_num = next_op_number; + result->u.op.opline_num = next_op_number; - switch (CG(active_op_array)->opcodes[case_token->u.opline_num].opcode) { + switch (CG(active_op_array)->opcodes[case_token->u.op.opline_num].opcode) { case ZEND_JMP: - CG(active_op_array)->opcodes[case_token->u.opline_num].op1.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[case_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array)); break; case ZEND_JMPZ: - CG(active_op_array)->opcodes[case_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[case_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); break; } } @@ -3348,7 +3540,7 @@ opline->opcode = ZEND_JMP; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - default_token->u.opline_num = next_op_number; + default_token->u.op.opline_num = next_op_number; next_op_number = get_next_op_number(CG(active_op_array)); switch_entry_ptr->default_case = next_op_number; @@ -3356,7 +3548,7 @@ if (case_list->op_type==IS_UNUSED) { return; } - CG(active_op_array)->opcodes[case_list->u.opline_num].op1.u.opline_num = next_op_number; + CG(active_op_array)->opcodes[case_list->u.op.opline_num].op1.opline_num = next_op_number; } /* }}} */ @@ -3367,7 +3559,7 @@ zend_class_entry *new_class_entry; char *lcname; int error = 0; - zval **ns_name; + zval **ns_name, key; if (CG(active_class_entry)) { zend_error(E_COMPILE_ERROR, "Class declarations may not be nested"); @@ -3416,11 +3608,11 @@ zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); new_class_entry->filename = zend_get_compiled_filename(TSRMLS_C); - new_class_entry->line_start = class_token->u.opline_num; - new_class_entry->ce_flags |= class_token->u.EA.type; + new_class_entry->line_start = class_token->u.op.opline_num; + new_class_entry->ce_flags |= class_token->EA; if (parent_class_name && parent_class_name->op_type != IS_UNUSED) { - switch (parent_class_name->u.EA.type) { + switch (parent_class_name->EA) { case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved"); break; @@ -3437,29 +3629,29 @@ } opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->op1.op_type = IS_CONST; - build_runtime_defined_function_key(&opline->op1.u.constant, lcname, new_class_entry->name_length TSRMLS_CC); + opline->op1_type = IS_CONST; + build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC); + opline->op1.constant = zend_add_literal(CG(active_op_array), &key); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); - opline->op2.op_type = IS_CONST; - opline->op2.u.constant.type = IS_STRING; - Z_SET_REFCOUNT(opline->op2.u.constant, 1); + opline->op2_type = IS_CONST; if (doing_inheritance) { - opline->extended_value = parent_class_name->u.var; + opline->extended_value = parent_class_name->u.op.var; opline->opcode = ZEND_DECLARE_INHERITED_CLASS; } else { opline->opcode = ZEND_DECLARE_CLASS; } - opline->op2.u.constant.value.str.val = lcname; - opline->op2.u.constant.value.str.len = new_class_entry->name_length; + LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0); + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); - zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL); + zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL); CG(active_class_entry) = new_class_entry; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_VAR; - CG(implementing_class) = opline->result; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_VAR; + GET_NODE(&CG(implementing_class), opline->result); if (CG(doc_comment)) { CG(active_class_entry)->doc_comment = CG(doc_comment); @@ -3475,7 +3667,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_VERIFY_ABSTRACT_CLASS; - opline->op1 = CG(implementing_class); + SET_NODE(opline->op1, &CG(implementing_class)); SET_UNUSED(opline->op2); } /* }}} */ @@ -3541,10 +3733,11 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ADD_INTERFACE; - opline->op1 = CG(implementing_class); + SET_NODE(opline->op1, &CG(implementing_class)); zend_resolve_class_name(interface_name, &opline->extended_value, 0 TSRMLS_CC); opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE; - opline->op2 = *interface_name; + SET_NODE(opline->op2, interface_name); + add_lowercased_class_name(opline->op2.constant TSRMLS_CC); CG(active_class_entry)->num_interfaces++; } /* }}} */ @@ -3642,7 +3835,7 @@ CG(doc_comment_len) = 0; } - zend_declare_property_ex(CG(active_class_entry), var_name->u.constant.value.str.val, var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); + zend_declare_property_ex(CG(active_class_entry), CG(new_interned_string)(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + 1, 0 TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); efree(var_name->u.constant.value.str.val); } /* }}} */ @@ -3658,7 +3851,7 @@ ALLOC_ZVAL(property); *property = value->u.constant; - if (zend_hash_add(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL)==FAILURE) { + if (zend_hash_add(&CG(active_class_entry)->constants_table, CG(new_interned_string)(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, 0 TSRMLS_CC), var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL)==FAILURE) { FREE_ZVAL(property); zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); } @@ -3680,17 +3873,17 @@ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); if (object->op_type == IS_CV) { - if (object->u.var == CG(active_op_array)->this_var) { - SET_UNUSED(*object); /* this means $this for objects */ + if (object->u.op.var == CG(active_op_array)->this_var) { + object->op_type = IS_UNUSED; /* this means $this for objects */ } } else if (fetch_list_ptr->count == 1) { zend_llist_element *le = fetch_list_ptr->head; zend_op *opline_ptr = (zend_op *) le->data; if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) { - efree(Z_STRVAL(opline_ptr->op1.u.constant)); + zend_del_literal(CG(active_op_array), opline_ptr->op1.constant); SET_UNUSED(opline_ptr->op1); /* this means $this for objects */ - opline_ptr->op2 = *property; + SET_NODE(opline_ptr->op2, property); /* if it was usual fetch, we change it to object fetch */ switch (opline_ptr->opcode) { case ZEND_FETCH_W: @@ -3712,19 +3905,24 @@ opline_ptr->opcode = ZEND_FETCH_OBJ_FUNC_ARG; break; } - *result = opline_ptr->result; + if (opline_ptr->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline_ptr->op2.constant)) == IS_STRING) { + Z_HASH_P(&CONSTANT(opline_ptr->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline_ptr->op2.constant)), Z_STRLEN(CONSTANT(opline_ptr->op2.constant))+1); + } + GET_NODE(result, opline_ptr->result); return; } } init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_OBJ_W; /* the backpatching routine assumes W */ - opline.result.op_type = IS_VAR; - opline.result.u.EA.type = 0; - opline.result.u.var = get_temporary_variable(CG(active_op_array)); - opline.op1 = *object; - opline.op2 = *property; - *result = opline.result; + opline.result_type = IS_VAR; + opline.result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline.op1, object); + SET_NODE(opline.op2, property); + if (opline.op2_type == IS_CONST && Z_TYPE(CONSTANT(opline.op2.constant)) == IS_STRING) { + Z_HASH_P(&CONSTANT(opline.op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1); + } + GET_NODE(result, opline.result); zend_llist_add_element(fetch_list_ptr, &opline); } @@ -3743,40 +3941,6 @@ } /* }}} */ -void zend_do_declare_implicit_property(TSRMLS_D) /* {{{ */ -{ -/* Fixes bug #26182. Not sure why we needed to do this in the first place. - Has to be checked with Zeev. -*/ -#if ANDI_0 - zend_op *opline_ptr; - zend_llist_element *le; - zend_llist *fetch_list_ptr; - - - zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); - - if (fetch_list_ptr->count != 1) { - return; - } - - le = fetch_list_ptr->head; - opline_ptr = (zend_op *) le->data; - - if (opline_ptr->op1.op_type == IS_UNUSED - && CG(active_class_entry) - && opline_ptr->op2.op_type == IS_CONST - && !zend_hash_exists(&CG(active_class_entry)->properties_info, opline_ptr->op2.u.constant.value.str.val, opline_ptr->op2.u.constant.value.str.len+1)) { - znode property; - - property = opline_ptr->op2; - property.u.constant.value.str.val = estrndup(opline_ptr->op2.u.constant.value.str.val, opline_ptr->op2.u.constant.value.str.len); - zend_do_declare_property(&property, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_IMPLICIT_PUBLIC TSRMLS_CC); - } -#endif -} -/* }}} */ - void zend_do_push_object(const znode *object TSRMLS_DC) /* {{{ */ { zend_stack_push(&CG(object_stack), object, sizeof(znode)); @@ -3800,12 +3964,12 @@ zend_op *opline; unsigned char *ptr = NULL; - new_token->u.opline_num = get_next_op_number(CG(active_op_array)); + new_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_NEW; - opline->result.op_type = IS_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *class_type; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, class_type); SET_UNUSED(opline->op2); zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(unsigned char *)); @@ -3819,8 +3983,8 @@ zend_do_end_function_call(NULL, &ctor_result, argument_list, 1, 0 TSRMLS_CC); zend_do_free(&ctor_result TSRMLS_CC); - CG(active_op_array)->opcodes[new_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); - *result = CG(active_op_array)->opcodes[new_token->u.opline_num].result; + CG(active_op_array)->opcodes[new_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); + GET_NODE(result, CG(active_op_array)->opcodes[new_token->u.op.opline_num].result); } /* }}} */ @@ -3916,11 +4080,15 @@ } opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CONSTANT; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *constant_container; - opline->op2 = *constant_name; - *result = opline->result; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, constant_container); + if (opline->op1_type == IS_CONST) { + add_lowercased_class_name(opline->op1.constant TSRMLS_CC); + } + SET_NODE(opline->op2, constant_name); + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); + GET_NODE(result, opline->result); break; } return; @@ -3956,9 +4124,9 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CONSTANT; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - *result = opline->result; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + GET_NODE(result, opline->result); SET_UNUSED(opline->op1); if(compound) { /* the name is unambiguous */ @@ -3966,7 +4134,8 @@ } else { opline->extended_value = IS_CONSTANT_UNQUALIFIED; } - opline->op2 = *constant_name; + SET_NODE(opline->op2, constant_name); + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); break; } } @@ -3985,25 +4154,22 @@ opline->opcode = ZEND_SEND_VAR; break; } - opline->op1 = *cmd; - opline->op2.u.opline_num = 0; + SET_NODE(opline->op1, cmd); + opline->op2.opline_num = 0; opline->extended_value = ZEND_DO_FCALL; SET_UNUSED(opline->op2); /* FIXME: exception support not added to this op2 */ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DO_FCALL; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_VAR; - Z_STRVAL(opline->op1.u.constant) = estrndup("shell_exec", sizeof("shell_exec")-1); - Z_STRLEN(opline->op1.u.constant) = sizeof("shell_exec")-1; - INIT_PZVAL(&opline->op1.u.constant); - Z_TYPE(opline->op1.u.constant) = IS_STRING; - opline->op1.op_type = IS_CONST; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_VAR; + LITERAL_STRINGL(opline->op1, estrndup("shell_exec", sizeof("shell_exec")-1), sizeof("shell_exec")-1, 0); + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); + opline->op1_type = IS_CONST; opline->extended_value = 1; SET_UNUSED(opline->op2); - ZVAL_LONG(&opline->op2.u.constant, zend_hash_func("shell_exec", sizeof("shell_exec"))); - *result = opline->result; + GET_NODE(result, opline->result); } /* }}} */ @@ -4012,13 +4178,25 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INIT_ARRAY; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->result.op_type = IS_TMP_VAR; - *result = opline->result; + opline->result.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; + GET_NODE(result, opline->result); if (expr) { - opline->op1 = *expr; + SET_NODE(opline->op1, expr); if (offset) { - opline->op2 = *offset; + SET_NODE(opline->op2, offset); + if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) { + long index; + int numeric = 0; + + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1); + if (numeric) { + zval_dtor(&CONSTANT(opline->op2.constant)); + ZVAL_LONG(&CONSTANT(opline->op2.constant), index); + } else { + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); + } + } } else { SET_UNUSED(opline->op2); } @@ -4035,10 +4213,22 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ADD_ARRAY_ELEMENT; - opline->result = *result; - opline->op1 = *expr; + SET_NODE(opline->result, result); + SET_NODE(opline->op1, expr); if (offset) { - opline->op2 = *offset; + SET_NODE(opline->op2, offset); + if (opline->op2_type == IS_CONST && Z_TYPE(CONSTANT(opline->op2.constant)) == IS_STRING) { + long index; + int numeric = 0; + + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1); + if (numeric) { + zval_dtor(&CONSTANT(opline->op2.constant)); + ZVAL_LONG(&CONSTANT(opline->op2.constant), index); + } else { + Z_HASH_P(&CONSTANT(opline->op2.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1); + } + } } else { SET_UNUSED(opline->op2); } @@ -4154,19 +4344,16 @@ opline->opcode = ZEND_FETCH_DIM_TMP_VAR; break; } - opline->extended_value = ZEND_FETCH_ADD_LOCK; + opline->extended_value |= ZEND_FETCH_ADD_LOCK; } else { opline->opcode = ZEND_FETCH_DIM_R; } - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = last_container; - opline->op2.op_type = IS_CONST; - Z_TYPE(opline->op2.u.constant) = IS_LONG; - Z_LVAL(opline->op2.u.constant) = *((int *) dimension->data); - INIT_PZVAL(&opline->op2.u.constant); - last_container = opline->result; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, &last_container); + opline->op2_type = IS_CONST; + LITERAL_LONG(opline->op2, *((int *) dimension->data)); + GET_NODE(&last_container, opline->result); dimension = dimension->next; } ((list_llist_element *) le->data)->value = last_container; @@ -4220,13 +4407,15 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = (fetch_type == ZEND_FETCH_LEXICAL) ? ZEND_FETCH_R : ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *varname; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, varname); + if (opline->op1_type == IS_CONST) { + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); + } SET_UNUSED(opline->op2); - opline->op2.u.EA.type = ZEND_FETCH_STATIC; - result = opline->result; + opline->extended_value = ZEND_FETCH_STATIC; + GET_NODE(&result, opline->result); if (varname->op_type == IS_CONST) { zval_copy_ctor(&varname->u.constant); @@ -4242,9 +4431,7 @@ } else { zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC); } - CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; - -/* zval_dtor(&varname->u.constant); */ + CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result_type |= EXT_TYPE_UNUSED; } /* }}} */ @@ -4282,13 +4469,15 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_W; /* the default mode must be Write, since fetch_simple_variable() is used to define function arguments */ - opline->result.op_type = IS_VAR; - opline->result.u.EA.type = 0; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *varname; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, varname); + if (opline->op1_type == IS_CONST) { + Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))+1); + } SET_UNUSED(opline->op2); - opline->op2.u.EA.type = fetch_type; - result = opline->result; + opline->extended_value = fetch_type; + GET_NODE(&result, opline->result); if (varname->op_type == IS_CONST) { zval_copy_ctor(&varname->u.constant); @@ -4296,7 +4485,7 @@ fetch_simple_variable(&lval, varname, 0 TSRMLS_CC); /* Relies on the fact that the default fetch is BP_VAR_W */ zend_do_assign_ref(NULL, &lval, &result TSRMLS_CC); - CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result.u.EA.type |= EXT_TYPE_UNUSED; + CG(active_op_array)->opcodes[CG(active_op_array)->last-1].result_type |= EXT_TYPE_UNUSED; } /* }}} */ @@ -4305,12 +4494,12 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_CAST; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *expr; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, expr); SET_UNUSED(opline->op2); opline->extended_value = type; - *result = opline->result; + GET_NODE(result, opline->result); } /* }}} */ @@ -4321,12 +4510,12 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INCLUDE_OR_EVAL; - opline->result.op_type = IS_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *op1; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, op1); SET_UNUSED(opline->op2); - Z_LVAL(opline->op2.u.constant) = type; - *result = opline->result; + opline->extended_value = type; + GET_NODE(result, opline->result); } zend_do_extended_fcall_end(TSRMLS_C); } @@ -4355,11 +4544,10 @@ if (variable->op_type == IS_CV) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_UNSET_VAR; - opline->op1 = *variable; + SET_NODE(opline->op1, variable); SET_UNUSED(opline->op2); - opline->op2.u.EA.type = ZEND_FETCH_LOCAL; SET_UNUSED(opline->result); - opline->extended_value = ZEND_QUICK_SET; + opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; } else { last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1]; @@ -4390,11 +4578,10 @@ if (variable->op_type == IS_CV) { last_op = get_next_op(CG(active_op_array) TSRMLS_CC); last_op->opcode = ZEND_ISSET_ISEMPTY_VAR; - last_op->op1 = *variable; + SET_NODE(last_op->op1, variable); SET_UNUSED(last_op->op2); - last_op->op2.u.EA.type = ZEND_FETCH_LOCAL; - last_op->result.u.var = get_temporary_variable(CG(active_op_array)); - last_op->extended_value = ZEND_QUICK_SET; + last_op->result.var = get_temporary_variable(CG(active_op_array)); + last_op->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; } else { last_op = &CG(active_op_array)->opcodes[get_next_op_number(CG(active_op_array))-1]; @@ -4409,12 +4596,11 @@ last_op->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ; break; } - last_op->extended_value = 0; } - last_op->result.op_type = IS_TMP_VAR; + last_op->result_type = IS_TMP_VAR; last_op->extended_value |= type; - *result = last_op->result; + GET_NODE(result, last_op->result); } /* }}} */ @@ -4436,13 +4622,13 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_INSTANCEOF; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *expr; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, expr); - opline->op2 = *class_znode; + SET_NODE(opline->op2, class_znode); - *result = opline->result; + GET_NODE(result, opline->result); } /* }}} */ @@ -4460,53 +4646,50 @@ is_variable = 1; } /* save the location of FETCH_W instruction(s) */ - open_brackets_token->u.opline_num = get_next_op_number(CG(active_op_array)); + open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC); if (CG(active_op_array)->last > 0 && CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_FETCH_OBJ_W) { /* Only lock the container if we are fetching from a real container and not $this */ - if (CG(active_op_array)->opcodes[CG(active_op_array)->last-1].op1.op_type == IS_VAR) { + if (CG(active_op_array)->opcodes[CG(active_op_array)->last-1].op1_type == IS_VAR) { CG(active_op_array)->opcodes[CG(active_op_array)->last-1].extended_value |= ZEND_FETCH_ADD_LOCK; push_container = 1; } } } else { is_variable = 0; - open_brackets_token->u.opline_num = get_next_op_number(CG(active_op_array)); + open_brackets_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); } /* save the location of FE_RESET */ - foreach_token->u.opline_num = get_next_op_number(CG(active_op_array)); + foreach_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); /* Preform array reset */ opline->opcode = ZEND_FE_RESET; - opline->result.op_type = IS_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *array; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, array); SET_UNUSED(opline->op2); opline->extended_value = is_variable ? ZEND_FE_RESET_VARIABLE : 0; - dummy_opline.result = opline->result; + COPY_NODE(dummy_opline.result, opline->result); if (push_container) { - dummy_opline.op1 = CG(active_op_array)->opcodes[CG(active_op_array)->last-2].op1; + COPY_NODE(dummy_opline.op1, CG(active_op_array)->opcodes[CG(active_op_array)->last-2].op1); } else { - znode tmp; - - tmp.op_type = IS_UNUSED; - dummy_opline.op1 = tmp; + dummy_opline.op1_type = IS_UNUSED; } zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op)); /* save the location of FE_FETCH */ - as_token->u.opline_num = get_next_op_number(CG(active_op_array)); + as_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FE_FETCH; - opline->result.op_type = IS_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = dummy_opline.result; + opline->result_type = IS_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + COPY_NODE(opline->op1, dummy_opline.result); opline->extended_value = 0; SET_UNUSED(opline->op2); @@ -4524,7 +4707,7 @@ znode dummy, value_node; zend_bool assign_by_ref=0; - opline = &CG(active_op_array)->opcodes[as_token->u.opline_num]; + opline = &CG(active_op_array)->opcodes[as_token->u.op. opline_num]; if (key->op_type != IS_UNUSED) { znode *tmp; @@ -4537,38 +4720,38 @@ opline->extended_value |= ZEND_FE_FETCH_WITH_KEY; } - if ((key->op_type != IS_UNUSED) && (key->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE)) { + if ((key->op_type != IS_UNUSED) && (key->EA & ZEND_PARSED_REFERENCE_VARIABLE)) { zend_error(E_COMPILE_ERROR, "Key element cannot be a reference"); } - if (value->u.EA.type & ZEND_PARSED_REFERENCE_VARIABLE) { + if (value->EA & ZEND_PARSED_REFERENCE_VARIABLE) { assign_by_ref = 1; if (!(opline-1)->extended_value) { zend_error(E_COMPILE_ERROR, "Cannot create references to elements of a temporary array expression"); } /* Mark extended_value for assign-by-reference */ opline->extended_value |= ZEND_FE_FETCH_BYREF; - CG(active_op_array)->opcodes[foreach_token->u.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE; + CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].extended_value |= ZEND_FE_RESET_REFERENCE; } else { zend_op *foreach_copy; - zend_op *fetch = &CG(active_op_array)->opcodes[foreach_token->u.opline_num]; - zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.opline_num]; + zend_op *fetch = &CG(active_op_array)->opcodes[foreach_token->u.op.opline_num]; + zend_op *end = &CG(active_op_array)->opcodes[open_brackets_token->u.op.opline_num]; /* Change "write context" into "read context" */ fetch->extended_value = 0; /* reset ZEND_FE_RESET_VARIABLE */ while (fetch != end) { --fetch; - if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2.op_type == IS_UNUSED) { + if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) { zend_error(E_COMPILE_ERROR, "Cannot use [] for reading"); } fetch->opcode -= 3; /* FETCH_W -> FETCH_R */ } /* prevent double SWITCH_FREE */ zend_stack_top(&CG(foreach_copy_stack), (void **) &foreach_copy); - foreach_copy->op1.op_type = IS_UNUSED; + foreach_copy->op1_type = IS_UNUSED; } - value_node = opline->result; + GET_NODE(&value_node, opline->result); if (assign_by_ref) { zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC); @@ -4582,11 +4765,10 @@ if (key->op_type != IS_UNUSED) { znode key_node; - opline = &CG(active_op_array)->opcodes[as_token->u.opline_num+1]; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.EA.type = 0; - opline->result.u.opline_num = get_temporary_variable(CG(active_op_array)); - key_node = opline->result; + opline = &CG(active_op_array)->opcodes[as_token->u.op.opline_num+1]; + opline->result_type = IS_TMP_VAR; + opline->result.opline_num = get_temporary_variable(CG(active_op_array)); + GET_NODE(&key_node, opline->result); zend_do_assign(&dummy, key, &key_node TSRMLS_CC); zend_do_free(&dummy TSRMLS_CC); @@ -4603,14 +4785,14 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP; - opline->op1.u.opline_num = as_token->u.opline_num; + opline->op1.opline_num = as_token->u.op.opline_num; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - CG(active_op_array)->opcodes[foreach_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); /* FE_RESET */ - CG(active_op_array)->opcodes[as_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); /* FE_FETCH */ + CG(active_op_array)->opcodes[foreach_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_RESET */ + CG(active_op_array)->opcodes[as_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); /* FE_FETCH */ - do_end_loop(as_token->u.opline_num, 1 TSRMLS_CC); + do_end_loop(as_token->u.op.opline_num, 1 TSRMLS_CC); zend_stack_top(&CG(foreach_copy_stack), (void **) &container_ptr); generate_free_foreach_copy(container_ptr TSRMLS_CC); @@ -4698,7 +4880,7 @@ zend_stack_top(&CG(declare_stack), (void **) &declarables); /* We should restore if there was more than (current - start) - (ticks?1:0) opcodes */ - if ((get_next_op_number(CG(active_op_array)) - declare_token->u.opline_num) - ((Z_LVAL(CG(declarables).ticks))?1:0)) { + if ((get_next_op_number(CG(active_op_array)) - declare_token->u.op.opline_num) - ((Z_LVAL(CG(declarables).ticks))?1:0)) { CG(declarables) = *declarables; } } @@ -4709,7 +4891,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_EXIT; - opline->op1 = *message; + SET_NODE(opline->op1, message); SET_UNUSED(opline->op2); result->op_type = IS_CONST; @@ -4723,11 +4905,11 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_BEGIN_SILENCE; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - *strudel_token = opline->result; + GET_NODE(strudel_token, opline->result); } /* }}} */ @@ -4736,7 +4918,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_END_SILENCE; - opline->op1 = *strudel_token; + SET_NODE(opline->op1, strudel_token); SET_UNUSED(opline->op2); } /* }}} */ @@ -4747,14 +4929,14 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP_SET; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *value; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, value); SET_UNUSED(opline->op2); - *colon_token = opline->result; + GET_NODE(colon_token, opline->result); - jmp_token->u.opline_num = op_number; + jmp_token->u.op .opline_num = op_number; INC_BPC(CG(active_op_array)); } @@ -4766,13 +4948,13 @@ opline->opcode = ZEND_QM_ASSIGN; opline->extended_value = 0; - opline->result = *colon_token; - opline->op1 = *false_value; + SET_NODE(opline->result, colon_token); + SET_NODE(opline->op1, false_value); SET_UNUSED(opline->op2); - *result = opline->result; + GET_NODE(result, opline->result); - CG(active_op_array)->opcodes[jmp_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); DEC_BPC(CG(active_op_array)); } @@ -4786,10 +4968,10 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMPZ; - opline->op1 = *cond; + SET_NODE(opline->op1, cond); SET_UNUSED(opline->op2); - opline->op2.u.opline_num = jmpz_op_number; - *qm_token = opline->op2; + opline->op2.opline_num = jmpz_op_number; + GET_NODE(qm_token, opline->op2); INC_BPC(CG(active_op_array)); } @@ -4799,16 +4981,16 @@ { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - CG(active_op_array)->opcodes[qm_token->u.opline_num].op2.u.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */ + CG(active_op_array)->opcodes[qm_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array))+1; /* jmp over the ZEND_JMP */ opline->opcode = ZEND_QM_ASSIGN; - opline->result.op_type = IS_TMP_VAR; - opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *true_value; + opline->result_type = IS_TMP_VAR; + opline->result.var = get_temporary_variable(CG(active_op_array)); + SET_NODE(opline->op1, true_value); SET_UNUSED(opline->op2); - *qm_token = opline->result; - colon_token->u.opline_num = get_next_op_number(CG(active_op_array)); + GET_NODE(qm_token, opline->result); + colon_token->u.op.opline_num = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_JMP; @@ -4822,13 +5004,13 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_QM_ASSIGN; - opline->result = *qm_token; - opline->op1 = *false_value; + SET_NODE(opline->result, qm_token); + SET_NODE(opline->op1, false_value); SET_UNUSED(opline->op2); - CG(active_op_array)->opcodes[colon_token->u.opline_num].op1.u.opline_num = get_next_op_number(CG(active_op_array)); + CG(active_op_array)->opcodes[colon_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array)); - *result = opline->result; + GET_NODE(result, opline->result); DEC_BPC(CG(active_op_array)); } @@ -4888,9 +5070,9 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_TICKS; - opline->op1.u.constant = CG(declarables).ticks; - opline->op1.op_type = IS_CONST; + SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); + opline->extended_value = Z_LVAL(CG(declarables).ticks); } } /* }}} */ @@ -5266,8 +5448,8 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_DECLARE_CONST; SET_UNUSED(opline->result); - opline->op1 = *name; - opline->op2 = *value; + SET_NODE(opline->op1, name); + SET_NODE(opline->op2, value); } /* }}} */ Index: Zend/ZendTS.dsp =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: Zend/zend_object_handlers.h =================================================================== --- Zend/zend_object_handlers.h (revision 297868) +++ Zend/zend_object_handlers.h (working copy) @@ -24,13 +24,14 @@ union _zend_function; struct _zend_property_info; +struct _zend_literal; /* The following rule applies to read_property() and read_dimension() implementations: If you return a zval which is not otherwise referenced by the extension or the engine's symbol table, its reference count should be 0. */ /* Used to fetch property from the object, read-only */ -typedef zval *(*zend_object_read_property_t)(zval *object, zval *member, int type TSRMLS_DC); +typedef zval *(*zend_object_read_property_t)(zval *object, zval *member, int type, const struct _zend_literal *key TSRMLS_DC); /* Used to fetch dimension from the object, read-only */ typedef zval *(*zend_object_read_dimension_t)(zval *object, zval *offset, int type TSRMLS_DC); @@ -42,14 +43,14 @@ any changes. You should NOT modify the reference count of the value passed to you. */ /* Used to set property of the object */ -typedef void (*zend_object_write_property_t)(zval *object, zval *member, zval *value TSRMLS_DC); +typedef void (*zend_object_write_property_t)(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC); /* Used to set dimension of the object */ typedef void (*zend_object_write_dimension_t)(zval *object, zval *offset, zval *value TSRMLS_DC); /* Used to create pointer to the property of the object, for future direct r/w access */ -typedef zval **(*zend_object_get_property_ptr_ptr_t)(zval *object, zval *member TSRMLS_DC); +typedef zval **(*zend_object_get_property_ptr_ptr_t)(zval *object, zval *member, const struct _zend_literal *key TSRMLS_DC); /* Used to set object value. Can be used to override assignments and scalar write ops (like ++, +=) on the object */ @@ -66,13 +67,13 @@ * 1 (set) whether property exists and is true * 2 (exists) whether property exists */ -typedef int (*zend_object_has_property_t)(zval *object, zval *member, int has_set_exists TSRMLS_DC); +typedef int (*zend_object_has_property_t)(zval *object, zval *member, int has_set_exists, const struct _zend_literal *key TSRMLS_DC); /* Used to check if a dimension of the object exists */ typedef int (*zend_object_has_dimension_t)(zval *object, zval *member, int check_empty TSRMLS_DC); /* Used to remove a property of the object */ -typedef void (*zend_object_unset_property_t)(zval *object, zval *member TSRMLS_DC); +typedef void (*zend_object_unset_property_t)(zval *object, zval *member, const struct _zend_literal *key TSRMLS_DC); /* Used to remove a dimension of the object */ typedef void (*zend_object_unset_dimension_t)(zval *object, zval *offset TSRMLS_DC); @@ -87,7 +88,7 @@ /* Andi - EX(fbc) (function being called) needs to be initialized already in the INIT fcall opcode so that the parameters can be parsed the right way. We need to add another callback for this. */ typedef int (*zend_object_call_method_t)(char *method, INTERNAL_FUNCTION_PARAMETERS); -typedef union _zend_function *(*zend_object_get_method_t)(zval **object_ptr, char *method, int method_len TSRMLS_DC); +typedef union _zend_function *(*zend_object_get_method_t)(zval **object_ptr, char *method, int method_len, const struct _zend_literal *key TSRMLS_DC); typedef union _zend_function *(*zend_object_get_constructor_t)(zval *object TSRMLS_DC); /* Object maintenance/destruction */ @@ -143,9 +144,9 @@ extern ZEND_API zend_object_handlers std_object_handlers; BEGIN_EXTERN_C() -ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC); -ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC); -ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC); +ZEND_API union _zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen, const struct _zend_literal *key TSRMLS_DC); +ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent, const struct _zend_literal *key TSRMLS_DC); +ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len, const struct _zend_literal *key TSRMLS_DC); ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC); ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC); ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC); Index: Zend/zend_compile.h =================================================================== --- Zend/zend_compile.h (revision 297868) +++ Zend/zend_compile.h (working copy) @@ -34,7 +34,7 @@ #define FREE_PNODE(znode) zval_dtor(&znode->u.constant); -#define SET_UNUSED(op) (op).op_type = IS_UNUSED +#define SET_UNUSED(op) op ## _type = IS_UNUSED #define INC_BPC(op_array) if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { ((op_array)->backpatch_count++); } #define DEC_BPC(op_array) if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { ((op_array)->backpatch_count--); } @@ -52,20 +52,33 @@ typedef struct _zend_op_array zend_op_array; typedef struct _zend_op zend_op; -typedef struct _znode { +typedef struct _zend_literal { + zval constant; + ulong hash_value; +} zend_literal; + +#define Z_HASH_P(zv) \ + (((zend_literal*)(zv))->hash_value) + +typedef union _znode_op { + zend_uint constant; + zend_uint var; + zend_uint num; + zend_ulong hash; + zend_uint opline_num; /* Needs to be signed */ + zend_op *jmp_addr; + zval *zv; + zend_literal *literal; +} znode_op; + +typedef struct _znode { /* used only during compilation */ int op_type; union { - zval constant; - - zend_uint var; - zend_uint opline_num; /* Needs to be signed */ + znode_op op; + zval constant; /* replaced by literal/zv */ zend_op_array *op_array; - zend_op *jmp_addr; - struct { - zend_uint var; /* dummy */ - zend_uint type; - } EA; } u; + zend_uint EA; /* extended attributes */ } znode; typedef struct _zend_execute_data zend_execute_data; @@ -80,12 +93,15 @@ struct _zend_op { opcode_handler_t handler; - znode result; - znode op1; - znode op2; + znode_op op1; + znode_op op2; + znode_op result; ulong extended_value; uint lineno; zend_uchar opcode; + zend_uchar op1_type; + zend_uchar op2_type; + zend_uchar result_type; }; @@ -236,6 +252,9 @@ zend_uint doc_comment_len; zend_uint early_binding; /* the linked list of delayed declarations */ + zend_literal *literals; + int last_literal, size_literal; + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; @@ -323,7 +342,6 @@ zend_class_entry *current_called_scope; zval *current_this; zval *current_object; - struct _zend_op *call_opline; }; #define EX(element) execute_data.element @@ -335,8 +353,7 @@ #define IS_UNUSED (1<<3) /* Unused variable */ #define IS_CV (1<<4) /* Compiled variable */ -#define EXT_TYPE_UNUSED (1<<0) -#define EXT_TYPE_FREE_ON_RETURN (2<<0) +#define EXT_TYPE_UNUSED (1<<5) #include "zend_globals.h" @@ -373,7 +390,7 @@ void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC); void zend_do_unary_op(zend_uchar op, znode *result, const znode *op1 TSRMLS_DC); void zend_do_binary_assign_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC); -void zend_do_assign(znode *result, znode *variable, const znode *value TSRMLS_DC); +void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC); void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC); void fetch_simple_variable(znode *result, znode *varname, int bp TSRMLS_DC); void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC); @@ -422,7 +439,7 @@ int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC); void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC); -void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_bool pass_by_reference TSRMLS_DC); +void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_bool pass_by_reference TSRMLS_DC); int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC); void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC); void zend_do_clone(znode *result, const znode *expr TSRMLS_DC); @@ -438,13 +455,13 @@ void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC); void zend_do_try(znode *try_token TSRMLS_DC); -void zend_do_begin_catch(znode *try_token, znode *catch_class, const znode *catch_var, znode *first_catch TSRMLS_DC); +void zend_do_begin_catch(znode *try_token, znode *catch_class, znode *catch_var, znode *first_catch TSRMLS_DC); void zend_do_end_catch(const znode *try_token TSRMLS_DC); void zend_do_throw(const znode *expr TSRMLS_DC); -ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, zend_bool compile_time); -ZEND_API zend_class_entry *do_bind_class(const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC); -ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC); +ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time); +ZEND_API zend_class_entry *do_bind_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC); +ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC); ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC); ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC); void zend_do_implements_interface(znode *interface_znode TSRMLS_DC); @@ -472,7 +489,6 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC); void zend_do_end_class_declaration(const znode *class_token, const znode *parent_token TSRMLS_DC); void zend_do_declare_property(const znode *var_name, const znode *value, zend_uint access_type TSRMLS_DC); -void zend_do_declare_implicit_property(TSRMLS_D); void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_DC); void zend_do_fetch_property(znode *result, znode *object, const znode *property TSRMLS_DC); @@ -608,6 +624,8 @@ int zendlex(znode *zendlval TSRMLS_DC); +int zend_add_literal(zend_op_array *op_array, const zval *zv); + /* BEGIN: OPCODES */ #include "zend_vm_opcodes.h" @@ -616,18 +634,6 @@ /* END: OPCODES */ - - - -/* global/local fetches */ -#define ZEND_FETCH_GLOBAL 0 -#define ZEND_FETCH_LOCAL 1 -#define ZEND_FETCH_STATIC 2 -#define ZEND_FETCH_STATIC_MEMBER 3 -#define ZEND_FETCH_GLOBAL_LOCK 4 -#define ZEND_FETCH_LEXICAL 5 - - /* class fetches */ #define ZEND_FETCH_CLASS_DEFAULT 0 #define ZEND_FETCH_CLASS_SELF 1 @@ -679,23 +685,36 @@ #define ZEND_REQUIRE (1<<3) #define ZEND_REQUIRE_ONCE (1<<4) -#define ZEND_ISSET (1<<0) -#define ZEND_ISEMPTY (1<<1) -#define ZEND_ISSET_ISEMPTY_MASK (ZEND_ISSET | ZEND_ISEMPTY) -#define ZEND_QUICK_SET (1<<2) - #define ZEND_CT (1<<0) #define ZEND_RT (1<<1) -#define ZEND_FETCH_STANDARD 0 -#define ZEND_FETCH_ADD_LOCK (1<<0) -#define ZEND_FETCH_MAKE_REF (1<<1) +/* global/local fetches */ +#define ZEND_FETCH_GLOBAL 0x00000000 +#define ZEND_FETCH_LOCAL 0x10000000 +#define ZEND_FETCH_STATIC 0x20000000 +#define ZEND_FETCH_STATIC_MEMBER 0x30000000 +#define ZEND_FETCH_GLOBAL_LOCK 0x40000000 +#define ZEND_FETCH_LEXICAL 0x50000000 +#define ZEND_FETCH_TYPE_MASK 0x70000000 + +#define ZEND_FETCH_STANDARD 0x00000000 +#define ZEND_FETCH_ADD_LOCK 0x08000000 +#define ZEND_FETCH_MAKE_REF 0x04000000 + +#define ZEND_ISSET 0x02000000 +#define ZEND_ISEMPTY 0x01000000 +#define ZEND_ISSET_ISEMPTY_MASK (ZEND_ISSET | ZEND_ISEMPTY) +#define ZEND_QUICK_SET 0x00800000 + +#define ZEND_FETCH_ARG_MASK 0x000fffff + #define ZEND_FE_FETCH_BYREF 1 #define ZEND_FE_FETCH_WITH_KEY 2 -#define ZEND_FE_RESET_VARIABLE 1 -#define ZEND_FE_RESET_REFERENCE 2 +#define ZEND_FE_RESET_VARIABLE (1<<0) +#define ZEND_FE_RESET_REFERENCE (1<<1) +#define EXT_TYPE_FREE_ON_RETURN (1<<2) #define ZEND_MEMBER_FUNC_CALL 1<<0 Index: Zend/zend_ptr_stack.h =================================================================== --- Zend/zend_ptr_stack.h (revision 297868) +++ Zend/zend_ptr_stack.h (working copy) @@ -54,7 +54,7 @@ /* Not doing this with a macro because of the loop unrolling in the element assignment. Just using a macro for 3 in the body for readability sake. */ -static inline void zend_ptr_stack_3_push(zend_ptr_stack *stack, void *a, void *b, void *c) +static zend_always_inline void zend_ptr_stack_3_push(zend_ptr_stack *stack, void *a, void *b, void *c) { #define ZEND_PTR_STACK_NUM_ARGS 3 @@ -68,7 +68,7 @@ #undef ZEND_PTR_STACK_NUM_ARGS } -static inline void zend_ptr_stack_2_push(zend_ptr_stack *stack, void *a, void *b) +static zend_always_inline void zend_ptr_stack_2_push(zend_ptr_stack *stack, void *a, void *b) { #define ZEND_PTR_STACK_NUM_ARGS 2 @@ -81,7 +81,7 @@ #undef ZEND_PTR_STACK_NUM_ARGS } -static inline void zend_ptr_stack_3_pop(zend_ptr_stack *stack, void **a, void **b, void **c) +static zend_always_inline void zend_ptr_stack_3_pop(zend_ptr_stack *stack, void **a, void **b, void **c) { *a = *(--stack->top_element); *b = *(--stack->top_element); @@ -89,14 +89,14 @@ stack->top -= 3; } -static inline void zend_ptr_stack_2_pop(zend_ptr_stack *stack, void **a, void **b) +static zend_always_inline void zend_ptr_stack_2_pop(zend_ptr_stack *stack, void **a, void **b) { *a = *(--stack->top_element); *b = *(--stack->top_element); stack->top -= 2; } -static inline void zend_ptr_stack_push(zend_ptr_stack *stack, void *ptr) +static zend_always_inline void zend_ptr_stack_push(zend_ptr_stack *stack, void *ptr) { ZEND_PTR_STACK_RESIZE_IF_NEEDED(stack, 1) @@ -104,7 +104,7 @@ *(stack->top_element++) = ptr; } -static inline void *zend_ptr_stack_pop(zend_ptr_stack *stack) +static zend_always_inline void *zend_ptr_stack_pop(zend_ptr_stack *stack) { stack->top--; return *(--stack->top_element); Index: Zend/tests/isset_003.phpt =================================================================== --- Zend/tests/isset_003.phpt (revision 297868) +++ Zend/tests/isset_003.phpt (working copy) @@ -29,10 +29,10 @@ bool(false) bool(false) +Notice: Undefined variable: c in %s on line %d + Notice: Undefined variable: d in %s on line %d -Notice: Undefined variable: c in %s on line %d - Notice: Trying to get property of non-object in %s on line %d bool(false) bool(true) Index: Zend/zend_API.c =================================================================== --- Zend/zend_API.c (revision 297868) +++ Zend/zend_API.c (working copy) @@ -971,7 +971,7 @@ MAKE_STD_ZVAL(member); ZVAL_STRINGL(member, hash_key->arKey, hash_key->nKeyLength-1, 1); - obj_ht->write_property(obj, member, *value TSRMLS_CC); + obj_ht->write_property(obj, member, *value, 0 TSRMLS_CC); zval_ptr_dtor(&member); } return ZEND_HASH_APPLY_KEEP; @@ -1435,7 +1435,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1453,7 +1453,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1471,7 +1471,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1489,7 +1489,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1507,7 +1507,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1525,7 +1525,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1543,7 +1543,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, tmp, 0 TSRMLS_CC); zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */ zval_ptr_dtor(&z_key); return SUCCESS; @@ -1557,7 +1557,7 @@ MAKE_STD_ZVAL(z_key); ZVAL_STRINGL(z_key, key, key_len-1, 1); - Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, value TSRMLS_CC); + Z_OBJ_HANDLER_P(arg, write_property)(arg, z_key, value, 0 TSRMLS_CC); zval_ptr_dtor(&z_key); return SUCCESS; } @@ -1893,10 +1893,12 @@ } } fname_len = strlen(ptr->fname); - lowercase_name = zend_str_tolower_dup(ptr->fname, fname_len); + lowercase_name = CG(new_interned_string)(zend_str_tolower_dup(ptr->fname, fname_len), fname_len + 1, 1 TSRMLS_CC); if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)®_function) == FAILURE) { unload=1; - efree(lowercase_name); + if (!IS_INTERNED(lowercase_name)) { + efree(lowercase_name); + } break; } if (scope) { @@ -1938,7 +1940,9 @@ } ptr++; count++; - efree(lowercase_name); + if (!IS_INTERNED(lowercase_name)) { + efree(lowercase_name); + } } if (unload) { /* before unloading, display all remaining bad function in the module */ if (scope) { @@ -2168,7 +2172,7 @@ static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, zend_uint ce_flags TSRMLS_DC) /* {{{ */ { zend_class_entry *class_entry = malloc(sizeof(zend_class_entry)); - char *lowercase_name = malloc(orig_class_entry->name_length + 1); + char *lowercase_name = emalloc(orig_class_entry->name_length + 1); *class_entry = *orig_class_entry; class_entry->type = ZEND_INTERNAL_CLASS; @@ -2181,8 +2185,11 @@ } zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length); + lowercase_name = CG(new_interned_string)(lowercase_name, class_entry->name_length + 1, 1 TSRMLS_CC); zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL); - free(lowercase_name); + if (!IS_INTERNED(lowercase_name)) { + efree(lowercase_name); + } return class_entry; } /* }}} */ @@ -2381,7 +2388,7 @@ *strict_class = 1; ret = 1; } - } else if (zend_lookup_class_ex(name, name_len, 1, &pce TSRMLS_CC) == SUCCESS) { + } else if (zend_lookup_class_ex(name, name_len, NULL, 1, &pce TSRMLS_CC) == SUCCESS) { zend_class_entry *scope = EG(active_op_array) ? EG(active_op_array)->scope : NULL; fcc->calling_scope = *pce; @@ -2546,7 +2553,7 @@ call_via_handler = 1; retval = 1; } else if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) { - fcc->function_handler = Z_OBJ_HT_P(fcc->object_ptr)->get_method(&fcc->object_ptr, mname, mlen TSRMLS_CC); + fcc->function_handler = Z_OBJ_HT_P(fcc->object_ptr)->get_method(&fcc->object_ptr, mname, mlen, NULL TSRMLS_CC); if (fcc->function_handler) { if (strict_class && (!fcc->function_handler->common.scope || @@ -2567,7 +2574,7 @@ if (fcc->calling_scope->get_static_method) { fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC); } else { - fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, mlen TSRMLS_CC); + fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, mlen, NULL TSRMLS_CC); } if (fcc->function_handler) { retval = 1; @@ -3070,6 +3077,7 @@ { zend_property_info property_info; HashTable *target_symbol_table; + char *interned_name; if (!(access_type & ZEND_ACC_PPP_MASK)) { access_type |= ZEND_ACC_PUBLIC; @@ -3097,7 +3105,6 @@ int priv_name_length; zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS); - zend_hash_update(target_symbol_table, priv_name, priv_name_length+1, &property, sizeof(zval *), NULL); property_info.name = priv_name; property_info.name_length = priv_name_length; } @@ -3107,7 +3114,6 @@ int prot_name_length; zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS); - zend_hash_update(target_symbol_table, prot_name, prot_name_length+1, &property, sizeof(zval *), NULL); property_info.name = prot_name; property_info.name_length = prot_name_length; } @@ -3121,11 +3127,27 @@ zend_hash_del(target_symbol_table, prot_name, prot_name_length+1); pefree(prot_name, ce->type & ZEND_INTERNAL_CLASS); } - zend_hash_update(target_symbol_table, name, name_length+1, &property, sizeof(zval *), NULL); - property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length); + if (IS_INTERNED(name)) { + property_info.name = (char*)name; + } else { + property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length); + } property_info.name_length = name_length; break; } + + interned_name = CG(new_interned_string)(property_info.name, property_info.name_length+1, 0 TSRMLS_CC); + if (interned_name != property_info.name) { + if (ce->type == ZEND_USER_CLASS) { + efree(property_info.name); + } else { + free(property_info.name); + } + property_info.name = interned_name; + } + + zend_hash_update(target_symbol_table, property_info.name, property_info.name_length+1, &property, sizeof(zval *), NULL); + property_info.flags = access_type; property_info.h = zend_get_hash_value(property_info.name, property_info.name_length+1); @@ -3343,7 +3365,7 @@ } MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, name, name_length, 1); - Z_OBJ_HT_P(object)->write_property(object, property, value TSRMLS_CC); + Z_OBJ_HT_P(object)->write_property(object, property, value, 0 TSRMLS_CC); zval_ptr_dtor(&property); EG(scope) = old_scope; @@ -3428,7 +3450,7 @@ zend_class_entry *old_scope = EG(scope); EG(scope) = scope; - property = zend_std_get_static_property(scope, name, name_length, 0 TSRMLS_CC); + property = zend_std_get_static_property(scope, name, name_length, 0, NULL TSRMLS_CC); EG(scope) = old_scope; if (!property) { return FAILURE; @@ -3546,7 +3568,7 @@ MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, name, name_length, 1); - value = Z_OBJ_HT_P(object)->read_property(object, property, silent?BP_VAR_IS:BP_VAR_R TSRMLS_CC); + value = Z_OBJ_HT_P(object)->read_property(object, property, silent?BP_VAR_IS:BP_VAR_R, 0 TSRMLS_CC); zval_ptr_dtor(&property); EG(scope) = old_scope; @@ -3560,7 +3582,7 @@ zend_class_entry *old_scope = EG(scope); EG(scope) = scope; - property = zend_std_get_static_property(scope, name, name_length, silent TSRMLS_CC); + property = zend_std_get_static_property(scope, name, name_length, silent, NULL TSRMLS_CC); EG(scope) = old_scope; return property?*property:NULL; Index: Zend/zend_iterators.c =================================================================== --- Zend/zend_iterators.c (revision 297868) +++ Zend/zend_iterators.c (working copy) @@ -82,13 +82,13 @@ *iter = (zend_object_iterator *)zend_object_store_get_object(array_ptr TSRMLS_CC); return ZEND_ITER_OBJECT; } - if (HASH_OF(array_ptr)) { + if (Z_OBJPROP_P(array_ptr)) { return ZEND_ITER_PLAIN_OBJECT; } return ZEND_ITER_INVALID; case IS_ARRAY: - if (HASH_OF(array_ptr)) { + if (Z_ARRVAL_P(array_ptr)) { return ZEND_ITER_PLAIN_ARRAY; } return ZEND_ITER_INVALID; Index: Zend/zend_API.h =================================================================== --- Zend/zend_API.h (revision 297868) +++ Zend/zend_API.h (working copy) @@ -488,8 +488,12 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, const char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...); +ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, char *name, int name_len, ulong hash_value TSRMLS_DC); + ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC); +ZEND_API int zend_delete_global_variable_ex(char *name, int name_len, ulong hash_value TSRMLS_DC); + ZEND_API void zend_reset_all_cv(HashTable *symbol_table TSRMLS_DC); ZEND_API void zend_rebuild_symbol_table(TSRMLS_D); @@ -510,54 +514,61 @@ #define CHECK_ZVAL_STRING_REL(z) #endif -#define ZVAL_RESOURCE(z, l) { \ - Z_TYPE_P(z) = IS_RESOURCE; \ - Z_LVAL_P(z) = l; \ - } +#define ZVAL_RESOURCE(z, l) do { \ + zval *__z = (z); \ + Z_LVAL_P(__z) = l; \ + Z_TYPE_P(__z) = IS_RESOURCE;\ + } while (0) -#define ZVAL_BOOL(z, b) { \ - Z_TYPE_P(z) = IS_BOOL; \ - Z_LVAL_P(z) = ((b) != 0); \ - } +#define ZVAL_BOOL(z, b) do { \ + zval *__z = (z); \ + Z_LVAL_P(__z) = ((b) != 0); \ + Z_TYPE_P(__z) = IS_BOOL; \ + } while (0) #define ZVAL_NULL(z) { \ Z_TYPE_P(z) = IS_NULL; \ } #define ZVAL_LONG(z, l) { \ - Z_TYPE_P(z) = IS_LONG; \ - Z_LVAL_P(z) = l; \ + zval *__z = (z); \ + Z_LVAL_P(__z) = l; \ + Z_TYPE_P(__z) = IS_LONG; \ } #define ZVAL_DOUBLE(z, d) { \ - Z_TYPE_P(z) = IS_DOUBLE; \ - Z_DVAL_P(z) = d; \ + zval *__z = (z); \ + Z_DVAL_P(__z) = d; \ + Z_TYPE_P(__z) = IS_DOUBLE; \ } -#define ZVAL_STRING(z, s, duplicate) { \ - const char *__s=(s); \ - Z_STRLEN_P(z) = strlen(__s); \ - Z_STRVAL_P(z) = (duplicate?estrndup(__s, Z_STRLEN_P(z)):(char*)__s);\ - Z_TYPE_P(z) = IS_STRING; \ - } +#define ZVAL_STRING(z, s, duplicate) do { \ + const char *__s=(s); \ + zval *__z = (z); \ + Z_STRLEN_P(__z) = strlen(__s); \ + Z_STRVAL_P(__z) = (duplicate?estrndup(__s, Z_STRLEN_P(__z)):(char*)__s);\ + Z_TYPE_P(__z) = IS_STRING; \ + } while (0) -#define ZVAL_STRINGL(z, s, l, duplicate) { \ - const char *__s=(s); int __l=l; \ - Z_STRLEN_P(z) = __l; \ - Z_STRVAL_P(z) = (duplicate?estrndup(__s, __l):(char*)__s);\ - Z_TYPE_P(z) = IS_STRING; \ - } +#define ZVAL_STRINGL(z, s, l, duplicate) do { \ + const char *__s=(s); int __l=l; \ + zval *__z = (z); \ + Z_STRLEN_P(__z) = __l; \ + Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);\ + Z_TYPE_P(__z) = IS_STRING; \ + } while (0) -#define ZVAL_EMPTY_STRING(z) { \ - Z_STRLEN_P(z) = 0; \ - Z_STRVAL_P(z) = STR_EMPTY_ALLOC();\ - Z_TYPE_P(z) = IS_STRING; \ - } +#define ZVAL_EMPTY_STRING(z) do { \ + zval *__z = (z); \ + Z_STRLEN_P(__z) = 0; \ + Z_STRVAL_P(__z) = STR_EMPTY_ALLOC();\ + Z_TYPE_P(__z) = IS_STRING; \ + } while (0) #define ZVAL_ZVAL(z, zv, copy, dtor) { \ zend_uchar is_ref = Z_ISREF_P(z); \ zend_uint refcount = Z_REFCOUNT_P(z); \ - *(z) = *(zv); \ + ZVAL_COPY_VALUE(z, zv); \ if (copy) { \ zval_copy_ctor(z); \ } \ Index: Zend/zend_operators.c =================================================================== --- Zend/zend_operators.c (revision 297868) +++ Zend/zend_operators.c (working copy) @@ -1177,11 +1177,18 @@ /* must support result==op1 */ ZEND_API int add_char_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */ { - Z_STRLEN_P(result) = Z_STRLEN_P(op1) + 1; - Z_STRVAL_P(result) = (char *) erealloc(Z_STRVAL_P(op1), Z_STRLEN_P(result)+1); - Z_STRVAL_P(result)[Z_STRLEN_P(result) - 1] = (char) Z_LVAL_P(op2); - Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; - Z_TYPE_P(result) = IS_STRING; + int length = Z_STRLEN_P(op1) + 1; + char *buf; + + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length + 1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + } else { + buf = (char *) erealloc(Z_STRVAL_P(op1), length + 1); + } + buf[length - 1] = (char) Z_LVAL_P(op2); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); return SUCCESS; } /* }}} */ @@ -1190,12 +1197,17 @@ ZEND_API int add_string_to_string(zval *result, const zval *op1, const zval *op2) /* {{{ */ { int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); + char *buf; - Z_STRVAL_P(result) = (char *) erealloc(Z_STRVAL_P(op1), length+1); - memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); - Z_STRVAL_P(result)[length] = 0; - Z_STRLEN_P(result) = length; - Z_TYPE_P(result) = IS_STRING; + if (IS_INTERNED(Z_STRVAL_P(op1))) { + buf = (char *) emalloc(length+1); + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + } else { + buf = (char *) erealloc(Z_STRVAL_P(op1), length+1); + } + memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); return SUCCESS; } /* }}} */ @@ -1224,7 +1236,7 @@ if (use_copy2) { op2 = &op2_copy; } - if (result==op1) { /* special case, perform operations on result */ + if (result==op1 && !IS_INTERNED(Z_STRVAL_P(op1))) { /* special case, perform operations on result */ uint res_len = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); if (Z_STRLEN_P(result) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) { @@ -1239,12 +1251,13 @@ Z_STRVAL_P(result)[res_len]=0; Z_STRLEN_P(result) = res_len; } else { - Z_STRLEN_P(result) = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); - Z_STRVAL_P(result) = (char *) emalloc(Z_STRLEN_P(result) + 1); - memcpy(Z_STRVAL_P(result), Z_STRVAL_P(op1), Z_STRLEN_P(op1)); - memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); - Z_STRVAL_P(result)[Z_STRLEN_P(result)] = 0; - Z_TYPE_P(result) = IS_STRING; + int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2); + char *buf = (char *) emalloc(length + 1); + + memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1)); + memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); + buf[length] = 0; + ZVAL_STRINGL(result, buf, length, 0); } if (use_copy1) { zval_dtor(op1); @@ -1668,6 +1681,12 @@ return; } + if (IS_INTERNED(s)) { + s = (char*) emalloc(Z_STRLEN_P(str) + 1); + memcpy(s, Z_STRVAL_P(str), Z_STRLEN_P(str) + 1); + Z_STRVAL_P(str) = s; + } + while (pos >= 0) { ch = s[pos]; if (ch >= 'a' && ch <= 'z') { @@ -1753,7 +1772,9 @@ switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) { case IS_LONG: - efree(Z_STRVAL_P(op1)); + if (!IS_INTERNED(Z_STRVAL_P(op1))) { + efree(Z_STRVAL_P(op1)); + } if (lval == LONG_MAX) { /* switch to double */ double d = (double)lval; @@ -1763,7 +1784,9 @@ } break; case IS_DOUBLE: - efree(Z_STRVAL_P(op1)); + if (!IS_INTERNED(Z_STRVAL_P(op1))) { + efree(Z_STRVAL_P(op1)); + } ZVAL_DOUBLE(op1, dval+1); break; default: @@ -1879,6 +1902,9 @@ { int retval; + if (s1 == s2) { + return 0; + } retval = memcmp(s1, s2, MIN(len1, len2)); if (!retval) { return (len1 - len2); @@ -1892,6 +1918,9 @@ { int retval; + if (s1 == s2) { + return 0; + } retval = memcmp(s1, s2, MIN(length, MIN(len1, len2))); if (!retval) { return (MIN(length, len1) - MIN(length, len2)); @@ -1906,8 +1935,11 @@ int len; int c1, c2; + if (s1 == s2) { + return 0; + } + len = MIN(len1, len2); - while (len--) { c1 = zend_tolower((int)*(unsigned char *)s1++); c2 = zend_tolower((int)*(unsigned char *)s2++); @@ -1925,8 +1957,10 @@ int len; int c1, c2; + if (s1 == s2) { + return 0; + } len = MIN(length, MIN(len1, len2)); - while (len--) { c1 = zend_tolower((int)*(unsigned char *)s1++); c2 = zend_tolower((int)*(unsigned char *)s2++); Index: Zend/zend_vm_gen.php =================================================================== --- Zend/zend_vm_gen.php (revision 297868) +++ Zend/zend_vm_gen.php (working copy) @@ -82,7 +82,7 @@ ); $op1_type = array( - "ANY" => "opline->op1.op_type", + "ANY" => "opline->op1_type", "TMP" => "IS_TMP_VAR", "VAR" => "IS_VAR", "CONST" => "IS_CONST", @@ -91,7 +91,7 @@ ); $op2_type = array( - "ANY" => "opline->op2.op_type", + "ANY" => "opline->op2_type", "TMP" => "IS_TMP_VAR", "VAR" => "IS_VAR", "CONST" => "IS_CONST", @@ -118,75 +118,75 @@ ); $op1_get_zval_ptr = array( - "ANY" => "get_zval_ptr(&opline->op1, EX(Ts), &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", - "VAR" => "_get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", - "CONST" => "&opline->op1.u.constant", + "ANY" => "get_zval_ptr(opline->op1_type, &opline->op1, EX_Ts(), &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", + "CONST" => "opline->op1.zv", "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv(&opline->op1, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_cv_\\1(EX_CVs(), opline->op1.var TSRMLS_CC)", ); $op2_get_zval_ptr = array( - "ANY" => "get_zval_ptr(&opline->op2, EX(Ts), &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", - "VAR" => "_get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", - "CONST" => "&opline->op2.u.constant", + "ANY" => "get_zval_ptr(opline->op2_type, &opline->op2, EX_Ts(), &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", + "CONST" => "opline->op2.zv", "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_cv(&opline->op2, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_cv_\\1(EX_CVs(), opline->op2.var TSRMLS_CC)", ); $op1_get_zval_ptr_ptr = array( - "ANY" => "get_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, \\1)", + "ANY" => "get_zval_ptr_ptr(opline->op1_type, &opline->op1, EX_Ts(), &free_op1, \\1)", "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", "CONST" => "NULL", "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_ptr_cv_\\1(EX_CVs(), opline->op1.var TSRMLS_CC)", ); $op2_get_zval_ptr_ptr = array( - "ANY" => "get_zval_ptr_ptr(&opline->op2, EX(Ts), &free_op2, \\1)", + "ANY" => "get_zval_ptr_ptr(opline->op2_type, &opline->op2, EX_Ts(), &free_op2, \\1)", "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", "CONST" => "NULL", "UNUSED" => "NULL", - "CV" => "_get_zval_ptr_ptr_cv(&opline->op2, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_ptr_cv_\\1(EX_CVs(), opline->op2.var TSRMLS_CC)", ); $op1_get_obj_zval_ptr = array( - "ANY" => "get_obj_zval_ptr(&opline->op1, EX(Ts), &free_op1, \\1)", - "TMP" => "_get_zval_ptr_tmp(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", - "VAR" => "_get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", - "CONST" => "&opline->op1.u.constant", + "ANY" => "get_obj_zval_ptr(opline->op1_type, &opline->op1, EX_Ts(), &free_op1, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", + "CONST" => "opline->op1.zv", "UNUSED" => "_get_obj_zval_ptr_unused(TSRMLS_C)", - "CV" => "_get_zval_ptr_cv(&opline->op1, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_cv_\\1(EX_CVs(), opline->op1.var TSRMLS_CC)", ); $op2_get_obj_zval_ptr = array( - "ANY" => "get_obj_zval_ptr(&opline->op2, EX(Ts), &free_op2, \\1)", - "TMP" => "_get_zval_ptr_tmp(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", - "VAR" => "_get_zval_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", - "CONST" => "&opline->op2.u.constant", + "ANY" => "get_obj_zval_ptr(opline->op2_type, &opline->op2, EX_Ts(), &free_op2, \\1)", + "TMP" => "_get_zval_ptr_tmp(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", + "CONST" => "opline->op2.zv", "UNUSED" => "_get_obj_zval_ptr_unused(TSRMLS_C)", - "CV" => "_get_zval_ptr_cv(&opline->op2, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_cv_\\1(EX_CVs(), opline->op2.var TSRMLS_CC)", ); $op1_get_obj_zval_ptr_ptr = array( - "ANY" => "get_obj_zval_ptr_ptr(&opline->op1, EX(Ts), &free_op1, \\1)", + "ANY" => "get_obj_zval_ptr_ptr(opline->op1_type, &opline->op1, EX_Ts(), &free_op1, \\1)", "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC)", "CONST" => "NULL", "UNUSED" => "_get_obj_zval_ptr_ptr_unused(TSRMLS_C)", - "CV" => "_get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_ptr_cv_\\1(EX_CVs(), opline->op1.var TSRMLS_CC)", ); $op2_get_obj_zval_ptr_ptr = array( - "ANY" => "get_obj_zval_ptr_ptr(&opline->op2, EX(Ts), &free_op2, \\1)", + "ANY" => "get_obj_zval_ptr_ptr(opline->op2_type, &opline->op2, EX_Ts(), &free_op2, \\1)", "TMP" => "NULL", - "VAR" => "_get_zval_ptr_ptr_var(&opline->op2, EX(Ts), &free_op2 TSRMLS_CC)", + "VAR" => "_get_zval_ptr_ptr_var(opline->op2.var, EX_Ts(), &free_op2 TSRMLS_CC)", "CONST" => "NULL", "UNUSED" => "_get_obj_zval_ptr_ptr_unused(TSRMLS_C)", - "CV" => "_get_zval_ptr_ptr_cv(&opline->op2, EX(Ts), \\1 TSRMLS_CC)", + "CV" => "_get_zval_ptr_ptr_cv_\\1(EX_CVs(), opline->op2.var TSRMLS_CC)", ); $op1_is_tmp_free = array( @@ -504,7 +504,7 @@ } break; case ZEND_VM_KIND_GOTO: - out($f,$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER:\n"); + out($f,$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER: ZEND_VM_GUARD(".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].");\n"); break; } @@ -694,7 +694,7 @@ $done = 1; out($f,"static int ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n"); out($f,"{\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); out($f,"}\n\n"); } } @@ -768,11 +768,11 @@ break; case ZEND_VM_KIND_SWITCH: out($f,"default:\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); break; case ZEND_VM_KIND_GOTO: out($f,"ZEND_NULL_HANDLER:\n"); - out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n"); + out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n"); break; } } @@ -800,18 +800,60 @@ out($f,"static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op);\n\n"); switch ($kind) { case ZEND_VM_KIND_CALL: - out($f,"\n"); - out($f,"#define ZEND_VM_CONTINUE() return 0\n"); - out($f,"#define ZEND_VM_RETURN() return 1\n"); - out($f,"#define ZEND_VM_ENTER() return 2\n"); - out($f,"#define ZEND_VM_LEAVE() return 3\n"); + out($f,"\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#define OPLINE EX(opline)\n"); + out($f,"#define DCL_OPLINE\n"); + out($f,"#define USE_OPLINE zend_op *opline = EX(opline);\n"); + out($f,"#define LOAD_OPLINE()\n"); + out($f,"#define SAVE_OPLINE()\n"); + out($f,"#undef CHECK_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); + out($f,"#define LOAD_REGS()\n"); + out($f,"#define ZEND_VM_CONTINUE() return 0\n"); + out($f,"#define ZEND_VM_RETURN() return 1\n"); + out($f,"#define ZEND_VM_ENTER() return 2\n"); + out($f,"#define ZEND_VM_LEAVE() return 3\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n"); out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n"); out($f,"#undef EX\n"); out($f,"#define EX(element) execute_data->element\n\n"); + out($f,"#undef EX_CV\n"); + out($f,"#define EX_CV(var) EX(CVs)[var]\n"); + out($f,"#undef EX_CVs\n"); + out($f,"#define EX_CVs() EX(CVs)\n"); + out($f,"#undef EX_T\n"); + out($f,"#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))\n"); + out($f,"#undef EX_Ts\n"); + out($f,"#define EX_Ts() EX(Ts)\n\n"); break; case ZEND_VM_KIND_SWITCH: out($f,"\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#define OPLINE opline\n"); + out($f,"#define DCL_OPLINE zend_op *opline;\n"); + out($f,"#define USE_OPLINE\n"); + out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"#undef CHECK_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); + out($f,"#define LOAD_REGS() do {Ts = EX(Ts); CVs = EX(CVs);} while (0)\n"); out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); out($f,"#define ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n"); out($f,"#define ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n"); @@ -820,10 +862,35 @@ out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n"); out($f,"#undef EX\n"); out($f,"#define EX(element) execute_data->element\n\n"); + out($f,"#undef EX_CV\n"); + out($f,"#define EX_CV(var) CVs[var]\n"); + out($f,"#undef EX_CVs\n"); + out($f,"#define EX_CVs() CVs\n"); + out($f,"#undef EX_T\n"); + out($f,"#define EX_T(offset) T(offset)\n"); + out($f,"#undef EX_Ts\n"); + out($f,"#define EX_Ts() Ts\n\n"); break; case ZEND_VM_KIND_GOTO: out($f,"\n"); - out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n"); + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#define OPLINE opline\n"); + out($f,"#define DCL_OPLINE zend_op *opline;\n"); + out($f,"#define USE_OPLINE\n"); + out($f,"#define LOAD_OPLINE() opline = EX(opline)\n"); + out($f,"#define SAVE_OPLINE() EX(opline) = opline\n"); + out($f,"#undef CHECK_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define CHECK_EXCEPTION() if (UNEXPECTED(EG(exception) != NULL)) goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); + out($f,"#define HANDLE_EXCEPTION() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() goto ZEND_HANDLE_EXCEPTION_SPEC_HANDLER\n"); + out($f,"#define LOAD_REGS() do {Ts = EX(Ts); CVs = EX(CVs);} while (0)\n"); + out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); out($f,"#define ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n"); out($f,"#define ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); @@ -831,6 +898,14 @@ out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n"); out($f,"#undef EX\n"); out($f,"#define EX(element) execute_data->element\n\n"); + out($f,"#undef EX_CV\n"); + out($f,"#define EX_CV(var) CVs[var]\n"); + out($f,"#undef EX_CVs\n"); + out($f,"#define EX_CVs() CVs\n"); + out($f,"#undef EX_T\n"); + out($f,"#define EX_T(offset) T(offset)\n\n"); + out($f,"#undef EX_Ts\n"); + out($f,"#define EX_Ts() Ts\n\n"); break; } break; @@ -839,6 +914,8 @@ break; case "HELPER_VARS": if ($kind != ZEND_VM_KIND_CALL) { + out($f,$m[1]."temp_variable *Ts;\n"); + out($f,$m[1]."zval ***CVs;\n"); if ($kind == ZEND_VM_KIND_SWITCH) { out($f,$m[1]."opcode_handler_t dispatch_handler;\n"); } @@ -881,13 +958,13 @@ // Emit code that dispatches to opcode handler switch ($kind) { case ZEND_VM_KIND_CALL: - out($f, $m[1]."if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0)".$m[3]."\n"); + out($f, $m[1]."if ((ret = OPLINE->handler(execute_data TSRMLS_CC)) > 0)".$m[3]."\n"); break; case ZEND_VM_KIND_SWITCH: - out($f, $m[1]."dispatch_handler = EX(opline)->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)dispatch_handler)".$m[3]."\n"); + out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)dispatch_handler)".$m[3]."\n"); break; case ZEND_VM_KIND_GOTO: - out($f, $m[1]."goto *(void**)(EX(opline)->handler);".$m[3]."\n"); + out($f, $m[1]."goto *(void**)(OPLINE->handler);".$m[3]."\n"); break; } break; @@ -1146,6 +1223,12 @@ out($f,"\n/* Old executor */\n\n"); out($f,"#undef EX\n"); out($f,"#define EX(element) execute_data.element\n\n"); + out($f,"#undef EX_CV\n"); + out($f,"#define EX_CV(var) EX(CVs)[var]\n"); + out($f,"#undef EX_CVs\n"); + out($f,"#define EX_CVs() EX(CVs)\n"); + out($f,"#undef EX_T\n"); + out($f,"#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))\n\n"); out($f,"#undef ZEND_VM_CONTINUE\n\n"); out($f,"#undef ZEND_VM_RETURN\n\n"); out($f,"#undef ZEND_VM_ENTER\n\n"); @@ -1185,7 +1268,7 @@ out($f, "\t\t\t_UNUSED_CODE, /* 15 */\n"); out($f, "\t\t\t_CV_CODE /* 16 = IS_CV */\n"); out($f, "\t\t};\n"); - out($f, "\t\treturn zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1.op_type] * 5 + zend_vm_decode[op->op2.op_type]];\n"); + out($f, "\t\treturn zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type]];\n"); if (ZEND_VM_OLD_EXECUTOR) { out($f, "\t}\n"); } @@ -1202,8 +1285,30 @@ if (count($export) > 0 && !ZEND_VM_OLD_EXECUTOR && ZEND_VM_KIND != ZEND_VM_KIND_CALL) { + out($f,"#undef OPLINE\n"); + out($f,"#undef DCL_OPLINE\n"); + out($f,"#undef USE_OPLINE\n"); + out($f,"#undef LOAD_OPLINE\n"); + out($f,"#undef SAVE_OPLINE\n"); + out($f,"#define OPLINE EX(opline)\n"); + out($f,"#define DCL_OPLINE\n"); + out($f,"#define USE_OPLINE zend_op *opline = EX(opline);\n"); + out($f,"#define LOAD_OPLINE()\n"); + out($f,"#define SAVE_OPLINE()\n"); + out($f,"#undef CHECK_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION\n"); + out($f,"#undef HANDLE_EXCEPTION_LEAVE\n"); + out($f,"#define CHECK_EXCEPTION() LOAD_OPLINE()\n"); + out($f,"#define HANDLE_EXCEPTION() LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); + out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#undef EX\n"); out($f,"#define EX(element) execute_data->element\n\n"); + out($f,"#undef EX_CV\n"); + out($f,"#define EX_CV(var) EX(CVs)[var]\n"); + out($f,"#undef EX_CVs\n"); + out($f,"#define EX_CVs() EX(CVs)\n"); + out($f,"#undef EX_T\n"); + out($f,"#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))\n\n"); out($f,"#undef ZEND_VM_CONTINUE\n"); out($f,"#undef ZEND_VM_RETURN\n"); out($f,"#undef ZEND_VM_ENTER\n"); Index: Zend/Zend.dsp =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: Zend/zend_language_parser.y =================================================================== --- Zend/zend_language_parser.y (revision 297868) +++ Zend/zend_language_parser.y (working copy) @@ -219,12 +219,12 @@ '{' inner_statement_list '}' | T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } statement { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); } | T_IF '(' expr ')' ':' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); } - | T_WHILE '(' { $1.u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { zend_do_while_cond(&$4, &$5 TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$5 TSRMLS_CC); } - | T_DO { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE '(' { $5.u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(&$1, &$5, &$7 TSRMLS_CC); } + | T_WHILE '(' { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { zend_do_while_cond(&$4, &$5 TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$5 TSRMLS_CC); } + | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE '(' { $5.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(&$1, &$5, &$7 TSRMLS_CC); } | T_FOR '(' for_expr - ';' { zend_do_free(&$3 TSRMLS_CC); $4.u.opline_num = get_next_op_number(CG(active_op_array)); } + ';' { zend_do_free(&$3 TSRMLS_CC); $4.u.op.opline_num = get_next_op_number(CG(active_op_array)); } for_expr ';' { zend_do_extended_info(TSRMLS_C); zend_do_for_cond(&$6, &$7 TSRMLS_CC); } for_expr @@ -252,7 +252,7 @@ { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); } variable foreach_optional_arg ')' { zend_check_writable_variable(&$6); zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); } foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); } - | T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } + | T_DECLARE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } | ';' /* empty statement */ | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); } @@ -267,7 +267,7 @@ additional_catches: non_empty_additional_catches { $$ = $1; } - | /* empty */ { $$.u.opline_num = -1; } + | /* empty */ { $$.u.op.opline_num = -1; } ; non_empty_additional_catches: @@ -277,7 +277,7 @@ additional_catch: - T_CATCH '(' fully_qualified_class_name { $$.u.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + T_CATCH '(' fully_qualified_class_name { $$.u.op.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } ; @@ -327,9 +327,9 @@ class_entry_type: - T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; } - | T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } - | T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; } + T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = 0; } + | T_ABSTRACT T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } + | T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; } ; extends_from: @@ -338,7 +338,7 @@ ; interface_entry: - T_INTERFACE { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_INTERFACE; } + T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; } ; interface_extends_list: @@ -364,7 +364,7 @@ foreach_variable: variable { zend_check_writable_variable(&$1); $$ = $1; } - | '&' variable { zend_check_writable_variable(&$2); $$ = $2; $$.u.EA.type |= ZEND_PARSED_REFERENCE_VARIABLE; } + | '&' variable { zend_check_writable_variable(&$2); $$ = $2; $$.EA |= ZEND_PARSED_REFERENCE_VARIABLE; } ; for_statement: @@ -450,14 +450,14 @@ non_empty_parameter_list: - optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; Z_LVAL($$.u.constant)=1; Z_TYPE($$.u.constant)=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, &$2, 0 TSRMLS_CC); } - | optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; Z_LVAL($$.u.constant)=1; Z_TYPE($$.u.constant)=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, &$3, 1 TSRMLS_CC); } - | optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$3, 0 TSRMLS_CC); $$.op_type = IS_CONST; Z_LVAL($$.u.constant)=1; Z_TYPE($$.u.constant)=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$5, &$1, &$3, 1 TSRMLS_CC); } - | optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$2, 0 TSRMLS_CC); $$.op_type = IS_CONST; Z_LVAL($$.u.constant)=1; Z_TYPE($$.u.constant)=IS_LONG; INIT_PZVAL(&$$.u.constant); zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$4, &$1, &$2, 0 TSRMLS_CC); } - | non_empty_parameter_list ',' optional_class_type T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; Z_LVAL($$.u.constant)++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, &$4, 0 TSRMLS_CC); } - | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; Z_LVAL($$.u.constant)++; zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$3, &$5, 1 TSRMLS_CC); } - | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$5, 0 TSRMLS_CC); $$=$1; Z_LVAL($$.u.constant)++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$7, &$3, &$5, 1 TSRMLS_CC); } - | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { znode tmp; fetch_simple_variable(&tmp, &$4, 0 TSRMLS_CC); $$=$1; Z_LVAL($$.u.constant)++; zend_do_receive_arg(ZEND_RECV_INIT, &tmp, &$$, &$6, &$3, &$4, 0 TSRMLS_CC); } + optional_class_type T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$2, &$$, NULL, &$1, 0 TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$1, 1 TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$3, &$$, &$5, &$1, 1 TSRMLS_CC); } + | optional_class_type T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$2, &$$, &$4, &$1, 0 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$3, 0 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$5, &$$, NULL, &$3, 1 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$5, &$$, &$7, &$3, 1 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$3, 0 TSRMLS_CC); } ; @@ -580,7 +580,7 @@ T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } - | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.u.EA.type = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } + | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); } @@ -652,7 +652,7 @@ ; function: - T_FUNCTION { $$.u.opline_num = CG(zend_lineno); } + T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); } ; lexical_vars: @@ -668,18 +668,18 @@ ; function_call: - namespace_name '(' { $2.u.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } + namespace_name '(' { $2.u.op.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } function_call_parameter_list - ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } - | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $4.u.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); } + ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $4.u.op.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); } function_call_parameter_list - ')' { zend_do_end_function_call(&$1, &$$, &$6, 0, $4.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } - | T_NS_SEPARATOR namespace_name '(' { $3.u.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } + ')' { zend_do_end_function_call(&$1, &$$, &$6, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_NS_SEPARATOR namespace_name '(' { $3.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } function_call_parameter_list - ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } - | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $4.u.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $4.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list - ')' { zend_do_end_function_call($4.u.opline_num?NULL:&$3, &$$, &$6, $4.u.opline_num, $4.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + ')' { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, &$6, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} @@ -717,8 +717,8 @@ dynamic_class_name_reference: base_variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } - object_property { zend_do_push_object(&$4 TSRMLS_CC); zend_do_declare_implicit_property(TSRMLS_C); } dynamic_class_name_variable_properties - { zend_do_pop_object(&$$ TSRMLS_CC); $$.u.EA.type = ZEND_PARSED_MEMBER; } + object_property { zend_do_push_object(&$4 TSRMLS_CC); } dynamic_class_name_variable_properties + { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } | base_variable { $$ = $1; } ; @@ -730,7 +730,7 @@ dynamic_class_name_variable_property: - T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); zend_do_declare_implicit_property(TSRMLS_C); } + T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } ; exit_expr: @@ -836,26 +836,26 @@ variable: base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties - { zend_do_pop_object(&$$ TSRMLS_CC); $$.u.EA.type = $1.u.EA.type | ($7.u.EA.type ? $7.u.EA.type : $6.u.EA.type); } + { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); } | base_variable_with_function_calls { $$ = $1; } ; variable_properties: - variable_properties variable_property { $$.u.EA.type = $2.u.EA.type; } - | /* empty */ { $$.u.EA.type = 0; } + variable_properties variable_property { $$.EA = $2.EA; } + | /* empty */ { $$.EA = 0; } ; variable_property: - T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.u.EA.type = $4.u.EA.type; } + T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.EA = $4.EA; } ; method_or_not: '(' { zend_do_pop_object(&$1 TSRMLS_CC); zend_do_begin_method_call(&$1 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(&$1, &$$, &$3, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); - zend_do_push_object(&$$ TSRMLS_CC); $$.u.EA.type = ZEND_PARSED_METHOD_CALL; } - | /* empty */ { zend_do_declare_implicit_property(TSRMLS_C); $$.u.EA.type = ZEND_PARSED_MEMBER; } + zend_do_push_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_METHOD_CALL; } + | /* empty */ { $$.EA = ZEND_PARSED_MEMBER; } ; variable_without_objects: @@ -875,14 +875,14 @@ base_variable_with_function_calls: base_variable { $$ = $1; } - | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.u.EA.type = ZEND_PARSED_FUNCTION_CALL; } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } ; base_variable: - reference_variable { $$ = $1; $$.u.EA.type = ZEND_PARSED_VARIABLE; } - | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); $$.u.EA.type = ZEND_PARSED_VARIABLE; } - | static_member { $$ = $1; $$.u.EA.type = ZEND_PARSED_STATIC_MEMBER; } + reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } + | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } ; reference_variable: Index: Zend/zend_globals.h =================================================================== --- Zend/zend_globals.h (revision 297868) +++ Zend/zend_globals.h (working copy) @@ -140,6 +140,18 @@ HashTable *labels; zend_stack labels_stack; + /* interned strings */ + char *interned_strings_start; + char *interned_strings_end; + char *interned_strings_top; + char *interned_strings_snapshot_top; + + HashTable interned_strings; + + char *(*new_interned_string)(char *str, int len, int free_src TSRMLS_DC); + void (*interned_strings_snapshot)(TSRMLS_D); + void (*interned_strings_restore)(TSRMLS_D); + #ifdef ZEND_MULTIBYTE zend_encoding **script_encoding_list; size_t script_encoding_list_size; Index: Zend/zend_execute_API.c =================================================================== --- Zend/zend_execute_API.c (revision 297868) +++ Zend/zend_execute_API.c (working copy) @@ -525,7 +525,9 @@ Z_STRLEN_P(p) -= ((colon - Z_STRVAL_P(p)) + 1); if (inline_change) { colon = estrndup(colon, Z_STRLEN_P(p)); - efree(Z_STRVAL_P(p)); + if (!IS_INTERNED(Z_STRVAL_P(p))) { + efree(Z_STRVAL_P(p)); + } Z_STRVAL_P(p) = colon; } else { Z_STRVAL_P(p) = colon + 1; @@ -561,12 +563,12 @@ if (fix_save) { save--; } - if (inline_change) { + if (inline_change && !IS_INTERNED(save)) { efree(save); } save = NULL; } - if (inline_change && save && save != actual) { + if (inline_change && save && save != actual && !IS_INTERNED(save)) { efree(save); } zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); @@ -1023,7 +1025,7 @@ } /* }}} */ -ZEND_API int zend_lookup_class_ex(const char *name, int name_length, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ +ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ { zval **args[1]; zval autoload_function; @@ -1038,23 +1040,31 @@ ulong hash; ALLOCA_FLAG(use_heap) - if (name == NULL || !name_length) { - return FAILURE; - } + if (key) { + lc_name = Z_STRVAL(key->constant); + lc_length = Z_STRLEN(key->constant) + 1; + hash = key->hash_value; + } else { + if (name == NULL || !name_length) { + return FAILURE; + } - lc_free = lc_name = do_alloca(name_length + 1, use_heap); - zend_str_tolower_copy(lc_name, name, name_length); - lc_length = name_length + 1; + lc_free = lc_name = do_alloca(name_length + 1, use_heap); + zend_str_tolower_copy(lc_name, name, name_length); + lc_length = name_length + 1; - if (lc_name[0] == '\\') { - lc_name += 1; - lc_length -= 1; + if (lc_name[0] == '\\') { + lc_name += 1; + lc_length -= 1; + } + + hash = zend_inline_hash_func(lc_name, lc_length); } - hash = zend_inline_hash_func(lc_name, lc_length); - if (zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) { - free_alloca(lc_free, use_heap); + if (!key) { + free_alloca(lc_free, use_heap); + } return SUCCESS; } @@ -1062,7 +1072,9 @@ * (doesn't impact fuctionality of __autoload() */ if (!use_autoload || zend_is_compiling(TSRMLS_C)) { - free_alloca(lc_free, use_heap); + if (!key) { + free_alloca(lc_free, use_heap); + } return FAILURE; } @@ -1072,7 +1084,9 @@ } if (zend_hash_quick_add(EG(in_autoload), lc_name, lc_length, hash, (void**)&dummy, sizeof(char), NULL) == FAILURE) { - free_alloca(lc_free, use_heap); + if (!key) { + free_alloca(lc_free, use_heap); + } return FAILURE; } @@ -1118,20 +1132,19 @@ zval_ptr_dtor(&retval_ptr); } - if (retval == FAILURE) { + if (retval == SUCCESS) { + retval = zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce); + } + if (!key) { free_alloca(lc_free, use_heap); - return FAILURE; } - - retval = zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce); - free_alloca(lc_free, use_heap); return retval; } /* }}} */ ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) /* {{{ */ { - return zend_lookup_class_ex(name, name_length, 1, ce TSRMLS_CC); + return zend_lookup_class_ex(name, name_length, NULL, 1, ce TSRMLS_CC); } /* }}} */ @@ -1249,8 +1262,8 @@ ret_opline = get_next_op(CG(active_op_array) TSRMLS_CC); ret_opline->opcode = ZEND_RETURN; - ret_opline->op1.op_type = IS_CONST; - INIT_ZVAL(ret_opline->op1.u.constant); + ret_opline->op1_type = IS_CONST; + ret_opline->op1.constant = zend_add_literal(CG(active_op_array), &EG(uninitialized_zval)); SET_UNUSED(ret_opline->op2); if (!CG(active_op_array)->start_op) { @@ -1261,29 +1274,27 @@ end=CG(active_op_array)->opcodes+CG(active_op_array)->last; while (oplineop1.op_type == IS_CONST) { - Z_SET_ISREF(opline->op1.u.constant); - Z_SET_REFCOUNT(opline->op1.u.constant, 2); /* Make sure is_ref won't be reset */ + if (opline->op1_type == IS_CONST) { + opline->op1.zv = &CG(active_op_array)->literals[opline->op1.constant].constant; } - if (opline->op2.op_type == IS_CONST) { - Z_SET_ISREF(opline->op2.u.constant); - Z_SET_REFCOUNT(opline->op2.u.constant, 2); + if (opline->op2_type == IS_CONST) { + opline->op2.zv = &CG(active_op_array)->literals[opline->op2.constant].constant; } switch (opline->opcode) { case ZEND_GOTO: - if (Z_TYPE(opline->op2.u.constant) != IS_LONG) { + if (Z_TYPE_P(opline->op2.zv) != IS_LONG) { zend_resolve_goto_label(CG(active_op_array), opline, 1 TSRMLS_CC); } /* break omitted intentionally */ case ZEND_JMP: - opline->op1.u.jmp_addr = &CG(active_op_array)->opcodes[opline->op1.u.opline_num]; + opline->op1.jmp_addr = &CG(active_op_array)->opcodes[opline->op1.opline_num]; break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_JMP_SET: - opline->op2.u.jmp_addr = &CG(active_op_array)->opcodes[opline->op2.u.opline_num]; + opline->op2.jmp_addr = &CG(active_op_array)->opcodes[opline->op2.opline_num]; break; } ZEND_VM_SET_OPCODE_HANDLER(opline); @@ -1547,7 +1558,7 @@ break; } - if (zend_lookup_class_ex(class_name, class_name_len, use_autoload, &pce TSRMLS_CC) == FAILURE) { + if (zend_lookup_class_ex(class_name, class_name_len, NULL, use_autoload, &pce TSRMLS_CC) == FAILURE) { if (use_autoload) { if (!silent && !EG(exception)) { if (fetch_type == ZEND_FETCH_CLASS_INTERFACE) { @@ -1563,6 +1574,27 @@ } /* }}} */ +zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC) /* {{{ */ +{ + zend_class_entry **pce; + int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0; + + if (zend_lookup_class_ex(class_name, class_name_len, key, use_autoload, &pce TSRMLS_CC) == FAILURE) { + if (use_autoload) { + if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) { + if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) { + zend_error(E_ERROR, "Interface '%s' not found", class_name); + } else { + zend_error(E_ERROR, "Class '%s' not found", class_name); + } + } + } + return NULL; + } + return *pce; +} +/* }}} */ + #define MAX_ABSTRACT_INFO_CNT 3 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" #define DISPLAY_ABSTRACT_FN(idx) \ @@ -1635,12 +1667,34 @@ } /* }}} */ -ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC) /* {{{ */ +ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, char *name, int name_len, ulong hash_value TSRMLS_DC) /* {{{ */ { + if (zend_hash_quick_del(ht, name, name_len, hash_value) == SUCCESS) { + name_len--; + while (ex && ex->symbol_table == ht) { + int i; + + if (ex->op_array) { + for (i = 0; i < ex->op_array->last_var; i++) { + if (ex->op_array->vars[i].hash_value == hash_value && + ex->op_array->vars[i].name_len == name_len && + !memcmp(ex->op_array->vars[i].name, name, name_len)) { + ex->CVs[i] = NULL; + break; + } + } + } + ex = ex->prev_execute_data; + } + } +} +/* }}} */ + +ZEND_API int zend_delete_global_variable_ex(char *name, int name_len, ulong hash_value TSRMLS_DC) /* {{{ */ +{ zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(name, name_len + 1); - if (zend_hash_quick_exists(&EG(symbol_table), name, name_len + 1, hash_value)) { + if (zend_hash_quick_del(&EG(symbol_table), name, name_len + 1, hash_value) == SUCCESS) { for (ex = EG(current_execute_data); ex; ex = ex->prev_execute_data) { if (ex->op_array && ex->symbol_table == &EG(symbol_table)) { int i; @@ -1655,12 +1709,18 @@ } } } - return zend_hash_quick_del(&EG(symbol_table), name, name_len + 1, hash_value); + return SUCCESS; } return FAILURE; } /* }}} */ +ZEND_API int zend_delete_global_variable(char *name, int name_len TSRMLS_DC) /* {{{ */ +{ + return zend_delete_global_variable_ex(name, name_len, zend_inline_hash_func(name, name_len + 1) TSRMLS_CC); +} +/* }}} */ + ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ { zend_uint i; @@ -1684,7 +1744,7 @@ EG(active_symbol_table) = *(EG(symtable_cache_ptr)--); } else { ALLOC_HASHTABLE(EG(active_symbol_table)); - zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(EG(active_symbol_table), ex->op_array->last_var, NULL, ZVAL_PTR_DTOR, 0); /*printf("Cache miss! Initialized %x\n", EG(active_symbol_table));*/ } ex->symbol_table = EG(active_symbol_table); Index: Zend/zend_vm_def.h =================================================================== --- Zend/zend_vm_def.h (revision 297868) +++ Zend/zend_vm_def.h (working copy) @@ -27,299 +27,337 @@ ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - add_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + add_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(2, ZEND_SUB, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - sub_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + sub_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(3, ZEND_MUL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - mul_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + mul_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(4, ZEND_DIV, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - div_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + div_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(5, ZEND_MOD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - mod_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + mod_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(6, ZEND_SL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - shift_left_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + shift_left_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(7, ZEND_SR, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - shift_right_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + shift_right_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - concat_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + concat_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(15, ZEND_IS_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - is_identical_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + is_identical_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(16, ZEND_IS_NOT_IDENTICAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); is_identical_function(result, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); Z_LVAL_P(result) = !Z_LVAL_P(result); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(17, ZEND_IS_EQUAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); compare_function(result, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); ZVAL_BOOL(result, (Z_LVAL_P(result) == 0)); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(18, ZEND_IS_NOT_EQUAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); compare_function(result, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); ZVAL_BOOL(result, (Z_LVAL_P(result) != 0)); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(19, ZEND_IS_SMALLER, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); compare_function(result, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); ZVAL_BOOL(result, (Z_LVAL_P(result) < 0)); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(20, ZEND_IS_SMALLER_OR_EQUAL, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); compare_function(result, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0)); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(9, ZEND_BW_OR, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - bitwise_or_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + bitwise_or_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(10, ZEND_BW_AND, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - bitwise_and_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + bitwise_and_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(11, ZEND_BW_XOR, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - bitwise_xor_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + bitwise_xor_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(14, ZEND_BOOL_XOR, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - boolean_xor_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + boolean_xor_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(12, ZEND_BW_NOT, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - bitwise_not_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + bitwise_not_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(13, ZEND_BOOL_NOT, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - boolean_not_function(&EX_T(opline->result.u.var).tmp_var, + SAVE_OPLINE(); + boolean_not_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) { - zend_op *opline = EX(opline); - zend_op *op_data = opline+1; + USE_OPLINE zend_free_op free_op1, free_op2, free_op_data1; zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); zval *object; zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval *value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R); - znode *result = &opline->result; + zval *value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, EX_Ts(), &free_op_data1, BP_VAR_R); + znode_op *result = &opline->result; int have_get_ptr = 0; - if (OP1_TYPE == IS_VAR && !object_ptr) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - EX_T(result->u.var).var.ptr_ptr = NULL; make_real_object(object_ptr TSRMLS_CC); object = *object_ptr; - if (Z_TYPE_P(object) != IS_OBJECT) { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { zend_error(E_WARNING, "Attempt to assign property of non-object"); FREE_OP2(); FREE_OP(free_op_data1); - if (!RETURN_VALUE_UNUSED(result)) { - EX_T(result->u.var).var.ptr = EG(uninitialized_zval_ptr); - EX_T(result->u.var).var.ptr_ptr = NULL; - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + EX_T(opline->result.var).var.ptr_ptr = NULL; } } else { /* here we are sure we are dealing with an object */ @@ -330,16 +368,16 @@ /* here property is a string */ if (opline->extended_value == ZEND_ASSIGN_OBJ && Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property TSRMLS_CC); + zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); if (zptr != NULL) { /* NULL means no success in getting PTR */ SEPARATE_ZVAL_IF_NOT_REF(zptr); have_get_ptr = 1; binary_op(*zptr, *zptr, value TSRMLS_CC); - if (!RETURN_VALUE_UNUSED(result)) { - EX_T(result->u.var).var.ptr = *zptr; - EX_T(result->u.var).var.ptr_ptr = NULL; + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(*zptr); + EX_T(opline->result.var).var.ptr = *zptr; + EX_T(opline->result.var).var.ptr_ptr = NULL; } } } @@ -349,7 +387,7 @@ if (opline->extended_value == ZEND_ASSIGN_OBJ) { if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R TSRMLS_CC); + z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); } } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { if (Z_OBJ_HT_P(object)->read_dimension) { @@ -371,22 +409,22 @@ SEPARATE_ZVAL_IF_NOT_REF(&z); binary_op(z, z, value TSRMLS_CC); if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); + Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); } - if (!RETURN_VALUE_UNUSED(result)) { - EX_T(result->u.var).var.ptr = z; - EX_T(result->u.var).var.ptr_ptr = NULL; + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(z); + EX_T(opline->result.var).var.ptr = z; + EX_T(opline->result.var).var.ptr_ptr = NULL; } zval_ptr_dtor(&z); } else { zend_error(E_WARNING, "Attempt to assign property of non-object"); - if (!RETURN_VALUE_UNUSED(result)) { - EX_T(result->u.var).var.ptr = EG(uninitialized_zval_ptr); - EX_T(result->u.var).var.ptr_ptr = NULL; - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + EX_T(opline->result.var).var.ptr_ptr = NULL; } } } @@ -401,17 +439,19 @@ FREE_OP1_VAR_PTR(); /* assign_obj has two opcodes! */ + CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HELPER_EX(zend_binary_assign_op_helper, VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2, free_op_data2, free_op_data1; zval **var_ptr; zval *value; + SAVE_OPLINE(); switch (opline->extended_value) { case ZEND_ASSIGN_OBJ: ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op); @@ -419,21 +459,19 @@ case ZEND_ASSIGN_DIM: { zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); - } else if (Z_TYPE_PP(container) == IS_OBJECT) { + } else if (UNEXPECTED(Z_TYPE_PP(container) == IS_OBJECT)) { if (OP1_TYPE == IS_VAR && !OP1_FREE) { Z_ADDREF_PP(container); /* undo the effect of get_obj_zval_ptr_ptr() */ } ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op); } else { - zend_op *op_data = opline+1; zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_RW TSRMLS_CC); - value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R); - var_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC); - ZEND_VM_INC_OPCODE(); + zend_fetch_dimension_address(&EX_T((opline+1)->op2.var), container, dim, OP2_TYPE, BP_VAR_RW TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, EX_Ts(), &free_op_data1, BP_VAR_R); + var_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, EX_Ts(), &free_op_data2 TSRMLS_CC); } } break; @@ -444,23 +482,28 @@ break; } - if (!var_ptr) { + if (UNEXPECTED(var_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - if (*var_ptr == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + if (UNEXPECTED(*var_ptr == &EG(error_zval))) { + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } FREE_OP2(); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); + if (opline->extended_value == ZEND_ASSIGN_DIM) { + ZEND_VM_INC_OPCODE(); + } ZEND_VM_NEXT_OPCODE(); } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); - if(Z_TYPE_PP(var_ptr) == IS_OBJECT && Z_OBJ_HANDLER_PP(var_ptr, get) + if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT) + && Z_OBJ_HANDLER_PP(var_ptr, get) && Z_OBJ_HANDLER_PP(var_ptr, set)) { /* proxy object */ zval *objval = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC); @@ -472,17 +515,22 @@ binary_op(*var_ptr, *var_ptr, value TSRMLS_CC); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr); + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(*var_ptr); + AI_SET_PTR(&EX_T(opline->result.var), *var_ptr); } FREE_OP2(); if (opline->extended_value == ZEND_ASSIGN_DIM) { FREE_OP(free_op_data1); FREE_OP_VAR_PTR(free_op_data2); + FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); + ZEND_VM_INC_OPCODE(); + } else { + FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); } - FREE_OP1_VAR_PTR(); ZEND_VM_NEXT_OPCODE(); } @@ -543,29 +591,35 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV, incdec_t incdec_op) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + zval **object_ptr; zval *object; - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **retval = &EX_T(opline->result.u.var).var.ptr; + zval *property; + zval **retval; int have_get_ptr = 0; - if (OP1_TYPE == IS_VAR && !object_ptr) { + SAVE_OPLINE(); + object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + retval = &EX_T(opline->result.var).var.ptr; + + if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } make_real_object(object_ptr TSRMLS_CC); /* this should modify object only if it's empty */ object = *object_ptr; - if (Z_TYPE_P(object) != IS_OBJECT) { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); FREE_OP2(); - if (!RETURN_VALUE_UNUSED(&opline->result)) { - *retval = EG(uninitialized_zval_ptr); - PZVAL_LOCK(*retval); + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + *retval = &EG(uninitialized_zval); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -576,13 +630,13 @@ } if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property TSRMLS_CC); + zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); if (zptr != NULL) { /* NULL means no success in getting PTR */ SEPARATE_ZVAL_IF_NOT_REF(zptr); have_get_ptr = 1; incdec_op(*zptr); - if (!RETURN_VALUE_UNUSED(&opline->result)) { + if (RETURN_VALUE_USED(opline)) { *retval = *zptr; PZVAL_LOCK(*retval); } @@ -591,9 +645,9 @@ if (!have_get_ptr) { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { - zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R TSRMLS_CC); + zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); - if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { + if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) { zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { @@ -607,14 +661,14 @@ SEPARATE_ZVAL_IF_NOT_REF(&z); incdec_op(z); *retval = z; - Z_OBJ_HT_P(object)->write_property(object, property, z TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(*retval, &opline->result); + Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + SELECTIVE_PZVAL_LOCK(*retval, opline); zval_ptr_dtor(&z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); - if (!RETURN_VALUE_UNUSED(&opline->result)) { - *retval = EG(uninitialized_zval_ptr); - PZVAL_LOCK(*retval); + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + *retval = &EG(uninitialized_zval); } } } @@ -625,6 +679,7 @@ FREE_OP2(); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -640,26 +695,32 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV, incdec_t incdec_op) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + zval **object_ptr; zval *object; - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval *retval = &EX_T(opline->result.u.var).tmp_var; + zval *property; + zval *retval; int have_get_ptr = 0; - if (OP1_TYPE == IS_VAR && !object_ptr) { + SAVE_OPLINE(); + object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + retval = &EX_T(opline->result.var).tmp_var; + + if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } make_real_object(object_ptr TSRMLS_CC); /* this should modify object only if it's empty */ object = *object_ptr; - if (Z_TYPE_P(object) != IS_OBJECT) { + if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); FREE_OP2(); - *retval = *EG(uninitialized_zval_ptr); + ZVAL_NULL(retval); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -670,12 +731,12 @@ } if (Z_OBJ_HT_P(object)->get_property_ptr_ptr) { - zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property TSRMLS_CC); + zval **zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); if (zptr != NULL) { /* NULL means no success in getting PTR */ have_get_ptr = 1; SEPARATE_ZVAL_IF_NOT_REF(zptr); - *retval = **zptr; + ZVAL_COPY_VALUE(retval, *zptr); zendi_zval_copy_ctor(*retval); incdec_op(*zptr); @@ -685,10 +746,10 @@ if (!have_get_ptr) { if (Z_OBJ_HT_P(object)->read_property && Z_OBJ_HT_P(object)->write_property) { - zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R TSRMLS_CC); + zval *z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); zval *z_copy; - if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { + if (UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && Z_OBJ_HT_P(z)->get) { zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC); if (Z_REFCOUNT_P(z) == 0) { @@ -698,20 +759,19 @@ } z = value; } - *retval = *z; + ZVAL_COPY_VALUE(retval, z); zendi_zval_copy_ctor(*retval); ALLOC_ZVAL(z_copy); - *z_copy = *z; + INIT_PZVAL_COPY(z_copy, z); zendi_zval_copy_ctor(*z_copy); - INIT_PZVAL(z_copy); incdec_op(z_copy); Z_ADDREF_P(z); - Z_OBJ_HT_P(object)->write_property(object, property, z_copy TSRMLS_CC); + Z_OBJ_HT_P(object)->write_property(object, property, z_copy, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); zval_ptr_dtor(&z_copy); zval_ptr_dtor(&z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); - *retval = *EG(uninitialized_zval_ptr); + ZVAL_NULL(retval); } } @@ -721,6 +781,7 @@ FREE_OP2(); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -736,25 +797,30 @@ ZEND_VM_HANDLER(34, ZEND_PRE_INC, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval **var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + zval **var_ptr; - if (OP1_TYPE == IS_VAR && !var_ptr) { + SAVE_OPLINE(); + var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + if (OP1_TYPE == IS_VAR && UNEXPECTED(*var_ptr == &EG(error_zval))) { + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); - if(Z_TYPE_PP(var_ptr) == IS_OBJECT && Z_OBJ_HANDLER_PP(var_ptr, get) + if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT) + && Z_OBJ_HANDLER_PP(var_ptr, get) && Z_OBJ_HANDLER_PP(var_ptr, set)) { /* proxy object */ zval *val = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC); @@ -766,36 +832,42 @@ increment_function(*var_ptr); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr); + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(*var_ptr); + AI_SET_PTR(&EX_T(opline->result.var), *var_ptr); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(35, ZEND_PRE_DEC, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval **var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + zval **var_ptr; - if (OP1_TYPE == IS_VAR && !var_ptr) { + SAVE_OPLINE(); + var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + if (OP1_TYPE == IS_VAR && UNEXPECTED(*var_ptr == &EG(error_zval))) { + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } SEPARATE_ZVAL_IF_NOT_REF(var_ptr); - if(Z_TYPE_PP(var_ptr) == IS_OBJECT && Z_OBJ_HANDLER_PP(var_ptr, get) + if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT) + && Z_OBJ_HANDLER_PP(var_ptr, get) && Z_OBJ_HANDLER_PP(var_ptr, set)) { /* proxy object */ zval *val = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC); @@ -807,38 +879,45 @@ decrement_function(*var_ptr); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, *var_ptr); + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(*var_ptr); + AI_SET_PTR(&EX_T(opline->result.var), *var_ptr); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(36, ZEND_POST_INC, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval **var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + zval **var_ptr, *retval; - if (OP1_TYPE == IS_VAR && !var_ptr) { + SAVE_OPLINE(); + var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - EX_T(opline->result.u.var).tmp_var = *EG(uninitialized_zval_ptr); + if (OP1_TYPE == IS_VAR && UNEXPECTED(*var_ptr == &EG(error_zval))) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(&EX_T(opline->result.var).tmp_var); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX_T(opline->result.u.var).tmp_var = **var_ptr; - zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + retval = &EX_T(opline->result.var).tmp_var; + ZVAL_COPY_VALUE(retval, *var_ptr); + zendi_zval_copy_ctor(*retval); SEPARATE_ZVAL_IF_NOT_REF(var_ptr); - if(Z_TYPE_PP(var_ptr) == IS_OBJECT && Z_OBJ_HANDLER_PP(var_ptr, get) + if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT) + && Z_OBJ_HANDLER_PP(var_ptr, get) && Z_OBJ_HANDLER_PP(var_ptr, set)) { /* proxy object */ zval *val = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC); @@ -851,32 +930,39 @@ } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(37, ZEND_POST_DEC, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval **var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + zval **var_ptr, *retval; - if (OP1_TYPE == IS_VAR && !var_ptr) { + SAVE_OPLINE(); + var_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(var_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets"); } - if (OP1_TYPE == IS_VAR && *var_ptr == EG(error_zval_ptr)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - EX_T(opline->result.u.var).tmp_var = *EG(uninitialized_zval_ptr); + if (OP1_TYPE == IS_VAR && UNEXPECTED(*var_ptr == &EG(error_zval))) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_NULL(&EX_T(opline->result.var).tmp_var); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } - EX_T(opline->result.u.var).tmp_var = **var_ptr; - zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + retval = &EX_T(opline->result.var).tmp_var; + ZVAL_COPY_VALUE(retval, *var_ptr); + zendi_zval_copy_ctor(*retval); SEPARATE_ZVAL_IF_NOT_REF(var_ptr); - if(Z_TYPE_PP(var_ptr) == IS_OBJECT && Z_OBJ_HANDLER_PP(var_ptr, get) + if (UNEXPECTED(Z_TYPE_PP(var_ptr) == IS_OBJECT) + && Z_OBJ_HANDLER_PP(var_ptr, get) && Z_OBJ_HANDLER_PP(var_ptr, set)) { /* proxy object */ zval *val = Z_OBJ_HANDLER_PP(var_ptr, get)(*var_ptr TSRMLS_CC); @@ -889,18 +975,23 @@ } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; zval z_copy; - zval *z = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *z; + SAVE_OPLINE(); + z = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE != IS_CONST && - Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL && + UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && + Z_OBJ_HT_P(z)->get_method != NULL && zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { zend_print_variable(&z_copy); zval_dtor(&z_copy); @@ -909,46 +1000,58 @@ } FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(41, ZEND_PRINT, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = 1; - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_LONG; - + ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1); ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ECHO); } ZEND_VM_HELPER_EX(zend_fetch_var_address_helper, CONST|TMP|VAR|CV, ANY, int type) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *varname = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *varname; zval **retval; zval tmp_varname; HashTable *target_symbol_table; + ulong hash_value; - if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { - tmp_varname = *varname; + SAVE_OPLINE(); + varname = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE != IS_CONST && UNEXPECTED(Z_TYPE_P(varname) != IS_STRING)) { + ZVAL_COPY_VALUE(&tmp_varname, varname); zval_copy_ctor(&tmp_varname); convert_to_string(&tmp_varname); varname = &tmp_varname; } - if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) { - retval = zend_std_get_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), 0 TSRMLS_CC); + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC_MEMBER) { + retval = zend_std_get_static_property(EX_T(opline->op2.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), 0, ((OP1_TYPE == IS_CONST) ? opline->op1.literal : NULL) TSRMLS_CC); FREE_OP1(); } else { - target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), type, varname TSRMLS_CC); + target_symbol_table = zend_get_target_symbol_table(opline->extended_value & ZEND_FETCH_TYPE_MASK TSRMLS_CC); /* if (!target_symbol_table) { + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } */ - if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &retval) == FAILURE) { + if (OP1_TYPE == IS_CONST) { + hash_value = Z_HASH_P(varname); + } else if (IS_INTERNED(Z_STRVAL_P(varname))) { + hash_value = INTERNED_HASH(Z_STRVAL_P(varname)); + } else { + hash_value = zend_hash_func(Z_STRVAL_P(varname), Z_STRLEN_P(varname)+1); + } + + if (zend_hash_quick_find(target_symbol_table, Z_STRVAL_P(varname), Z_STRLEN_P(varname)+1, hash_value, (void **) &retval) == FAILURE) { switch (type) { case BP_VAR_R: case BP_VAR_UNSET: @@ -960,17 +1063,14 @@ case BP_VAR_RW: zend_error(E_NOTICE,"Undefined variable: %s", Z_STRVAL_P(varname)); /* break missing intentionally */ - case BP_VAR_W: { - zval *new_zval = &EG(uninitialized_zval); - - Z_ADDREF_P(new_zval); - zend_hash_update(target_symbol_table, varname->value.str.val, varname->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval); - } + case BP_VAR_W: + Z_ADDREF_P(&EG(uninitialized_zval)); + zend_hash_quick_update(target_symbol_table, Z_STRVAL_P(varname), Z_STRLEN_P(varname)+1, hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **) &retval); break; EMPTY_SWITCH_DEFAULT_CASE() } } - switch (opline->op2.u.EA.type) { + switch (opline->extended_value & ZEND_FETCH_TYPE_MASK) { case ZEND_FETCH_GLOBAL: if (OP1_TYPE != IS_TMP_VAR) { FREE_OP1(); @@ -984,7 +1084,7 @@ break; case ZEND_FETCH_GLOBAL_LOCK: if (OP1_TYPE == IS_VAR && !free_op1.var) { - PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr); + PZVAL_LOCK(*EX_T(opline->op1.var).var.ptr_ptr); } break; } @@ -992,9 +1092,9 @@ if (OP1_TYPE != IS_CONST && varname == &tmp_varname) { - zval_dtor(varname); + zval_dtor(&tmp_varname); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { + if (RETURN_VALUE_USED(opline)) { if (opline->extended_value & ZEND_FETCH_MAKE_REF) { SEPARATE_ZVAL_TO_MAKE_IS_REF(retval); } @@ -1002,25 +1102,25 @@ switch (type) { case BP_VAR_R: case BP_VAR_IS: - AI_SET_PTR(EX_T(opline->result.u.var).var, *retval); + AI_SET_PTR(&EX_T(opline->result.var), *retval); break; case BP_VAR_UNSET: { zend_free_op free_res; - EX_T(opline->result.u.var).var.ptr_ptr = retval; - PZVAL_UNLOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &free_res); - if (EX_T(opline->result.u.var).var.ptr_ptr != &EG(uninitialized_zval_ptr)) { - SEPARATE_ZVAL_IF_NOT_REF(EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_UNLOCK(*retval, &free_res); + if (retval != &EG(uninitialized_zval_ptr)) { + SEPARATE_ZVAL_IF_NOT_REF(retval); } - PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_LOCK(*retval); FREE_OP_VAR_PTR(free_res); - break; + } + /* break missing intentionally */ default: - EX_T(opline->result.u.var).var.ptr_ptr = retval; + EX_T(opline->result.var).var.ptr_ptr = retval; break; - } } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -1041,8 +1141,10 @@ ZEND_VM_HANDLER(92, ZEND_FETCH_FUNC_ARG, CONST|TMP|VAR|CV, ANY) { + USE_OPLINE + ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_var_address_helper, type, - ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), EX(opline)->extended_value)?BP_VAR_W:BP_VAR_R); + ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))?BP_VAR_W:BP_VAR_R); } ZEND_VM_HANDLER(95, ZEND_FETCH_UNSET, CONST|TMP|VAR|CV, ANY) @@ -1057,196 +1159,195 @@ ZEND_VM_HANDLER(81, ZEND_FETCH_DIM_R, VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); zval **container; - if (opline->extended_value == ZEND_FETCH_ADD_LOCK && + SAVE_OPLINE(); + + if ((opline->extended_value & ZEND_FETCH_ADD_LOCK) && OP1_TYPE != IS_CV && - EX_T(opline->op1.u.var).var.ptr_ptr) { - PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr); + EX_T(opline->op1.var).var.ptr_ptr) { + PZVAL_LOCK(*EX_T(opline->op1.var).var.ptr_ptr); } container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address_read(RETURN_VALUE_UNUSED(&opline->result)?NULL:&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_R TSRMLS_CC); + zend_fetch_dimension_address_read(!RETURN_VALUE_USED(opline)?NULL:&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC); FREE_OP2(); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + zval **container; - if (OP1_TYPE == IS_VAR && !container) { + SAVE_OPLINE(); + container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC); + zend_fetch_dimension_address(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_W TSRMLS_CC); FREE_OP2(); - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); /* We are going to assign the result by reference */ - if (opline->extended_value && EX_T(opline->result.u.var).var.ptr_ptr) { - Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); - SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); - Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + if (UNEXPECTED(opline->extended_value != 0)) { + zval **retval_ptr = EX_T(opline->result.var).var.ptr_ptr; + + if (retval_ptr) { + Z_DELREF_PP(retval_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr); + Z_ADDREF_PP(retval_ptr); + } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(87, ZEND_FETCH_DIM_RW, VAR|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + zval **container; - if (OP1_TYPE == IS_VAR && !container) { + SAVE_OPLINE(); + container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_RW); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_RW TSRMLS_CC); + zend_fetch_dimension_address(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_RW TSRMLS_CC); FREE_OP2(); - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(90, ZEND_FETCH_DIM_IS, VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS); + zval **container; - if (OP1_TYPE == IS_VAR && !container) { + SAVE_OPLINE(); + container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_IS); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address_read(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_IS TSRMLS_CC); + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_IS TSRMLS_CC); FREE_OP2(); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, VAR|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); zval **container; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->extended_value)) { + SAVE_OPLINE(); + + if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC); - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + zend_fetch_dimension_address(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_W TSRMLS_CC); + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } } else { if (OP2_TYPE == IS_UNUSED) { zend_error_noreturn(E_ERROR, "Cannot use [] for reading"); } container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address_read(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_R TSRMLS_CC); + zend_fetch_dimension_address_read(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC); } FREE_OP2(); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(96, ZEND_FETCH_DIM_UNSET, VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval **container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_UNSET); - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval **container; - /* Not needed in DIM_UNSET - if (opline->extended_value == ZEND_FETCH_ADD_LOCK) { - PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr); - } - */ + SAVE_OPLINE(); + container = GET_OP1_ZVAL_PTR_PTR(BP_VAR_UNSET); + if (OP1_TYPE == IS_CV) { if (container != &EG(uninitialized_zval_ptr)) { SEPARATE_ZVAL_IF_NOT_REF(container); } } - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_fetch_dimension_address(&EX_T(opline->result.u.var), container, dim, IS_OP2_TMP_FREE(), BP_VAR_UNSET TSRMLS_CC); + zend_fetch_dimension_address(&EX_T(opline->result.var), container, GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_UNSET TSRMLS_CC); FREE_OP2(); - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); - if (EX_T(opline->result.u.var).var.ptr_ptr == NULL) { + if (UNEXPECTED(EX_T(opline->result.var).var.ptr_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } else { zend_free_op free_res; + zval **retval_ptr = EX_T(opline->result.var).var.ptr_ptr; - PZVAL_UNLOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &free_res); - if (EX_T(opline->result.u.var).var.ptr_ptr != &EG(uninitialized_zval_ptr)) { - SEPARATE_ZVAL_IF_NOT_REF(EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_UNLOCK(*retval_ptr, &free_res); + if (retval_ptr != &EG(uninitialized_zval_ptr)) { + SEPARATE_ZVAL_IF_NOT_REF(retval_ptr); } - PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_LOCK(*retval_ptr); FREE_OP_VAR_PTR(free_res); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } - ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HELPER_EX(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV, int type) +ZEND_VM_HELPER(zend_fetch_property_address_read_helper, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *container = GET_OP1_OBJ_ZVAL_PTR(type); + zval *container; zend_free_op free_op2; - zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval *offset; - if (Z_TYPE_P(container) != IS_OBJECT || !Z_OBJ_HT_P(container)->read_property) { - if (type != BP_VAR_IS) { - zend_error(E_NOTICE, "Trying to get property of non-object"); + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); + offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + zend_error(E_NOTICE, "Trying to get property of non-object"); + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); - } FREE_OP2(); } else { zval *retval; @@ -1256,17 +1357,17 @@ } /* here we are sure we are dealing with an object */ - retval = Z_OBJ_HT_P(container)->read_property(container, offset, type TSRMLS_CC); + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); - if (RETURN_VALUE_UNUSED(&opline->result)) { + if (!RETURN_VALUE_USED(opline)) { if (Z_REFCOUNT_P(retval) == 0) { GC_REMOVE_ZVAL_FROM_BUFFER(retval); zval_dtor(retval); FREE_ZVAL(retval); } } else { - AI_SET_PTR(EX_T(opline->result.u.var).var, retval); PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); } if (IS_OP2_TMP_FREE()) { @@ -1277,139 +1378,193 @@ } FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(82, ZEND_FETCH_OBJ_R, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_property_address_read_helper, type, BP_VAR_R); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_property_address_read_helper); } ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval *property; zval **container; + SAVE_OPLINE(); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE == IS_VAR && (opline->extended_value & ZEND_FETCH_ADD_LOCK)) { - PZVAL_LOCK(*EX_T(opline->op1.u.var).var.ptr_ptr); - EX_T(opline->op1.u.var).var.ptr = *EX_T(opline->op1.u.var).var.ptr_ptr; + PZVAL_LOCK(*EX_T(opline->op1.var).var.ptr_ptr); + EX_T(opline->op1.var).var.ptr = *EX_T(opline->op1.var).var.ptr_ptr; } - + if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property); } container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(&EX_T(opline->result.u.var), container, property, BP_VAR_W TSRMLS_CC); + + zend_fetch_property_address(&EX_T(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL), BP_VAR_W TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property); } else { FREE_OP2(); } - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); /* We are going to assign the result by reference */ if (opline->extended_value & ZEND_FETCH_MAKE_REF) { - Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); - SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); - Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + zval **retval_ptr = EX_T(opline->result.var).var.ptr_ptr; + + Z_DELREF_PP(retval_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(retval_ptr); + Z_ADDREF_PP(retval_ptr); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(88, ZEND_FETCH_OBJ_RW, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + zval *property; + zval **container; + SAVE_OPLINE(); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_RW); + if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property); } - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(&EX_T(opline->result.u.var), container, property, BP_VAR_RW TSRMLS_CC); + zend_fetch_property_address(&EX_T(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL), BP_VAR_RW TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property); } else { FREE_OP2(); } - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(91, ZEND_FETCH_OBJ_IS, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_property_address_read_helper, type, BP_VAR_IS); + USE_OPLINE + zend_free_op free_op1; + zval *container; + zend_free_op free_op2; + zval *offset; + + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_IS); + offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_OBJECT) || + UNEXPECTED(Z_OBJ_HT_P(container)->read_property == NULL)) { + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + } + FREE_OP2(); + } else { + zval *retval; + + if (IS_OP2_TMP_FREE()) { + MAKE_REAL_ZVAL_PTR(offset); + } + + /* here we are sure we are dealing with an object */ + retval = Z_OBJ_HT_P(container)->read_property(container, offset, BP_VAR_IS, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); + + if (!RETURN_VALUE_USED(opline)) { + if (Z_REFCOUNT_P(retval) == 0) { + GC_REMOVE_ZVAL_FROM_BUFFER(retval); + zval_dtor(retval); + FREE_ZVAL(retval); + } + } else { + PZVAL_LOCK(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); + } + + if (IS_OP2_TMP_FREE()) { + zval_ptr_dtor(&offset); + } else { + FREE_OP2(); + } + } + + FREE_OP1(); + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE - if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->extended_value)) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), (opline->extended_value & ZEND_FETCH_ARG_MASK))) { /* Behave like FETCH_OBJ_W */ zend_free_op free_op1, free_op2; - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + zval *property; + zval **container; + SAVE_OPLINE(); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property); } - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(&EX_T(opline->result.u.var), container, property, BP_VAR_W TSRMLS_CC); + zend_fetch_property_address(&EX_T(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL), BP_VAR_W TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property); } else { FREE_OP2(); } - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else { - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_fetch_property_address_read_helper, type, BP_VAR_R); + ZEND_VM_DISPATCH_TO_HELPER(zend_fetch_property_address_read_helper); } } ZEND_VM_HANDLER(97, ZEND_FETCH_OBJ_UNSET, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2, free_res; - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_R); - zval *property = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval **container; + zval *property; + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_R); + property = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE == IS_CV) { if (container != &EG(uninitialized_zval_ptr)) { SEPARATE_ZVAL_IF_NOT_REF(container); @@ -1418,71 +1573,74 @@ if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property); } - if (OP1_TYPE == IS_VAR && !container) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an object"); } - zend_fetch_property_address(&EX_T(opline->result.u.var), container, property, BP_VAR_UNSET TSRMLS_CC); + zend_fetch_property_address(&EX_T(opline->result.var), container, property, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL), BP_VAR_UNSET TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property); } else { FREE_OP2(); } - if (OP1_TYPE == IS_VAR && OP1_FREE && - READY_TO_DESTROY(free_op1.var)) { - AI_USE_PTR(EX_T(opline->result.u.var).var); - if (!PZVAL_IS_REF(*EX_T(opline->result.u.var).var.ptr_ptr) && - Z_REFCOUNT_PP(EX_T(opline->result.u.var).var.ptr_ptr) > 2) { - SEPARATE_ZVAL(EX_T(opline->result.u.var).var.ptr_ptr); - } + if (OP1_TYPE == IS_VAR && OP1_FREE && READY_TO_DESTROY(free_op1.var)) { + EXTRACT_ZVAL_PTR(&EX_T(opline->result.var)); } FREE_OP1_VAR_PTR(); - PZVAL_UNLOCK(*EX_T(opline->result.u.var).var.ptr_ptr, &free_res); - if (EX_T(opline->result.u.var).var.ptr_ptr != &EG(uninitialized_zval_ptr)) { - SEPARATE_ZVAL_IF_NOT_REF(EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_UNLOCK(*EX_T(opline->result.var).var.ptr_ptr, &free_res); + if (EX_T(opline->result.var).var.ptr_ptr != &EG(uninitialized_zval_ptr)) { + SEPARATE_ZVAL_IF_NOT_REF(EX_T(opline->result.var).var.ptr_ptr); } - PZVAL_LOCK(*EX_T(opline->result.u.var).var.ptr_ptr); + PZVAL_LOCK(*EX_T(opline->result.var).var.ptr_ptr); FREE_OP_VAR_PTR(free_res); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(98, ZEND_FETCH_DIM_TMP_VAR, CONST|TMP, CONST) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *container = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *container; - if (Z_TYPE_P(container) != IS_ARRAY) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + SAVE_OPLINE(); + container = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } } else { zend_free_op free_op2; - zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval *value = *zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), GET_OP2_ZVAL_PTR(BP_VAR_R), OP2_TYPE, BP_VAR_R TSRMLS_CC); - AI_SET_PTR(EX_T(opline->result.u.var).var, *zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, BP_VAR_R TSRMLS_CC)); - SELECTIVE_PZVAL_LOCK(EX_T(opline->result.u.var).var.ptr, &opline->result); + SELECTIVE_PZVAL_LOCK(value, opline); + AI_SET_PTR(&EX_T(opline->result.var), value); FREE_OP2(); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(136, ZEND_ASSIGN_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); - zend_op *op_data = opline+1; + USE_OPLINE zend_free_op free_op1, free_op2; - zval **object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); - zval *property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval **object_ptr; + zval *property_name; + SAVE_OPLINE(); + object_ptr = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_W); + property_name = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property_name); } - if (OP1_TYPE == IS_VAR && !object_ptr) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - zend_assign_to_object(&opline->result, object_ptr, property_name, &op_data->op1, EX(Ts), ZEND_ASSIGN_OBJ TSRMLS_CC); + zend_assign_to_object(RETURN_VALUE_USED(opline)?&EX_T(opline->result.var).var.ptr:NULL, object_ptr, property_name, (opline+1)->op1_type, &(opline+1)->op1, EX_Ts(), ZEND_ASSIGN_OBJ, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property_name); } else { @@ -1490,18 +1648,21 @@ } FREE_OP1_VAR_PTR(); /* assign_obj has two opcodes! */ + CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); - zend_op *op_data = opline+1; + USE_OPLINE zend_free_op free_op1; - zval **object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + zval **object_ptr; - if (OP1_TYPE == IS_VAR && !object_ptr) { + SAVE_OPLINE(); + object_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(object_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } if (Z_TYPE_PP(object_ptr) == IS_OBJECT) { @@ -1511,7 +1672,7 @@ if (IS_OP2_TMP_FREE()) { MAKE_REAL_ZVAL_PTR(property_name); } - zend_assign_to_object(&opline->result, object_ptr, property_name, &op_data->op1, EX(Ts), ZEND_ASSIGN_DIM TSRMLS_CC); + zend_assign_to_object(RETURN_VALUE_USED(opline)?&EX_T(opline->result.var).var.ptr:NULL, object_ptr, property_name, (opline+1)->op1_type, &(opline+1)->op1, EX_Ts(), ZEND_ASSIGN_DIM, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); if (IS_OP2_TMP_FREE()) { zval_ptr_dtor(&property_name); } else { @@ -1523,28 +1684,42 @@ zval *dim = GET_OP2_ZVAL_PTR(BP_VAR_R); zval **variable_ptr_ptr; - zend_fetch_dimension_address(&EX_T(op_data->op2.u.var), object_ptr, dim, IS_OP2_TMP_FREE(), BP_VAR_W TSRMLS_CC); + zend_fetch_dimension_address(&EX_T((opline+1)->op2.var), object_ptr, dim, OP2_TYPE, BP_VAR_W TSRMLS_CC); FREE_OP2(); - value = get_zval_ptr(&op_data->op1, EX(Ts), &free_op_data1, BP_VAR_R); - variable_ptr_ptr = _get_zval_ptr_ptr_var(&op_data->op2, EX(Ts), &free_op_data2 TSRMLS_CC); - if (!variable_ptr_ptr) { - if (zend_assign_to_string_offset(&EX_T(op_data->op2.u.var), value, op_data->op1.op_type TSRMLS_CC)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); - INIT_PZVAL(EX_T(opline->result.u.var).var.ptr); - ZVAL_STRINGL(EX_T(opline->result.u.var).var.ptr, Z_STRVAL_P(EX_T(op_data->op2.u.var).str_offset.str)+EX_T(op_data->op2.u.var).str_offset.offset, 1, 1); + value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, EX_Ts(), &free_op_data1, BP_VAR_R); + variable_ptr_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, EX_Ts(), &free_op_data2 TSRMLS_CC); + if (UNEXPECTED(variable_ptr_ptr == NULL)) { + if (zend_assign_to_string_offset(&EX_T((opline+1)->op2.var), value, (opline+1)->op1_type TSRMLS_CC)) { + if (RETURN_VALUE_USED(opline)) { + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_STRINGL(retval, Z_STRVAL_P(EX_T((opline+1)->op2.var).str_offset.str)+EX_T((opline+1)->op2.var).str_offset.offset, 1, 1); + INIT_PZVAL(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); } - } else if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + } else if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } + } else if (UNEXPECTED(*variable_ptr_ptr == &EG(error_zval))) { + if (IS_TMP_FREE(free_op_data1)) { + zval_dtor(value); + } + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + } } else { - value = zend_assign_to_variable(variable_ptr_ptr, value, IS_TMP_FREE(free_op_data1) TSRMLS_CC); - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, value); + if (IS_TMP_FREE(free_op_data1)) { + value = zend_assign_tmp_to_variable(variable_ptr_ptr, value TSRMLS_CC); + } else { + value = zend_assign_to_variable(variable_ptr_ptr, value TSRMLS_CC); + } + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(value); + AI_SET_PTR(&EX_T(opline->result.var), value); } } FREE_OP_VAR_PTR(free_op_data2); @@ -1552,34 +1727,53 @@ } FREE_OP1_VAR_PTR(); /* assign_dim has two opcodes! */ + CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *value = GET_OP2_ZVAL_PTR(BP_VAR_R); - zval **variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + zval *value; + zval **variable_ptr_ptr; - if (OP1_TYPE == IS_VAR && !variable_ptr_ptr) { - if (zend_assign_to_string_offset(&EX_T(opline->op1.u.var), value, OP2_TYPE TSRMLS_CC)) { - if (!RETURN_VALUE_UNUSED(&opline->result)) { - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); - INIT_PZVAL(EX_T(opline->result.u.var).var.ptr); - ZVAL_STRINGL(EX_T(opline->result.u.var).var.ptr, Z_STRVAL_P(EX_T(opline->op1.u.var).str_offset.str)+EX_T(opline->op1.u.var).str_offset.offset, 1, 1); + SAVE_OPLINE(); + value = GET_OP2_ZVAL_PTR(BP_VAR_R); + variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + + if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr_ptr == NULL)) { + if (zend_assign_to_string_offset(&EX_T(opline->op1.var), value, OP2_TYPE TSRMLS_CC)) { + if (RETURN_VALUE_USED(opline)) { + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_STRINGL(retval, Z_STRVAL_P(EX_T(opline->op1.var).str_offset.str)+EX_T(opline->op1.var).str_offset.offset, 1, 1); + INIT_PZVAL(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); } - } else if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, EG(uninitialized_zval_ptr)); - PZVAL_LOCK(EG(uninitialized_zval_ptr)); + } else if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); } + } else if (OP1_TYPE == IS_VAR && UNEXPECTED(*variable_ptr_ptr == &EG(error_zval))) { + if (IS_OP2_TMP_FREE()) { + zval_dtor(value); + } + if (RETURN_VALUE_USED(opline)) { + PZVAL_LOCK(&EG(uninitialized_zval)); + AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval)); + } } else { - value = zend_assign_to_variable(variable_ptr_ptr, value, IS_OP2_TMP_FREE() TSRMLS_CC); - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, value); + if (IS_OP2_TMP_FREE()) { + value = zend_assign_tmp_to_variable(variable_ptr_ptr, value TSRMLS_CC); + } else { + value = zend_assign_to_variable(variable_ptr_ptr, value TSRMLS_CC); + } + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(value); + AI_SET_PTR(&EX_T(opline->result.var), value); } } @@ -1588,40 +1782,44 @@ /* zend_assign_to_variable() always takes care of op2, never free it! */ FREE_OP2_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; zval **variable_ptr_ptr; - zval **value_ptr_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); + zval **value_ptr_ptr; + SAVE_OPLINE(); + value_ptr_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); + if (OP2_TYPE == IS_VAR && value_ptr_ptr && !Z_ISREF_PP(value_ptr_ptr) && opline->extended_value == ZEND_RETURNS_FUNCTION && - !EX_T(opline->op2.u.var).var.fcall_returned_reference) { + !EX_T(opline->op2.var).var.fcall_returned_reference) { if (free_op2.var == NULL) { PZVAL_LOCK(*value_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ } zend_error(E_STRICT, "Only variables should be assigned by reference"); if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP2_VAR_PTR(); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ASSIGN); } else if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { PZVAL_LOCK(*value_ptr_ptr); } - if (OP1_TYPE == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr)) { zend_error_noreturn(E_ERROR, "Cannot assign by reference to overloaded object"); } variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if ((OP2_TYPE == IS_VAR && !value_ptr_ptr) || - (OP1_TYPE == IS_VAR && !variable_ptr_ptr)) { + if ((OP2_TYPE == IS_VAR && UNEXPECTED(value_ptr_ptr == NULL)) || + (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr_ptr == NULL))) { zend_error_noreturn(E_ERROR, "Cannot create references to/from string offsets nor overloaded objects"); } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); @@ -1630,47 +1828,53 @@ Z_DELREF_PP(variable_ptr_ptr); } - if (!RETURN_VALUE_UNUSED(&opline->result)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); + if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(*variable_ptr_ptr); + AI_SET_PTR(&EX_T(opline->result.var), *variable_ptr_ptr); } FREE_OP1_VAR_PTR(); FREE_OP2_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(42, ZEND_JMP, ANY, ANY) { + USE_OPLINE + #if DEBUG_ZEND>=2 - printf("Jumping to %d\n", EX(opline)->op1.u.opline_num); + printf("Jumping to %d\n", opline->op1.opline_num); #endif - ZEND_VM_SET_OPCODE(EX(opline)->op1.u.jmp_addr); + ZEND_VM_SET_OPCODE(opline->op1.jmp_addr); ZEND_VM_CONTINUE(); /* CHECK_ME */ } ZEND_VM_HANDLER(43, ZEND_JMPZ, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *val; int ret; - if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(val) == IS_BOOL) { + SAVE_OPLINE(); + val = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) { ret = Z_LVAL_P(val); } else { ret = i_zend_is_true(val); FREE_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_CONTINUE(); + HANDLE_EXCEPTION(); } } if (!ret) { #if DEBUG_ZEND>=2 - printf("Conditional jmp to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp to %d\n", opline->op2.opline_num); #endif - ZEND_VM_SET_OPCODE(opline->op2.u.jmp_addr); + ZEND_VM_SET_OPCODE(opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } @@ -1679,25 +1883,28 @@ ZEND_VM_HANDLER(44, ZEND_JMPNZ, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *val; int ret; - if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(val) == IS_BOOL) { + SAVE_OPLINE(); + val = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) { ret = Z_LVAL_P(val); } else { ret = i_zend_is_true(val); FREE_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_CONTINUE(); + HANDLE_EXCEPTION(); } } if (ret) { #if DEBUG_ZEND>=2 - printf("Conditional jmp to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp to %d\n", opline->op2.opline_num); #endif - ZEND_VM_SET_OPCODE(opline->op2.u.jmp_addr); + ZEND_VM_SET_OPCODE(opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } @@ -1706,18 +1913,21 @@ ZEND_VM_HANDLER(45, ZEND_JMPZNZ, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *val; int retval; - if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(val) == IS_BOOL) { + SAVE_OPLINE(); + val = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) { retval = Z_LVAL_P(val); } else { retval = i_zend_is_true(val); FREE_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_CONTINUE(); + HANDLE_EXCEPTION(); } } if (EXPECTED(retval != 0)) { @@ -1728,36 +1938,39 @@ ZEND_VM_CONTINUE(); /* CHECK_ME */ } else { #if DEBUG_ZEND>=2 - printf("Conditional jmp on false to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp on false to %d\n", opline->op2.opline_num); #endif - ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.u.opline_num]); + ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } } ZEND_VM_HANDLER(46, ZEND_JMPZ_EX, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *val; int retval; - if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(val) == IS_BOOL) { + SAVE_OPLINE(); + val = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) { retval = Z_LVAL_P(val); } else { retval = i_zend_is_true(val); FREE_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_CONTINUE(); + HANDLE_EXCEPTION(); } } - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = retval; - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_BOOL; + Z_LVAL(EX_T(opline->result.var).tmp_var) = retval; + Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL; if (!retval) { #if DEBUG_ZEND>=2 - printf("Conditional jmp to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp to %d\n", opline->op2.opline_num); #endif - ZEND_VM_SET_OPCODE(opline->op2.u.jmp_addr); + ZEND_VM_SET_OPCODE(opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } ZEND_VM_NEXT_OPCODE(); @@ -1765,27 +1978,30 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *val = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *val; int retval; - if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(val) == IS_BOOL) { + SAVE_OPLINE(); + val = GET_OP1_ZVAL_PTR(BP_VAR_R); + + if (OP1_TYPE == IS_TMP_VAR && EXPECTED(Z_TYPE_P(val) == IS_BOOL)) { retval = Z_LVAL_P(val); } else { retval = i_zend_is_true(val); FREE_OP1(); if (UNEXPECTED(EG(exception) != NULL)) { - ZEND_VM_CONTINUE(); + HANDLE_EXCEPTION(); } } - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = retval; - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_BOOL; + Z_LVAL(EX_T(opline->result.var).tmp_var) = retval; + Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL; if (retval) { #if DEBUG_ZEND>=2 - printf("Conditional jmp to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp to %d\n", opline->op2.opline_num); #endif - ZEND_VM_SET_OPCODE(opline->op2.u.jmp_addr); + ZEND_VM_SET_OPCODE(opline->op2.jmp_addr); ZEND_VM_CONTINUE(); } ZEND_VM_NEXT_OPCODE(); @@ -1793,28 +2009,37 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMP, ANY) { - zendi_zval_dtor(EX_T(EX(opline)->op1.u.var).tmp_var); + USE_OPLINE + + SAVE_OPLINE(); + zendi_zval_dtor(EX_T(opline->op1.var).tmp_var); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(53, ZEND_INIT_STRING, ANY, ANY) { - zval *tmp = &EX_T(EX(opline)->result.u.var).tmp_var; + USE_OPLINE + zval *tmp = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); tmp->value.str.val = emalloc(1); tmp->value.str.val[0] = 0; tmp->value.str.len = 0; Z_SET_REFCOUNT_P(tmp, 1); tmp->type = IS_STRING; Z_UNSET_ISREF_P(tmp); + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(54, ZEND_ADD_CHAR, TMP|UNUSED, CONST) { - zend_op *opline = EX(opline); - zval *str = &EX_T(opline->result.u.var).tmp_var; + USE_OPLINE + zval *str = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); + if (OP1_TYPE == IS_UNUSED) { /* Initialize for erealloc in add_char_to_string */ Z_STRVAL_P(str) = NULL; @@ -1824,17 +2049,20 @@ INIT_PZVAL(str); } - add_char_to_string(str, str, &opline->op2.u.constant); + add_char_to_string(str, str, opline->op2.zv); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(55, ZEND_ADD_STRING, TMP|UNUSED, CONST) { - zend_op *opline = EX(opline); - zval *str = &EX_T(opline->result.u.var).tmp_var; + USE_OPLINE + zval *str = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); + if (OP1_TYPE == IS_UNUSED) { /* Initialize for erealloc in add_string_to_string */ Z_STRVAL_P(str) = NULL; @@ -1844,21 +2072,25 @@ INIT_PZVAL(str); } - add_string_to_string(str, str, &opline->op2.u.constant); + add_string_to_string(str, str, opline->op2.zv); /* FREE_OP is missing intentionally here - we're always working on the same temporary variable */ + /*CHECK_EXCEPTION();*/ ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(56, ZEND_ADD_VAR, TMP|UNUSED, TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op2; - zval *str = &EX_T(opline->result.u.var).tmp_var; - zval *var = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval *str = &EX_T(opline->result.var).tmp_var; + zval *var; zval var_copy; int use_copy = 0; + SAVE_OPLINE(); + var = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE == IS_UNUSED) { /* Initialize for erealloc in add_string_to_string */ Z_STRVAL_P(str) = NULL; @@ -1888,47 +2120,55 @@ */ FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE - + SAVE_OPLINE(); + EG(exception) = NULL; if (OP2_TYPE == IS_UNUSED) { - EX_T(opline->result.u.var).class_entry = zend_fetch_class(NULL, 0, opline->extended_value TSRMLS_CC); + EX_T(opline->result.var).class_entry = zend_fetch_class(NULL, 0, opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else { zend_free_op free_op2; zval *class_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (OP2_TYPE != IS_CONST && Z_TYPE_P(class_name) == IS_OBJECT) { - EX_T(opline->result.u.var).class_entry = Z_OBJCE_P(class_name); + if (OP2_TYPE == IS_CONST) { + EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); + } else if (Z_TYPE_P(class_name) == IS_OBJECT) { + EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name); } else if (Z_TYPE_P(class_name) == IS_STRING) { - EX_T(opline->result.u.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); + EX_T(opline->result.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string"); } FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } } ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, TMP|VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zval *function_name; char *function_name_strval; int function_name_strlen; zend_free_op free_op1, free_op2; + SAVE_OPLINE(); zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(function_name)!=IS_STRING) { + if (OP2_TYPE != IS_CONST && + UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { zend_error_noreturn(E_ERROR, "Method name must be a string"); } @@ -1937,14 +2177,15 @@ EX(object) = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); - if (EX(object) && Z_TYPE_P(EX(object)) == IS_OBJECT) { - if (Z_OBJ_HT_P(EX(object))->get_method == NULL) { + if (EXPECTED(EX(object) != NULL) && + EXPECTED(Z_TYPE_P(EX(object)) == IS_OBJECT)) { + if (UNEXPECTED(Z_OBJ_HT_P(EX(object))->get_method == NULL)) { zend_error_noreturn(E_ERROR, "Object does not support method calls"); } /* First, locate the function. */ - EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen TSRMLS_CC); - if (!EX(fbc)) { + EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(&EX(object), function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); + if (UNEXPECTED(EX(fbc) == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval); } @@ -1970,28 +2211,30 @@ FREE_OP2(); FREE_OP1_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, CONST|VAR, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zval *function_name; zend_class_entry *ce; + SAVE_OPLINE(); zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP1_TYPE == IS_CONST) { /* no function found. try a static method in class */ - ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); - if (!ce) { - zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL(opline->op1.u.constant)); + ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + zend_error_noreturn(E_ERROR, "Class '%s' not found", Z_STRVAL_P(opline->op1.zv)); } EX(called_scope) = ce; } else { - ce = EX_T(opline->op1.u.var).class_entry; + ce = EX_T(opline->op1.var).class_entry; - if (opline->op1.u.EA.type == ZEND_FETCH_CLASS_PARENT || opline->op1.u.EA.type == ZEND_FETCH_CLASS_SELF) { + if (opline->extended_value == ZEND_FETCH_CLASS_PARENT || opline->extended_value == ZEND_FETCH_CLASS_SELF) { EX(called_scope) = EG(called_scope); } else { EX(called_scope) = ce; @@ -2003,12 +2246,12 @@ zend_free_op free_op2; if (OP2_TYPE == IS_CONST) { - function_name_strval = Z_STRVAL(opline->op2.u.constant); - function_name_strlen = Z_STRLEN(opline->op2.u.constant); + function_name_strval = Z_STRVAL_P(opline->op2.zv); + function_name_strlen = Z_STRLEN_P(opline->op2.zv); } else { function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(function_name) != IS_STRING) { + if (UNEXPECTED(Z_TYPE_P(function_name) != IS_STRING)) { zend_error_noreturn(E_ERROR, "Function name must be a string"); } else { function_name_strval = Z_STRVAL_P(function_name); @@ -2020,9 +2263,9 @@ if (ce->get_static_method) { EX(fbc) = ce->get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); } else { - EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen TSRMLS_CC); + EX(fbc) = zend_std_get_static_method(ce, function_name_strval, function_name_strlen, ((OP2_TYPE == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC); } - if (!EX(fbc)) { + if (UNEXPECTED(EX(fbc) == NULL)) { zend_error_noreturn(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval); } } @@ -2031,11 +2274,11 @@ FREE_OP2(); } } else { - if(!ce->constructor) { + if (UNEXPECTED(ce->constructor == NULL)) { zend_error_noreturn(E_ERROR, "Cannot call constructor"); } if (EG(This) && Z_OBJCE_P(EG(This)) != ce->constructor->common.scope && (ce->constructor->common.fn_flags & ZEND_ACC_PRIVATE)) { - zend_error(E_COMPILE_ERROR, "Cannot call private %s::__construct()", ce->name); + zend_error_noreturn(E_ERROR, "Cannot call private %s::__construct()", ce->name); } EX(fbc) = ce->constructor; } @@ -2067,77 +2310,83 @@ } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zval *function_name; - char *function_name_strval, *lcname; - int function_name_strlen; - zend_free_op free_op2; - zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); if (OP2_TYPE == IS_CONST) { - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc)) == FAILURE) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); + function_name = opline->op1.zv; + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name)+1, Z_HASH_P(function_name), (void **) &EX(fbc)) == FAILURE)) { + SAVE_OPLINE(); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } + EX(object) = NULL; + /*CHECK_EXCEPTION();*/ + ZEND_VM_NEXT_OPCODE(); } else { + char *function_name_strval, *lcname; + int function_name_strlen; + zend_free_op free_op2; + + SAVE_OPLINE(); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); - if (OP2_TYPE != IS_CONST && - Z_TYPE_P(function_name) == IS_OBJECT && + if (EXPECTED(Z_TYPE_P(function_name) == IS_STRING)) { + function_name_strval = Z_STRVAL_P(function_name); + function_name_strlen = Z_STRLEN_P(function_name); + if (function_name_strval[0] == '\\') { + function_name_strlen -= 1; + lcname = zend_str_tolower_dup(function_name_strval + 1, function_name_strlen); + } else { + lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); + } + if (UNEXPECTED(zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE)) { + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); + } + efree(lcname); + FREE_OP2(); + EX(object) = NULL; + CHECK_EXCEPTION(); + ZEND_VM_NEXT_OPCODE(); + } else if (OP2_TYPE != IS_CONST && + EXPECTED(Z_TYPE_P(function_name) == IS_OBJECT) && Z_OBJ_HANDLER_P(function_name, get_closure) && Z_OBJ_HANDLER_P(function_name, get_closure)(function_name, &EX(called_scope), &EX(fbc), &EX(object) TSRMLS_CC) == SUCCESS) { if (EX(object)) { Z_ADDREF_P(EX(object)); } FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); - } - - if (Z_TYPE_P(function_name) != IS_STRING) { + } else { zend_error_noreturn(E_ERROR, "Function name must be a string"); } - function_name_strval = Z_STRVAL_P(function_name); - function_name_strlen = Z_STRLEN_P(function_name); - if (function_name_strval[0] == '\\') { - - function_name_strlen -= 1; - lcname = zend_str_tolower_dup(function_name_strval + 1, function_name_strlen); - } else { - lcname = zend_str_tolower_dup(function_name_strval, function_name_strlen); - } - if (zend_hash_find(EG(function_table), lcname, function_name_strlen+1, (void **) &EX(fbc)) == FAILURE) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", function_name_strval); - } - efree(lcname); - FREE_OP2(); } - - EX(object) = NULL; - ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST) { - zend_op *opline = EX(opline); - zend_op *op_data = opline + 1; + USE_OPLINE - ZEND_VM_INC_OPCODE(); zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant)+1, opline->extended_value, (void **) &EX(fbc))==FAILURE) { - char *short_name = Z_STRVAL(opline->op1.u.constant)+Z_LVAL(op_data->op1.u.constant); - if (zend_hash_quick_find(EG(function_table), short_name, Z_STRLEN(opline->op1.u.constant)-Z_LVAL(op_data->op1.u.constant)+1, op_data->extended_value, (void **) &EX(fbc))==FAILURE) { - zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL(opline->op2.u.constant)); + if (zend_hash_quick_find(EG(function_table), Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv)+1, Z_HASH_P(opline->op1.zv), (void **) &EX(fbc))==FAILURE) { + char *short_name = Z_STRVAL_P(opline->op1.zv) + (opline+1)->op1.num; + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), short_name, Z_STRLEN_P(opline->op1.zv) - (opline+1)->op1.num+1, (opline+1)->extended_value, (void **) &EX(fbc))==FAILURE)) { + SAVE_OPLINE(); + zend_error_noreturn(E_ERROR, "Call to undefined function %s()", Z_STRVAL_P(opline->op2.zv)); } } EX(object) = NULL; + ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } @@ -2149,8 +2398,8 @@ EG(current_execute_data) = EX(prev_execute_data); EG(opline_ptr) = NULL; if (!EG(active_symbol_table)) { - zval ***cv = EX(CVs); - zval ***end = cv + EX(op_array)->last_var; + zval ***cv = EX_CVs(); + zval ***end = cv + op_array->last_var; while (cv != end) { if (*cv) { zval_ptr_dtor(*cv); @@ -2165,32 +2414,38 @@ if (nested) { execute_data = EG(current_execute_data); + } + if (nested) { + USE_OPLINE - if (EX(call_opline)->opcode == ZEND_INCLUDE_OR_EVAL) { + LOAD_REGS(); + LOAD_OPLINE(); + if (UNEXPECTED(opline->opcode == ZEND_INCLUDE_OR_EVAL)) { EX(function_state).function = (zend_function *) EX(op_array); EX(function_state).arguments = NULL; EX(object) = EX(current_object); - if (RETURN_VALUE_USED(EX(call_opline))) { - if (!EX_T(EX(call_opline)->result.u.var).var.ptr) { /* there was no return statement */ - ALLOC_ZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr); - INIT_PZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr); - Z_LVAL_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = 1; - Z_TYPE_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = IS_BOOL; - } - } - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); EG(return_value_ptr_ptr) = EX(original_return_value); destroy_op_array(op_array TSRMLS_CC); efree(op_array); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); + HANDLE_EXCEPTION_LEAVE(); + } else if (RETURN_VALUE_USED(opline)) { + if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */ + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_BOOL(retval, 1); + INIT_PZVAL(retval); + EX_T(opline->result.var).var.ptr = retval; + } } - EX(opline)++; + ZEND_VM_INC_OPCODE(); ZEND_VM_LEAVE(); } else { @@ -2214,7 +2469,7 @@ EX(function_state).arguments = NULL; if (EG(This)) { - if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { if (IS_CTOR_USED(EX(called_scope))) { Z_DELREF_P(EG(This)); } @@ -2233,14 +2488,15 @@ zend_vm_stack_clear_multiple(TSRMLS_C); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(EX(call_opline)) && EX_T(EX(call_opline)->result.u.var).var.ptr) { - zval_ptr_dtor(&EX_T(EX(call_opline)->result.u.var).var.ptr); + if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); } + HANDLE_EXCEPTION_LEAVE(); } - EX(opline)++; + ZEND_VM_INC_OPCODE(); ZEND_VM_LEAVE(); } } @@ -2249,89 +2505,99 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_bool should_change_scope = 0; + zend_function *fbc = EX(function_state).function; - if (EX(function_state).function->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) { - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + SAVE_OPLINE(); + if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) { + zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } - if (EX(function_state).function->common.fn_flags & ZEND_ACC_DEPRECATED) { + if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) { zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated", - EX(function_state).function->common.scope ? EX(function_state).function->common.scope->name : "", - EX(function_state).function->common.scope ? "::" : "", - EX(function_state).function->common.function_name); + fbc->common.scope ? fbc->common.scope->name : "", + fbc->common.scope ? "::" : "", + fbc->common.function_name); } } - if (EX(function_state).function->common.scope && - !(EX(function_state).function->common.fn_flags & ZEND_ACC_STATIC) && + if (fbc->common.scope && + !(fbc->common.fn_flags & ZEND_ACC_STATIC) && !EX(object)) { - if (EX(function_state).function->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { + if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { /* FIXME: output identifiers properly */ - zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name); } else { /* FIXME: output identifiers properly */ /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */ - zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", EX(function_state).function->common.scope->name, EX(function_state).function->common.function_name); + zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name); } } - if (EX(function_state).function->type == ZEND_USER_FUNCTION || - EX(function_state).function->common.scope) { + if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { should_change_scope = 1; EX(current_this) = EG(This); EX(current_scope) = EG(scope); EX(current_called_scope) = EG(called_scope); EG(This) = EX(object); - EG(scope) = (EX(function_state).function->type == ZEND_USER_FUNCTION || !EX(object)) ? EX(function_state).function->common.scope : NULL; + EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; EG(called_scope) = EX(called_scope); } zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc)); EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC); + LOAD_OPLINE(); - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { - ALLOC_INIT_ZVAL(EX_T(opline->result.u.var).var.ptr); - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference; + if (fbc->type == ZEND_INTERNAL_FUNCTION) { + temp_variable *ret = &EX_T(opline->result.var); - if (EX(function_state).function->common.arg_info) { + MAKE_STD_ZVAL(ret->var.ptr); + ZVAL_NULL(ret->var.ptr); + ret->var.ptr_ptr = &ret->var.ptr; + ret->var.fcall_returned_reference = fbc->common.return_reference; + + if (fbc->common.arg_info) { zend_uint i=0; zval **p = (zval**)EX(function_state).arguments; ulong arg_count = opline->extended_value; while (arg_count>0) { - zend_verify_arg_type(EX(function_state).function, ++i, *(p-arg_count), 0 TSRMLS_CC); + zend_verify_arg_type(fbc, ++i, *(p-arg_count), 0 TSRMLS_CC); arg_count--; } } + if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - ((zend_internal_function *) EX(function_state).function)->handler(opline->extended_value, EX_T(opline->result.u.var).var.ptr, EX(function_state).function->common.return_reference?&EX_T(opline->result.u.var).var.ptr:NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + fbc->internal_function.handler(opline->extended_value, ret->var.ptr, fbc->common.return_reference ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_execute_internal(EXECUTE_DATA, RETURN_VALUE_USED(opline) TSRMLS_CC); } if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); + zval_ptr_dtor(&ret->var.ptr); } - } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) { + } else if (fbc->type == ZEND_USER_FUNCTION) { EX(original_return_value) = EG(return_value_ptr_ptr); EG(active_symbol_table) = NULL; - EG(active_op_array) = &EX(function_state).function->op_array; + EG(active_op_array) = &fbc->op_array; EG(return_value_ptr_ptr) = NULL; - if (RETURN_VALUE_USED(opline)) { - EG(return_value_ptr_ptr) = &EX_T(opline->result.u.var).var.ptr; - EX_T(opline->result.u.var).var.ptr = NULL; - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - EX_T(opline->result.u.var).var.fcall_returned_reference = EX(function_state).function->common.return_reference; + if (RETURN_VALUE_USED(opline)) { + temp_variable *ret = &EX_T(opline->result.var); + + ret->var.ptr = NULL; + EG(return_value_ptr_ptr) = &ret->var.ptr; + ret->var.ptr_ptr = &ret->var.ptr; + ret->var.fcall_returned_reference = fbc->common.return_reference; } - if (zend_execute == execute && !EG(exception)) { - EX(call_opline) = opline; - ZEND_VM_ENTER(); + if (EXPECTED(zend_execute == execute)) { + if (EXPECTED(EG(exception) == NULL)) { + ZEND_VM_ENTER(); + } } else { zend_execute(EG(active_op_array) TSRMLS_CC); } @@ -2352,27 +2618,28 @@ } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ - ALLOC_INIT_ZVAL(EX_T(opline->result.u.var).var.ptr); + MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr); + ZVAL_NULL(EX_T(opline->result.var).var.ptr); /* Not sure what should be done here if it's a static method */ - if (EX(object)) { - Z_OBJ_HT_P(EX(object))->call_method(EX(function_state).function->common.function_name, opline->extended_value, EX_T(opline->result.u.var).var.ptr, &EX_T(opline->result.u.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); + if (EXPECTED(EX(object) != NULL)) { + Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } - if (EX(function_state).function->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { - efree(EX(function_state).function->common.function_name); + if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { + efree(fbc->common.function_name); } - efree(EX(function_state).function); + efree(fbc); if (!RETURN_VALUE_USED(opline)) { - zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); } else { - Z_UNSET_ISREF_P(EX_T(opline->result.u.var).var.ptr); - Z_SET_REFCOUNT_P(EX_T(opline->result.u.var).var.ptr, 1); - EX_T(opline->result.u.var).var.fcall_returned_reference = 0; - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; + Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); + Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); + EX_T(opline->result.var).var.fcall_returned_reference = 0; + EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr; } } @@ -2381,7 +2648,7 @@ if (should_change_scope) { if (EG(This)) { - if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) { + if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) { if (IS_CTOR_USED(EX(called_scope))) { Z_DELREF_P(EG(This)); } @@ -2401,11 +2668,12 @@ zend_vm_stack_clear_multiple(TSRMLS_C); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); - if (RETURN_VALUE_USED(opline) && EX_T(opline->result.u.var).var.ptr) { - zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); + if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { + zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); } + HANDLE_EXCEPTION(); } ZEND_VM_NEXT_OPCODE(); @@ -2419,13 +2687,14 @@ ZEND_VM_HANDLER(60, ZEND_DO_FCALL, CONST, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; zval *fname = GET_OP1_ZVAL_PTR(BP_VAR_R); zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope)); - if (zend_hash_quick_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, Z_LVAL(opline->op2.u.constant), (void **) &EX(function_state).function)==FAILURE) { + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { + SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } EX(object) = NULL; @@ -2437,12 +2706,13 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval *retval_ptr; zval **retval_ptr_ptr; zend_free_op free_op1; - if (EG(active_op_array)->return_reference == ZEND_RETURN_REF) { + SAVE_OPLINE(); + if (UNEXPECTED(EG(active_op_array)->return_reference == ZEND_RETURN_REF)) { if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) { /* Not supposed to happen, but we'll allow it */ @@ -2452,14 +2722,14 @@ retval_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && !retval_ptr_ptr) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(retval_ptr_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Cannot return string offsets by reference"); } if (OP1_TYPE == IS_VAR && !Z_ISREF_PP(retval_ptr_ptr)) { if (opline->extended_value == ZEND_RETURNS_FUNCTION && - EX_T(opline->op1.u.var).var.fcall_returned_reference) { - } else if (EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { + EX_T(opline->op1.var).var.fcall_returned_reference) { + } else if (EX_T(opline->op1.var).var.ptr_ptr == &EX_T(opline->op1.var).var.ptr) { if (OP1_TYPE == IS_VAR && !OP1_FREE) { PZVAL_LOCK(*retval_ptr_ptr); /* undo the effect of get_zval_ptr_ptr() */ } @@ -2474,6 +2744,8 @@ (*EG(return_value_ptr_ptr)) = (*retval_ptr_ptr); } + FREE_OP1_IF_VAR(); + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } else { ZEND_VM_C_LABEL(return_by_value): @@ -2504,21 +2776,22 @@ INIT_PZVAL_COPY(ret, retval_ptr); *EG(return_value_ptr_ptr) = ret; } + FREE_OP1_IF_VAR(); + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } - FREE_OP1_IF_VAR(); - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval *value; zval *exception; zend_free_op free_op1; + SAVE_OPLINE(); value = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE == IS_CONST || Z_TYPE_P(value) != IS_OBJECT) { + if (OP1_TYPE == IS_CONST || UNEXPECTED(Z_TYPE_P(value) != IS_OBJECT)) { zend_error_noreturn(E_ERROR, "Can only throw objects"); } zend_exception_save(TSRMLS_C); @@ -2532,26 +2805,28 @@ zend_throw_exception_object(exception TSRMLS_CC); zend_exception_restore(TSRMLS_C); FREE_OP1_IF_VAR(); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } -ZEND_VM_HANDLER(107, ZEND_CATCH, ANY, CV) +ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV) { - zend_op *opline = EX(opline); - zend_class_entry *ce; + USE_OPLINE + zend_class_entry *ce, *catch_ce; + SAVE_OPLINE(); /* Check whether an exception has been thrown, if not, jump over code */ zend_exception_restore(TSRMLS_C); if (EG(exception) == NULL) { ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ } + catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC); ce = Z_OBJCE_P(EG(exception)); - if (ce != EX_T(opline->op1.u.var).class_entry) { - if (!instanceof_function(ce, EX_T(opline->op1.u.var).class_entry TSRMLS_CC)) { - if (opline->op1.u.EA.type) { + if (ce != catch_ce) { + if (!instanceof_function(ce, catch_ce TSRMLS_CC)) { + if (opline->result.num) { zend_throw_exception_internal(NULL TSRMLS_CC); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]); ZEND_VM_CONTINUE(); /* CHECK_ME */ @@ -2559,15 +2834,15 @@ } if (!EG(active_symbol_table)) { - if (EX(CVs)[opline->op2.u.var]) { - zval_ptr_dtor(EX(CVs)[opline->op2.u.var]); + if (EX_CV(opline->op2.var)) { + zval_ptr_dtor(EX_CV(opline->op2.var)); } - EX(CVs)[opline->op2.u.var] = (zval**)EX(CVs) + (EX(op_array)->last_var + opline->op2.u.var); - *EX(CVs)[opline->op2.u.var] = EG(exception); + EX_CV(opline->op2.var) = (zval**)EX_CVs() + (EX(op_array)->last_var + opline->op2.var); + *EX_CV(opline->op2.var) = EG(exception); } else { - zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.u.var); + zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.var); zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, - &EG(exception), sizeof(zval *), (void**)&EX(CVs)[opline->op2.u.var]); + &EG(exception), sizeof(zval *), (void**)&EX_CV(opline->op2.var)); } EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); @@ -2575,10 +2850,12 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE + + SAVE_OPLINE(); if (opline->extended_value==ZEND_DO_FCALL_BY_NAME - && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { - zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.u.opline_num); + && ARG_MUST_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + zend_error_noreturn(E_ERROR, "Cannot pass parameter %d by reference", opline->op2.opline_num); } { zval *valptr; @@ -2595,12 +2872,13 @@ zend_vm_stack_push(valptr TSRMLS_CC); FREE_OP1_IF_VAR(); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HELPER(zend_send_by_var_helper, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval *varptr; zend_free_op free_op1; varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -2613,7 +2891,7 @@ zval *original_var = varptr; ALLOC_ZVAL(varptr); - *varptr = *original_var; + ZVAL_COPY_VALUE(varptr, original_var); Z_UNSET_ISREF_P(varptr); Z_SET_REFCOUNT_P(varptr, 0); zval_copy_ctor(varptr); @@ -2622,34 +2900,36 @@ zend_vm_stack_push(varptr TSRMLS_CC); FREE_OP1(); /* for string offsets */ + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; zval *varptr; + SAVE_OPLINE(); if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) { /* Had function_ptr at compile_time */ if (!(opline->extended_value & ZEND_ARG_SEND_BY_REF)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } - } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { + } else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } if (OP1_TYPE == IS_VAR && (opline->extended_value & ZEND_ARG_SEND_FUNCTION) && - EX_T(opline->op1.u.var).var.fcall_returned_reference && - EX_T(opline->op1.u.var).var.ptr) { - varptr = EX_T(opline->op1.u.var).var.ptr; + EX_T(opline->op1.var).var.fcall_returned_reference && + EX_T(opline->op1.var).var.ptr) { + varptr = EX_T(opline->op1.var).var.ptr; PZVAL_UNLOCK_EX(varptr, &free_op1, 0); } else { varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); } if ((!(opline->extended_value & ZEND_ARG_SEND_FUNCTION) || - EX_T(opline->op1.u.var).var.fcall_returned_reference) && + EX_T(opline->op1.var).var.fcall_returned_reference) && varptr != &EG(uninitialized_zval) && (PZVAL_IS_REF(varptr) || (Z_REFCOUNT_P(varptr) == 1 && (OP1_TYPE == IS_CV || free_op1.var)))) { @@ -2661,7 +2941,7 @@ if ((opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) ? !(opline->extended_value & ZEND_ARG_SEND_SILENT) : - !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { + !ARG_MAY_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { zend_error(E_STRICT, "Only variables should be passed by reference"); } ALLOC_ZVAL(valptr); @@ -2672,24 +2952,27 @@ zend_vm_stack_push(valptr TSRMLS_CC); } FREE_OP1_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; zval **varptr_ptr; zval *varptr; + + SAVE_OPLINE(); varptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (OP1_TYPE == IS_VAR && !varptr_ptr) { + if (OP1_TYPE == IS_VAR && UNEXPECTED(varptr_ptr == NULL)) { zend_error_noreturn(E_ERROR, "Only variables can be passed by reference"); } - if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); - } + if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { + ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); + } SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr); varptr = *varptr_ptr; @@ -2697,68 +2980,77 @@ zend_vm_stack_push(varptr TSRMLS_CC); FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(66, ZEND_SEND_VAR, VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE if ((opline->extended_value == ZEND_DO_FCALL_BY_NAME) - && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) { + && ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.opline_num)) { ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } + SAVE_OPLINE(); ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper); } ZEND_VM_HANDLER(63, ZEND_RECV, ANY, ANY) { - zend_op *opline = EX(opline); - zend_uint arg_num = Z_LVAL(opline->op1.u.constant); + USE_OPLINE + zend_uint arg_num = opline->op1.num; zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); - if (param == NULL) { - char *space; - char *class_name = get_active_class_name(&space TSRMLS_CC); - zend_execute_data *ptr = EX(prev_execute_data); + SAVE_OPLINE(); + if (UNEXPECTED(param == NULL)) { + if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { + char *space; + char *class_name; + zend_execute_data *ptr; + + if (EG(active_op_array)->scope) { + class_name = EG(active_op_array)->scope->name; + space = "::"; + } else { + class_name = space = ""; + } + ptr = EX(prev_execute_data); - if (zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, NULL, opline->extended_value TSRMLS_CC)) { if(ptr && ptr->op_array) { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s(), called in %s on line %d and defined", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); + zend_error(E_WARNING, "Missing argument %u for %s%s%s(), called in %s on line %d and defined", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C), ptr->op_array->filename, ptr->opline->lineno); } else { - zend_error(E_WARNING, "Missing argument %ld for %s%s%s()", opline->op1.u.constant.value.lval, class_name, space, get_active_function_name(TSRMLS_C)); + zend_error(E_WARNING, "Missing argument %u for %s%s%s()", opline->op1.num, class_name, space, get_active_function_name(TSRMLS_C)); } } - if (opline->result.op_type == IS_VAR) { - PZVAL_UNLOCK_FREE(*EX_T(opline->result.u.var).var.ptr_ptr); - } } else { - zend_free_op free_res; zval **var_ptr; zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC); - var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W); + var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC); Z_DELREF_PP(var_ptr); *var_ptr = *param; Z_ADDREF_PP(var_ptr); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST) { - zend_op *opline = EX(opline); + USE_OPLINE zval *assignment_value; - zend_uint arg_num = Z_LVAL(opline->op1.u.constant); - zend_free_op free_res; + zend_uint arg_num = opline->op1.num; zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC); zval **var_ptr; + SAVE_OPLINE(); if (param == NULL) { ALLOC_ZVAL(assignment_value); - *assignment_value = opline->op2.u.constant; - if ((Z_TYPE(opline->op2.u.constant) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE(opline->op2.u.constant)==IS_CONSTANT_ARRAY) { + *assignment_value = *opline->op2.zv; + if ((Z_TYPE_P(assignment_value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || + Z_TYPE_P(assignment_value)==IS_CONSTANT_ARRAY) { Z_SET_REFCOUNT_P(assignment_value, 1); zval_update_constant(&assignment_value, 0 TSRMLS_CC); } else { @@ -2771,46 +3063,51 @@ } zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, assignment_value, opline->extended_value TSRMLS_CC); - var_ptr = get_zval_ptr_ptr(&opline->result, EX(Ts), &free_res, BP_VAR_W); + var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(EX_CVs(), opline->result.var TSRMLS_CC); Z_DELREF_PP(var_ptr); *var_ptr = assignment_value; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; + zval *retval = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); /* PHP 3.0 returned "" for false and 1 for true, here we use 0 and 1 for now */ - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = i_zend_is_true(GET_OP1_ZVAL_PTR(BP_VAR_R)); - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_BOOL; + ZVAL_BOOL(retval, i_zend_is_true(GET_OP1_ZVAL_PTR(BP_VAR_R))); FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(50, ZEND_BRK, ANY, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op2; zend_brk_cont_element *el; - el = zend_brk_cont(GET_OP2_ZVAL_PTR(BP_VAR_R), opline->op1.u.opline_num, - EX(op_array), EX(Ts) TSRMLS_CC); + SAVE_OPLINE(); + el = zend_brk_cont(GET_OP2_ZVAL_PTR(BP_VAR_R), opline->op1.opline_num, + EX(op_array), EX_Ts() TSRMLS_CC); FREE_OP2(); ZEND_VM_JMP(EX(op_array)->opcodes + el->brk); } ZEND_VM_HANDLER(51, ZEND_CONT, ANY, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op2; zend_brk_cont_element *el; - el = zend_brk_cont(GET_OP2_ZVAL_PTR(BP_VAR_R), opline->op1.u.opline_num, - EX(op_array), EX(Ts) TSRMLS_CC); + SAVE_OPLINE(); + el = zend_brk_cont(GET_OP2_ZVAL_PTR(BP_VAR_R), opline->op1.opline_num, + EX(op_array), EX_Ts() TSRMLS_CC); FREE_OP2(); ZEND_VM_JMP(EX(op_array)->opcodes + el->cont); } @@ -2818,44 +3115,46 @@ ZEND_VM_HANDLER(100, ZEND_GOTO, ANY, CONST) { zend_op *brk_opline; - zend_op *opline = EX(opline); + USE_OPLINE zend_brk_cont_element *el; - el = zend_brk_cont(&opline->op2.u.constant, opline->extended_value, - EX(op_array), EX(Ts) TSRMLS_CC); + SAVE_OPLINE(); + el = zend_brk_cont(opline->op2.zv, opline->extended_value, + EX(op_array), EX_Ts() TSRMLS_CC); brk_opline = EX(op_array)->opcodes + el->brk; switch (brk_opline->opcode) { case ZEND_SWITCH_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zend_switch_free(&EX_T(brk_opline->op1.var), brk_opline->extended_value TSRMLS_CC); } break; case ZEND_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zendi_zval_dtor(EX_T(brk_opline->op1.var).tmp_var); } break; } - ZEND_VM_JMP(opline->op1.u.jmp_addr); + ZEND_VM_JMP(opline->op1.jmp_addr); } ZEND_VM_HANDLER(48, ZEND_CASE, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE int switch_expr_is_overloaded=0; zend_free_op free_op1, free_op2; + SAVE_OPLINE(); if (OP1_TYPE==IS_VAR) { - if (EX_T(opline->op1.u.var).var.ptr_ptr) { - PZVAL_LOCK(EX_T(opline->op1.u.var).var.ptr); + if (EX_T(opline->op1.var).var.ptr_ptr) { + PZVAL_LOCK(EX_T(opline->op1.var).var.ptr); } else { switch_expr_is_overloaded = 1; - Z_ADDREF_P(EX_T(opline->op1.u.var).str_offset.str); + Z_ADDREF_P(EX_T(opline->op1.var).str_offset.str); } } - is_equal_function(&EX_T(opline->result.u.var).tmp_var, + is_equal_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); @@ -2867,53 +3166,57 @@ * are allocated at each get_zval_ptr()) */ FREE_OP1(); - EX_T(opline->op1.u.var).var.ptr_ptr = NULL; - EX_T(opline->op1.u.var).var.ptr = NULL; + EX_T(opline->op1.var).var.ptr_ptr = NULL; + EX_T(opline->op1.var).var.ptr = NULL; } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(49, ZEND_SWITCH_FREE, VAR, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - zend_switch_free(&EX_T(opline->op1.u.var), opline->extended_value TSRMLS_CC); + SAVE_OPLINE(); + zend_switch_free(&EX_T(opline->op1.var), opline->extended_value TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(68, ZEND_NEW, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval *object_zval; zend_function *constructor; - if (EX_T(opline->op1.u.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + SAVE_OPLINE(); + if (UNEXPECTED((EX_T(opline->op1.var).class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0)) { char *class_type; - if (EX_T(opline->op1.u.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) { + if (EX_T(opline->op1.var).class_entry->ce_flags & ZEND_ACC_INTERFACE) { class_type = "interface"; } else { class_type = "abstract class"; } - zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.u.var).class_entry->name); + zend_error_noreturn(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(opline->op1.var).class_entry->name); } ALLOC_ZVAL(object_zval); - object_init_ex(object_zval, EX_T(opline->op1.u.var).class_entry); + object_init_ex(object_zval, EX_T(opline->op1.var).class_entry); INIT_PZVAL(object_zval); constructor = Z_OBJ_HT_P(object_zval)->get_constructor(object_zval TSRMLS_CC); if (constructor == NULL) { if (RETURN_VALUE_USED(opline)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, object_zval); + AI_SET_PTR(&EX_T(opline->result.var), object_zval); } else { zval_ptr_dtor(&object_zval); } - ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes + opline->op2.opline_num); } else { if (RETURN_VALUE_USED(opline)) { - AI_SET_PTR(EX_T(opline->result.u.var).var, object_zval); PZVAL_LOCK(object_zval); + AI_SET_PTR(&EX_T(opline->result.var), object_zval); } zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), ENCODE_CTOR(EX(called_scope), RETURN_VALUE_USED(opline))); @@ -2921,31 +3224,35 @@ /* We are not handling overloaded classes right now */ EX(object) = object_zval; EX(fbc) = constructor; - EX(called_scope) = EX_T(opline->op1.u.var).class_entry; + EX(called_scope) = EX_T(opline->op1.var).class_entry; + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } } ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMP|VAR|UNUSED|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *obj = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); + zval *obj; zend_class_entry *ce; zend_function *clone; zend_object_clone_obj_t clone_call; + SAVE_OPLINE(); + obj = GET_OP1_OBJ_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE == IS_CONST || - (OP1_TYPE == IS_VAR && !obj) || - Z_TYPE_P(obj) != IS_OBJECT) { + (OP1_TYPE == IS_VAR && UNEXPECTED(obj == NULL)) || + UNEXPECTED(Z_TYPE_P(obj) != IS_OBJECT)) { zend_error_noreturn(E_ERROR, "__clone method called on non-object"); } ce = Z_OBJCE_P(obj); clone = ce ? ce->clone : NULL; clone_call = Z_OBJ_HT_P(obj)->clone_obj; - if (!clone_call) { + if (UNEXPECTED(clone_call == NULL)) { if (ce) { zend_error_noreturn(E_ERROR, "Trying to clone an uncloneable object of class %s", ce->name); } else { @@ -2957,55 +3264,60 @@ if (clone->op_array.fn_flags & ZEND_ACC_PRIVATE) { /* Ensure that if we're calling a private function, we're allowed to do so. */ - if (ce != EG(scope)) { + if (UNEXPECTED(ce != EG(scope))) { zend_error_noreturn(E_ERROR, "Call to private %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); } } else if ((clone->common.fn_flags & ZEND_ACC_PROTECTED)) { /* Ensure that if we're calling a protected function, we're allowed to do so. */ - if (!zend_check_protected(clone->common.scope, EG(scope))) { + if (UNEXPECTED(!zend_check_protected(clone->common.scope, EG(scope)))) { zend_error_noreturn(E_ERROR, "Call to protected %s::__clone() from context '%s'", ce->name, EG(scope) ? EG(scope)->name : ""); } } } - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - if (!EG(exception)) { - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); - Z_OBJVAL_P(EX_T(opline->result.u.var).var.ptr) = clone_call(obj TSRMLS_CC); - Z_TYPE_P(EX_T(opline->result.u.var).var.ptr) = IS_OBJECT; - Z_SET_REFCOUNT_P(EX_T(opline->result.u.var).var.ptr, 1); - Z_SET_ISREF_P(EX_T(opline->result.u.var).var.ptr); - if (!RETURN_VALUE_USED(opline) || EG(exception)) { - zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr); + if (EXPECTED(EG(exception) == NULL)) { + zval *retval; + + ALLOC_ZVAL(retval); + Z_OBJVAL_P(retval) = clone_call(obj TSRMLS_CC); + Z_TYPE_P(retval) = IS_OBJECT; + Z_SET_REFCOUNT_P(retval, 1); + Z_SET_ISREF_P(retval); + if (!RETURN_VALUE_USED(opline) || UNEXPECTED(EG(exception) != NULL)) { + zval_ptr_dtor(&retval); + } else { + AI_SET_PTR(&EX_T(opline->result.var), retval); } } FREE_OP1_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST) { - zend_op *opline = EX(opline); + USE_OPLINE + SAVE_OPLINE(); if (OP1_TYPE == IS_UNUSED) { /* namespaced constant */ - if (!zend_get_constant_ex(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), &EX_T(opline->result.u.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) { + if (!zend_get_constant_ex(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), &EX_T(opline->result.var).tmp_var, NULL, opline->extended_value TSRMLS_CC)) { if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) { - char *actual = (char *)zend_memrchr(Z_STRVAL(opline->op2.u.constant), '\\', Z_STRLEN(opline->op2.u.constant)); + char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv)); if(!actual) { - actual = Z_STRVAL(opline->op2.u.constant); + actual = Z_STRVAL_P(opline->op2.zv); } else { actual++; } /* non-qualified constant - allow text substitution */ zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", actual, actual); - ZVAL_STRINGL(&EX_T(opline->result.u.var).tmp_var, actual, Z_STRLEN(opline->op2.u.constant)-(actual - Z_STRVAL(opline->op2.u.constant)), 1); + ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, actual, Z_STRLEN_P(opline->op2.zv)-(actual - Z_STRVAL_P(opline->op2.zv)), 1); } else { - zend_error_noreturn(E_ERROR, "Undefined constant '%s'", - Z_STRVAL(opline->op2.u.constant), Z_STRVAL(opline->op2.u.constant)); + zend_error_noreturn(E_ERROR, "Undefined constant '%s'", Z_STRVAL_P(opline->op2.zv)); } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } else { /* class constant */ @@ -3014,15 +3326,15 @@ if (OP1_TYPE == IS_CONST) { - ce = zend_fetch_class(Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), opline->extended_value TSRMLS_CC); - if (!ce) { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, opline->extended_value TSRMLS_CC); + if (UNEXPECTED(ce == NULL)) { + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); } } else { - ce = EX_T(opline->op1.u.var).class_entry; + ce = EX_T(opline->op1.var).class_entry; } - if (zend_hash_find(&ce->constants_table, Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void **) &value) == SUCCESS) { + if (EXPECTED(zend_hash_quick_find(&ce->constants_table, Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void **) &value) == SUCCESS)) { if (Z_TYPE_PP(value) == IS_CONSTANT_ARRAY || (Z_TYPE_PP(value) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { zend_class_entry *old_scope = EG(scope); @@ -3031,52 +3343,39 @@ zval_update_constant(value, (void *) 1 TSRMLS_CC); EG(scope) = old_scope; } - EX_T(opline->result.u.var).tmp_var = **value; - zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value); + zval_copy_ctor(&EX_T(opline->result.var).tmp_var); } else { - zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL(opline->op2.u.constant)); + zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv)); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } } ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); - zend_free_op free_op1, free_op2; - zval *array_ptr = &EX_T(opline->result.u.var).tmp_var; + USE_OPLINE + zend_free_op free_op1; zval *expr_ptr; - zval *offset=GET_OP2_ZVAL_PTR(BP_VAR_R); -#if !defined(ZEND_VM_SPEC) || OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV - zval **expr_ptr_ptr = NULL; + SAVE_OPLINE(); + if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) && opline->extended_value) { + zval **expr_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); - if (opline->extended_value) { - expr_ptr_ptr=GET_OP1_ZVAL_PTR_PTR(BP_VAR_W); + SEPARATE_ZVAL_TO_MAKE_IS_REF(expr_ptr_ptr); expr_ptr = *expr_ptr_ptr; + Z_ADDREF_P(expr_ptr); } else { expr_ptr=GET_OP1_ZVAL_PTR(BP_VAR_R); - } -#else - expr_ptr=GET_OP1_ZVAL_PTR(BP_VAR_R); -#endif + if (IS_OP1_TMP_FREE()) { /* temporary variable */ + zval *new_expr; - if (IS_OP1_TMP_FREE()) { /* temporary variable */ - zval *new_expr; - - ALLOC_ZVAL(new_expr); - INIT_PZVAL_COPY(new_expr, expr_ptr); - expr_ptr = new_expr; - } else { -#if !defined(ZEND_VM_SPEC) || OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV - if (opline->extended_value) { - SEPARATE_ZVAL_TO_MAKE_IS_REF(expr_ptr_ptr); - expr_ptr = *expr_ptr_ptr; - Z_ADDREF_P(expr_ptr); - } else -#endif - if (OP1_TYPE == IS_CONST || PZVAL_IS_REF(expr_ptr)) { + ALLOC_ZVAL(new_expr); + INIT_PZVAL_COPY(new_expr, expr_ptr); + expr_ptr = new_expr; + } else if (OP1_TYPE == IS_CONST || PZVAL_IS_REF(expr_ptr)) { zval *new_expr; ALLOC_ZVAL(new_expr); @@ -3087,20 +3386,38 @@ Z_ADDREF_P(expr_ptr); } } - if (offset) { + + if (OP2_TYPE != IS_UNUSED) { + zend_free_op free_op2; + zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + ulong hval; + long index; + switch (Z_TYPE_P(offset)) { case IS_DOUBLE: - zend_hash_index_update(Z_ARRVAL_P(array_ptr), zend_dval_to_lval(Z_DVAL_P(offset)), &expr_ptr, sizeof(zval *), NULL); - break; + index = zend_dval_to_lval(Z_DVAL_P(offset)); + ZEND_VM_C_GOTO(num_index); case IS_LONG: case IS_BOOL: - zend_hash_index_update(Z_ARRVAL_P(array_ptr), Z_LVAL_P(offset), &expr_ptr, sizeof(zval *), NULL); + index = Z_LVAL_P(offset); +ZEND_VM_C_LABEL(num_index): + zend_hash_index_update(Z_ARRVAL(EX_T(opline->result.var).tmp_var), index, &expr_ptr, sizeof(zval *), NULL); break; case IS_STRING: - zend_symtable_update(Z_ARRVAL_P(array_ptr), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, &expr_ptr, sizeof(zval *), NULL); + if (OP2_TYPE == IS_CONST) { + hval = Z_HASH_P(offset); + } else { + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, index, ZEND_VM_C_GOTO(num_index)); + if (IS_INTERNED(Z_STRVAL_P(offset))) { + hval = INTERNED_HASH(Z_STRVAL_P(offset)); + } else { + hval = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + } + } + zend_hash_quick_update(Z_ARRVAL(EX_T(opline->result.var).tmp_var), Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hval, &expr_ptr, sizeof(zval *), NULL); break; case IS_NULL: - zend_hash_update(Z_ARRVAL_P(array_ptr), "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); + zend_hash_update(Z_ARRVAL(EX_T(opline->result.var).tmp_var), "", sizeof(""), &expr_ptr, sizeof(zval *), NULL); break; default: zend_error(E_WARNING, "Illegal offset type"); @@ -3110,21 +3427,22 @@ } FREE_OP2(); } else { - zend_hash_next_index_insert(Z_ARRVAL_P(array_ptr), &expr_ptr, sizeof(zval *), NULL); + zend_hash_next_index_insert(Z_ARRVAL(EX_T(opline->result.var).tmp_var), &expr_ptr, sizeof(zval *), NULL); } - if (opline->extended_value) { + if ((OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) && opline->extended_value) { FREE_OP1_VAR_PTR(); } else { FREE_OP1_IF_VAR(); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(71, ZEND_INIT_ARRAY, CONST|TMP|VAR|UNUSED|CV, CONST|TMP|VAR|UNUSED|CV) { - zend_op *opline = EX(opline); + USE_OPLINE - array_init(&EX_T(opline->result.u.var).tmp_var); + array_init(&EX_T(opline->result.var).tmp_var); if (OP1_TYPE == IS_UNUSED) { ZEND_VM_NEXT_OPCODE(); #if !defined(ZEND_VM_SPEC) || OP1_TYPE != IS_UNUSED @@ -3136,13 +3454,16 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *expr = GET_OP1_ZVAL_PTR(BP_VAR_R); - zval *result = &EX_T(opline->result.u.var).tmp_var; + zval *expr; + zval *result = &EX_T(opline->result.var).tmp_var; + SAVE_OPLINE(); + expr = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (opline->extended_value != IS_STRING) { - *result = *expr; + ZVAL_COPY_VALUE(result, expr); if (!IS_OP1_TMP_FREE()) { zendi_zval_copy_ctor(*result); } @@ -3166,12 +3487,12 @@ zend_make_printable_zval(expr, &var_copy, &use_copy); if (use_copy) { - *result = var_copy; + ZVAL_COPY_VALUE(result, &var_copy); if (IS_OP1_TMP_FREE()) { FREE_OP1(); } } else { - *result = *expr; + ZVAL_COPY_VALUE(result, expr); if (!IS_OP1_TMP_FREE()) { zendi_zval_copy_ctor(*result); } @@ -3186,29 +3507,30 @@ break; } FREE_OP1_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_op_array *new_op_array=NULL; - int return_value_used; zend_free_op free_op1; - zval *inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *inc_filename; zval tmp_inc_filename; zend_bool failure_retval=0; + SAVE_OPLINE(); + inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (inc_filename->type!=IS_STRING) { - tmp_inc_filename = *inc_filename; + ZVAL_COPY_VALUE(&tmp_inc_filename, inc_filename); zval_copy_ctor(&tmp_inc_filename); convert_to_string(&tmp_inc_filename); inc_filename = &tmp_inc_filename; } - return_value_used = RETURN_VALUE_USED(opline); - - switch (Z_LVAL(opline->op2.u.constant)) { + switch (opline->extended_value) { case ZEND_INCLUDE_ONCE: case ZEND_REQUIRE_ONCE: { zend_file_handle file_handle; @@ -3230,14 +3552,14 @@ } if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) { - new_op_array = zend_compile_file(&file_handle, (Z_LVAL(opline->op2.u.constant)==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); + new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); zend_destroy_file_handle(&file_handle TSRMLS_CC); } else { zend_file_handle_dtor(&file_handle TSRMLS_CC); failure_retval=1; } } else { - if (Z_LVAL(opline->op2.u.constant)==ZEND_INCLUDE_ONCE) { + if (opline->extended_value == ZEND_INCLUDE_ONCE) { zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC); } else { zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC); @@ -3250,7 +3572,7 @@ break; case ZEND_INCLUDE: case ZEND_REQUIRE: - new_op_array = compile_filename(Z_LVAL(opline->op2.u.constant), inc_filename TSRMLS_CC); + new_op_array = compile_filename(opline->extended_value, inc_filename TSRMLS_CC); break; case ZEND_EVAL: { char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC); @@ -3265,12 +3587,18 @@ zval_dtor(&tmp_inc_filename); } FREE_OP1(); - EX_T(opline->result.u.var).var.ptr_ptr = &EX_T(opline->result.u.var).var.ptr; - if (new_op_array && !EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { + HANDLE_EXCEPTION(); + } else if (EXPECTED(new_op_array != NULL)) { EX(original_return_value) = EG(return_value_ptr_ptr); - EG(return_value_ptr_ptr) = return_value_used ? EX_T(opline->result.u.var).var.ptr_ptr : NULL; EG(active_op_array) = new_op_array; - EX_T(opline->result.u.var).var.ptr = NULL; + if (RETURN_VALUE_USED(opline)) { + EX_T(opline->result.var).var.ptr = NULL; + EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr; + EG(return_value_ptr_ptr) = EX_T(opline->result.var).var.ptr_ptr; + } else { + EG(return_value_ptr_ptr) = NULL; + } EX(current_object) = EX(object); @@ -3281,8 +3609,7 @@ zend_rebuild_symbol_table(TSRMLS_C); } - if (zend_execute == execute) { - EX(call_opline) = opline; + if (EXPECTED(zend_execute == execute)) { ZEND_VM_ENTER(); } else { zend_execute(new_op_array TSRMLS_CC); @@ -3291,75 +3618,62 @@ EX(function_state).function = (zend_function *) EX(op_array); EX(object) = EX(current_object); - if (return_value_used) { - if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */ - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); - INIT_PZVAL(EX_T(opline->result.u.var).var.ptr); - Z_LVAL_P(EX_T(opline->result.u.var).var.ptr) = 1; - Z_TYPE_P(EX_T(opline->result.u.var).var.ptr) = IS_BOOL; - } - } - EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); EG(return_value_ptr_ptr) = EX(original_return_value); destroy_op_array(new_op_array TSRMLS_CC); efree(new_op_array); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); + HANDLE_EXCEPTION(); + } else if (RETURN_VALUE_USED(opline)) { + if (!EX_T(opline->result.var).var.ptr) { /* there was no return statement */ + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_BOOL(retval, 1); + INIT_PZVAL(retval); + EX_T(opline->result.var).var.ptr = retval; + } } - } else { - if (return_value_used) { - ALLOC_ZVAL(EX_T(opline->result.u.var).var.ptr); - INIT_ZVAL(*EX_T(opline->result.u.var).var.ptr); - Z_LVAL_P(EX_T(opline->result.u.var).var.ptr) = failure_retval; - Z_TYPE_P(EX_T(opline->result.u.var).var.ptr) = IS_BOOL; - } + + } else if (RETURN_VALUE_USED(opline)) { + zval *retval; + + ALLOC_ZVAL(retval); + ZVAL_BOOL(retval, failure_retval); + INIT_PZVAL(retval); + AI_SET_PTR(&EX_T(opline->result.var), retval); } ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval tmp, *varname; HashTable *target_symbol_table; zend_free_op free_op1; + SAVE_OPLINE(); if (OP1_TYPE == IS_CV && (opline->extended_value & ZEND_QUICK_SET)) { if (EG(active_symbol_table)) { - zend_execute_data *ex = EX(prev_execute_data); - zend_compiled_variable *cv = &CV_DEF_OF(opline->op1.u.var); + zend_compiled_variable *cv = &CV_DEF_OF(opline->op1.var); - if (zend_hash_quick_del(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value) == SUCCESS) { - while (ex && ex->symbol_table == EG(active_symbol_table)) { - int i; - - if (ex->op_array) { - for (i = 0; i < ex->op_array->last_var; i++) { - if (ex->op_array->vars[i].hash_value == cv->hash_value && - ex->op_array->vars[i].name_len == cv->name_len && - !memcmp(ex->op_array->vars[i].name, cv->name, cv->name_len)) { - ex->CVs[i] = NULL; - break; - } - } - } - ex = ex->prev_execute_data; - } - } - EX(CVs)[opline->op1.u.var] = NULL; - } else if (EX(CVs)[opline->op1.u.var]) { - zval_ptr_dtor(EX(CVs)[opline->op1.u.var]); - EX(CVs)[opline->op1.u.var] = NULL; + zend_delete_variable(EX(prev_execute_data), EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value TSRMLS_CC); + EX_CV(opline->op1.var) = NULL; + } else if (EX_CV(opline->op1.var)) { + zval_ptr_dtor(EX_CV(opline->op1.var)); + EX_CV(opline->op1.var) = NULL; } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } varname = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (Z_TYPE_P(varname) != IS_STRING) { - tmp = *varname; + if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { + ZVAL_COPY_VALUE(&tmp, varname); zval_copy_ctor(&tmp); convert_to_string(&tmp); varname = &tmp; @@ -3367,49 +3681,38 @@ Z_ADDREF_P(varname); } - if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) { - zend_std_unset_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname) TSRMLS_CC); + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC_MEMBER) { + zend_std_unset_static_property(EX_T(opline->op2.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), ((OP1_TYPE == IS_CONST) ? opline->op1.literal : NULL) TSRMLS_CC); } else { ulong hash_value = zend_inline_hash_func(varname->value.str.val, varname->value.str.len+1); - target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); - if (zend_hash_quick_del(target_symbol_table, varname->value.str.val, varname->value.str.len+1, hash_value) == SUCCESS) { - zend_execute_data *ex = EXECUTE_DATA; - - do { - int i; - - if (ex->op_array) { - for (i = 0; i < ex->op_array->last_var; i++) { - if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == varname->value.str.len && - !memcmp(ex->op_array->vars[i].name, varname->value.str.val, varname->value.str.len)) { - ex->CVs[i] = NULL; - break; - } - } - } - ex = ex->prev_execute_data; - } while (ex && ex->symbol_table == target_symbol_table); - } + target_symbol_table = zend_get_target_symbol_table(opline->extended_value & ZEND_FETCH_TYPE_MASK TSRMLS_CC); + zend_delete_variable(EXECUTE_DATA, target_symbol_table, varname->value.str.val, varname->value.str.len+1, hash_value TSRMLS_CC); } - if (varname == &tmp) { + if (OP1_TYPE != IS_CONST && varname == &tmp) { zval_dtor(&tmp); } else if (OP1_TYPE == IS_VAR || OP1_TYPE == IS_CV) { zval_ptr_dtor(&varname); } FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); - zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval **container; + zval *offset; + ulong hval; + long index; + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); + offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE != IS_VAR || container) { if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) { SEPARATE_ZVAL_IF_NOT_REF(container); @@ -3420,37 +3723,34 @@ switch (Z_TYPE_P(offset)) { case IS_DOUBLE: - zend_hash_index_del(ht, zend_dval_to_lval(Z_DVAL_P(offset))); - break; + index = zend_dval_to_lval(Z_DVAL_P(offset)); + ZEND_VM_C_GOTO(num_index_dim); case IS_RESOURCE: case IS_BOOL: case IS_LONG: - zend_hash_index_del(ht, Z_LVAL_P(offset)); +ZEND_VM_C_LABEL(num_index_dim): + index = Z_LVAL_P(offset); + zend_hash_index_del(ht, index); break; case IS_STRING: if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { Z_ADDREF_P(offset); } - if (zend_symtable_del(ht, offset->value.str.val, offset->value.str.len+1) == SUCCESS && - ht == &EG(symbol_table)) { - zend_execute_data *ex; - ulong hash_value = zend_inline_hash_func(offset->value.str.val, offset->value.str.len+1); - - for (ex = EXECUTE_DATA; ex; ex = ex->prev_execute_data) { - if (ex->op_array && ex->symbol_table == ht) { - int i; - - for (i = 0; i < ex->op_array->last_var; i++) { - if (ex->op_array->vars[i].hash_value == hash_value && - ex->op_array->vars[i].name_len == offset->value.str.len && - !memcmp(ex->op_array->vars[i].name, offset->value.str.val, offset->value.str.len)) { - ex->CVs[i] = NULL; - break; - } - } - } + if (OP2_TYPE == IS_CONST) { + hval = Z_HASH_P(offset); + } else { + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, index, ZEND_VM_C_GOTO(num_index_dim)); + if (IS_INTERNED(Z_STRVAL_P(offset))) { + hval = INTERNED_HASH(Z_STRVAL_P(offset)); + } else { + hval = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); } } + if (ht == &EG(symbol_table)) { + zend_delete_global_variable_ex(offset->value.str.val, offset->value.str.len, hval TSRMLS_CC); + } else { + zend_hash_quick_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hval); + } if (OP2_TYPE == IS_CV || OP2_TYPE == IS_VAR) { zval_ptr_dtor(&offset); } @@ -3466,7 +3766,7 @@ break; } case IS_OBJECT: - if (!Z_OBJ_HT_P(*container)->unset_dimension) { + if (UNEXPECTED(Z_OBJ_HT_P(*container)->unset_dimension == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use object as array"); } if (IS_OP2_TMP_FREE()) { @@ -3491,16 +3791,21 @@ } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(76, ZEND_UNSET_OBJ, VAR|UNUSED|CV, CONST|TMP|VAR|CV) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); - zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval **container; + zval *offset; + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_UNSET); + offset = GET_OP2_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE != IS_VAR || container) { if (OP1_TYPE == IS_CV && container != &EG(uninitialized_zval_ptr)) { SEPARATE_ZVAL_IF_NOT_REF(container); @@ -3510,7 +3815,7 @@ MAKE_REAL_ZVAL_PTR(offset); } if (Z_OBJ_HT_P(*container)->unset_property) { - Z_OBJ_HT_P(*container)->unset_property(*container, offset TSRMLS_CC); + Z_OBJ_HT_P(*container)->unset_property(*container, offset, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); } else { zend_error(E_NOTICE, "Trying to unset property of non-object"); } @@ -3527,12 +3832,13 @@ } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; zval *array_ptr, **array_ptr_ptr; HashTable *fe_ht; @@ -3540,14 +3846,17 @@ zend_class_entry *ce = NULL; zend_bool is_empty = 0; + SAVE_OPLINE(); + if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { array_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); if (array_ptr_ptr == NULL || array_ptr_ptr == &EG(uninitialized_zval_ptr)) { - ALLOC_INIT_ZVAL(array_ptr); + MAKE_STD_ZVAL(array_ptr); + ZVAL_NULL(array_ptr); } else if (Z_TYPE_PP(array_ptr_ptr) == IS_OBJECT) { if(Z_OBJ_HT_PP(array_ptr_ptr)->get_class_entry == NULL) { zend_error(E_WARNING, "foreach() cannot iterate over objects without PHP class"); - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } ce = Z_OBJCE_PP(array_ptr_ptr); @@ -3603,7 +3912,7 @@ if (ce && ce->get_iterator) { iter = ce->get_iterator(ce, array_ptr, opline->extended_value & ZEND_FE_RESET_REFERENCE TSRMLS_CC); - if (iter && !EG(exception)) { + if (iter && EXPECTED(EG(exception) == NULL)) { array_ptr = zend_iterator_wrap(iter TSRMLS_CC); } else { if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { @@ -3615,18 +3924,18 @@ zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Object of type %s did not create an Iterator", ce->name); } zend_throw_exception_internal(NULL TSRMLS_CC); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } } - AI_SET_PTR(EX_T(opline->result.u.var).var, array_ptr); PZVAL_LOCK(array_ptr); + AI_SET_PTR(&EX_T(opline->result.var), array_ptr); if (iter) { iter->index = 0; if (iter->funcs->rewind) { iter->funcs->rewind(iter TSRMLS_CC); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array_ptr); zval_ptr_dtor(&array_ptr); if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { @@ -3634,11 +3943,11 @@ } else { FREE_OP1_IF_VAR(); } - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } } is_empty = iter->funcs->valid(iter TSRMLS_CC) != SUCCESS; - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array_ptr); zval_ptr_dtor(&array_ptr); if (opline->extended_value & ZEND_FE_RESET_VARIABLE) { @@ -3646,7 +3955,7 @@ } else { FREE_OP1_IF_VAR(); } - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } iter->index = -1; /* will be set to 0 before using next handler */ } else if ((fe_ht = HASH_OF(array_ptr)) != NULL) { @@ -3669,7 +3978,7 @@ } } is_empty = zend_hash_has_more_elements(fe_ht) != SUCCESS; - zend_hash_get_pointer(fe_ht, &EX_T(opline->result.u.var).fe.fe_pos); + zend_hash_get_pointer(fe_ht, &EX_T(opline->result.var).fe.fe_pos); } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); is_empty = 1; @@ -3681,17 +3990,18 @@ FREE_OP1_IF_VAR(); } if (is_empty) { - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } else { + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } } ZEND_VM_HANDLER(78, ZEND_FE_FETCH, VAR, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *array = EX_T(opline->op1.u.var).var.ptr; + zval *array = EX_T(opline->op1.var).var.ptr; zval **value; char *str_key; uint str_key_len; @@ -3701,22 +4011,24 @@ int key_type = 0; zend_bool use_key = (zend_bool)(opline->extended_value & ZEND_FE_FETCH_WITH_KEY); + SAVE_OPLINE(); + switch (zend_iterator_unwrap(array, &iter TSRMLS_CC)) { default: case ZEND_ITER_INVALID: zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); case ZEND_ITER_PLAIN_OBJECT: { char *class_name, *prop_name; zend_object *zobj = zend_objects_get_address(array TSRMLS_CC); - fe_ht = HASH_OF(array); - zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.u.var).fe.fe_pos); + fe_ht = Z_OBJPROP_P(array); + zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); do { if (zend_hash_get_current_data(fe_ht, (void **) &value)==FAILURE) { /* reached end of iteration */ - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 0, NULL); @@ -3724,7 +4036,7 @@ } while (key_type == HASH_KEY_NON_EXISTANT || (key_type != HASH_KEY_IS_LONG && zend_check_property_access(zobj, str_key, str_key_len-1 TSRMLS_CC) != SUCCESS)); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.u.var).fe.fe_pos); + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); if (use_key && key_type != HASH_KEY_IS_LONG) { zend_unmangle_property_name(str_key, str_key_len-1, &class_name, &prop_name); str_key_len = strlen(prop_name); @@ -3735,17 +4047,17 @@ } case ZEND_ITER_PLAIN_ARRAY: - fe_ht = HASH_OF(array); - zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.u.var).fe.fe_pos); + fe_ht = Z_ARRVAL_P(array); + zend_hash_set_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); if (zend_hash_get_current_data(fe_ht, (void **) &value)==FAILURE) { /* reached end of iteration */ - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } if (use_key) { key_type = zend_hash_get_current_key_ex(fe_ht, &str_key, &str_key_len, &int_key, 1, NULL); } zend_hash_move_forward(fe_ht); - zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.u.var).fe.fe_pos); + zend_hash_get_pointer(fe_ht, &EX_T(opline->op1.var).fe.fe_pos); break; case ZEND_ITER_OBJECT: @@ -3754,39 +4066,39 @@ /* This could cause an endless loop if index becomes zero again. * In case that ever happens we need an additional flag. */ iter->funcs->move_forward(iter TSRMLS_CC); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array); zval_ptr_dtor(&array); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } } /* If index is zero we come from FE_RESET and checked valid() already. */ if (!iter || (iter->index > 0 && iter->funcs->valid(iter TSRMLS_CC) == FAILURE)) { /* reached end of iteration */ - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array); zval_ptr_dtor(&array); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } iter->funcs->get_current_data(iter, &value TSRMLS_CC); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array); zval_ptr_dtor(&array); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } if (!value) { /* failure in get_current_data */ - ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.u.opline_num); + ZEND_VM_JMP(EX(op_array)->opcodes+opline->op2.opline_num); } if (use_key) { if (iter->funcs->get_current_key) { key_type = iter->funcs->get_current_key(iter, &str_key, &str_key_len, &int_key TSRMLS_CC); - if (EG(exception)) { + if (UNEXPECTED(EG(exception) != NULL)) { Z_DELREF_P(array); zval_ptr_dtor(&array); - ZEND_VM_NEXT_OPCODE(); + HANDLE_EXCEPTION(); } } else { key_type = HASH_KEY_IS_LONG; @@ -3799,16 +4111,15 @@ if (opline->extended_value & ZEND_FE_FETCH_BYREF) { SEPARATE_ZVAL_IF_NOT_REF(value); Z_SET_ISREF_PP(value); - EX_T(opline->result.u.var).var.ptr_ptr = value; + EX_T(opline->result.var).var.ptr_ptr = value; Z_ADDREF_PP(value); } else { - AI_SET_PTR(EX_T(opline->result.u.var).var, *value); PZVAL_LOCK(*value); + AI_SET_PTR(&EX_T(opline->result.var), *value); } if (use_key) { - zend_op *op_data = opline+1; - zval *key = &EX_T(op_data->result.u.var).tmp_var; + zval *key = &EX_T((opline+1)->result.var).tmp_var; switch (key_type) { case HASH_KEY_IS_STRING: @@ -3827,21 +4138,23 @@ } } + CHECK_EXCEPTION(); ZEND_VM_INC_OPCODE(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(114, ZEND_ISSET_ISEMPTY_VAR, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval **value; zend_bool isset = 1; + SAVE_OPLINE(); if (OP1_TYPE == IS_CV && (opline->extended_value & ZEND_QUICK_SET)) { - if (EX(CVs)[opline->op1.u.var]) { - value = EX(CVs)[opline->op1.u.var]; + if (EX_CV(opline->op1.var)) { + value = EX_CV(opline->op1.var); } else if (EG(active_symbol_table)) { - zend_compiled_variable *cv = &CV_DEF_OF(opline->op1.u.var); + zend_compiled_variable *cv = &CV_DEF_OF(opline->op1.var); if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **) &value) == FAILURE) { isset = 0; @@ -3854,61 +4167,62 @@ zend_free_op free_op1; zval tmp, *varname = GET_OP1_ZVAL_PTR(BP_VAR_IS); - if (Z_TYPE_P(varname) != IS_STRING) { - tmp = *varname; + if (OP1_TYPE != IS_CONST && Z_TYPE_P(varname) != IS_STRING) { + ZVAL_COPY_VALUE(&tmp, varname); zval_copy_ctor(&tmp); convert_to_string(&tmp); varname = &tmp; } - if (opline->op2.u.EA.type == ZEND_FETCH_STATIC_MEMBER) { - value = zend_std_get_static_property(EX_T(opline->op2.u.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), 1 TSRMLS_CC); + if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_STATIC_MEMBER) { + value = zend_std_get_static_property(EX_T(opline->op2.var).class_entry, Z_STRVAL_P(varname), Z_STRLEN_P(varname), 1, ((OP1_TYPE == IS_CONST) ? opline->op1.literal : NULL) TSRMLS_CC); if (!value) { isset = 0; } } else { - target_symbol_table = zend_get_target_symbol_table(opline, EX(Ts), BP_VAR_IS, varname TSRMLS_CC); + target_symbol_table = zend_get_target_symbol_table(opline->extended_value & ZEND_FETCH_TYPE_MASK TSRMLS_CC); if (zend_hash_find(target_symbol_table, varname->value.str.val, varname->value.str.len+1, (void **) &value) == FAILURE) { isset = 0; } } - if (varname == &tmp) { + if (OP1_TYPE != IS_CONST && varname == &tmp) { zval_dtor(&tmp); } FREE_OP1(); } - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_BOOL; - - switch (opline->extended_value & ZEND_ISSET_ISEMPTY_MASK) { - case ZEND_ISSET: - if (isset && Z_TYPE_PP(value) == IS_NULL) { - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = 0; - } else { - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = isset; - } - break; - case ZEND_ISEMPTY: - if (!isset || !i_zend_is_true(*value)) { - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = 1; - } else { - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = 0; - } - break; + if (opline->extended_value & ZEND_ISSET) { + if (isset && Z_TYPE_PP(value) != IS_NULL) { + ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1); + } else { + ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 0); + } + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + if (!isset || !i_zend_is_true(*value)) { + ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 1); + } else { + ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, 0); + } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HELPER_EX(zend_isset_isempty_dim_prop_obj_handler, VAR|UNUSED|CV, CONST|TMP|VAR|CV, int prop_dim) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval **container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_IS); + zval **container; zval **value = NULL; int result = 0; + ulong hval; + long index; + SAVE_OPLINE(); + container = GET_OP1_OBJ_ZVAL_PTR_PTR(BP_VAR_IS); + if (OP1_TYPE != IS_VAR || container) { zend_free_op free_op2; zval *offset = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -3921,19 +4235,31 @@ switch (Z_TYPE_P(offset)) { case IS_DOUBLE: - if (zend_hash_index_find(ht, zend_dval_to_lval(Z_DVAL_P(offset)), (void **) &value) == SUCCESS) { - isset = 1; - } - break; + index = zend_dval_to_lval(Z_DVAL_P(offset)); + ZEND_VM_C_GOTO(num_index_prop); case IS_RESOURCE: case IS_BOOL: case IS_LONG: - if (zend_hash_index_find(ht, Z_LVAL_P(offset), (void **) &value) == SUCCESS) { + index = Z_LVAL_P(offset); +ZEND_VM_C_LABEL(num_index_prop): + if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) { isset = 1; } break; case IS_STRING: - if (zend_symtable_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) { + if (OP2_TYPE == IS_CONST) { + hval = Z_HASH_P(offset); + } else { + if (!prop_dim) { + ZEND_HANDLE_NUMERIC_EX(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, index, ZEND_VM_C_GOTO(num_index_prop)); + } + if (IS_INTERNED(Z_STRVAL_P(offset))) { + hval = INTERNED_HASH(Z_STRVAL_P(offset)); + } else { + hval = zend_hash_func(Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1); + } + } + if (zend_hash_quick_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, hval, (void **) &value) == SUCCESS) { isset = 1; } break; @@ -3948,21 +4274,18 @@ break; } - switch (opline->extended_value) { - case ZEND_ISSET: - if (isset && Z_TYPE_PP(value) == IS_NULL) { - result = 0; - } else { - result = isset; - } - break; - case ZEND_ISEMPTY: - if (!isset || !i_zend_is_true(*value)) { - result = 0; - } else { - result = 1; - } - break; + if (opline->extended_value & ZEND_ISSET) { + if (isset && Z_TYPE_PP(value) == IS_NULL) { + result = 0; + } else { + result = isset; + } + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + if (!isset || !i_zend_is_true(*value)) { + result = 0; + } else { + result = 1; + } } FREE_OP2(); } else if (Z_TYPE_PP(container) == IS_OBJECT) { @@ -3971,14 +4294,14 @@ } if (prop_dim) { if (Z_OBJ_HT_P(*container)->has_property) { - result = Z_OBJ_HT_P(*container)->has_property(*container, offset, (opline->extended_value == ZEND_ISEMPTY) TSRMLS_CC); + result = Z_OBJ_HT_P(*container)->has_property(*container, offset, (opline->extended_value & ZEND_ISEMPTY) != 0, ((OP2_TYPE == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC); } else { zend_error(E_NOTICE, "Trying to check property of non-object"); result = 0; } } else { if (Z_OBJ_HT_P(*container)->has_dimension) { - result = Z_OBJ_HT_P(*container)->has_dimension(*container, offset, (opline->extended_value == ZEND_ISEMPTY) TSRMLS_CC); + result = Z_OBJ_HT_P(*container)->has_dimension(*container, offset, (opline->extended_value & ZEND_ISEMPTY) != 0 TSRMLS_CC); } else { zend_error(E_NOTICE, "Trying to check element of non-array"); result = 0; @@ -3993,23 +4316,20 @@ zval tmp; if (Z_TYPE_P(offset) != IS_LONG) { - tmp = *offset; + ZVAL_COPY_VALUE(&tmp, offset); zval_copy_ctor(&tmp); convert_to_long(&tmp); offset = &tmp; } if (Z_TYPE_P(offset) == IS_LONG) { - switch (opline->extended_value) { - case ZEND_ISSET: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { - result = 1; - } - break; - case ZEND_ISEMPTY: - if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { - result = 1; - } - break; + if (opline->extended_value & ZEND_ISSET) { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container)) { + result = 1; + } + } else /* if (opline->extended_value & ZEND_ISEMPTY) */ { + if (offset->value.lval >= 0 && offset->value.lval < Z_STRLEN_PP(container) && Z_STRVAL_PP(container)[offset->value.lval] != '0') { + result = 1; + } } } FREE_OP2(); @@ -4018,19 +4338,16 @@ } } - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_BOOL; - - switch (opline->extended_value) { - case ZEND_ISSET: - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = result; - break; - case ZEND_ISEMPTY: - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = !result; - break; + Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_BOOL; + if (opline->extended_value & ZEND_ISSET) { + Z_LVAL(EX_T(opline->result.var).tmp_var) = result; + } else { + Z_LVAL(EX_T(opline->result.var).tmp_var) = !result; } FREE_OP1_VAR_PTR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4047,7 +4364,9 @@ ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP|VAR|UNUSED|CV, ANY) { #if !defined(ZEND_VM_SPEC) || (OP1_TYPE != IS_UNUSED) - zend_op *opline = EX(opline); + USE_OPLINE + + SAVE_OPLINE(); if (OP1_TYPE != IS_UNUSED) { zend_free_op free_op1; zval *ptr = GET_OP1_ZVAL_PTR(BP_VAR_R); @@ -4061,169 +4380,208 @@ } #endif zend_bailout(); - ZEND_VM_NEXT_OPCODE(); + ZEND_VM_NEXT_OPCODE(); /* Never reached */ } ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - Z_LVAL(EX_T(opline->result.u.var).tmp_var) = EG(error_reporting); - Z_TYPE(EX_T(opline->result.u.var).tmp_var) = IS_LONG; /* shouldn't be necessary */ + SAVE_OPLINE(); + Z_LVAL(EX_T(opline->result.var).tmp_var) = EG(error_reporting); + Z_TYPE(EX_T(opline->result.var).tmp_var) = IS_LONG; /* shouldn't be necessary */ if (EX(old_error_reporting) == NULL) { - EX(old_error_reporting) = &EX_T(opline->result.u.var).tmp_var; + EX(old_error_reporting) = &EX_T(opline->result.var).tmp_var; } if (EG(error_reporting)) { zend_alter_ini_entry_ex("error_reporting", sizeof("error_reporting"), "0", 1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME, 1 TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(142, ZEND_RAISE_ABSTRACT_ERROR, ANY, ANY) { + SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", EG(scope)->name, EX(op_array)->function_name); ZEND_VM_NEXT_OPCODE(); /* Never reached */ } ZEND_VM_HANDLER(58, ZEND_END_SILENCE, TMP, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zval restored_error_reporting; - if (!EG(error_reporting) && Z_LVAL(EX_T(opline->op1.u.var).tmp_var) != 0) { + SAVE_OPLINE(); + if (!EG(error_reporting) && Z_LVAL(EX_T(opline->op1.var).tmp_var) != 0) { Z_TYPE(restored_error_reporting) = IS_LONG; - Z_LVAL(restored_error_reporting) = Z_LVAL(EX_T(opline->op1.u.var).tmp_var); + Z_LVAL(restored_error_reporting) = Z_LVAL(EX_T(opline->op1.var).tmp_var); convert_to_string(&restored_error_reporting); zend_alter_ini_entry_ex("error_reporting", sizeof("error_reporting"), Z_STRVAL(restored_error_reporting), Z_STRLEN(restored_error_reporting), ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME, 1 TSRMLS_CC); zendi_zval_dtor(restored_error_reporting); } - if (EX(old_error_reporting) == &EX_T(opline->op1.u.var).tmp_var) { + if (EX(old_error_reporting) == &EX_T(opline->op1.var).tmp_var) { EX(old_error_reporting) = NULL; } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *value; + SAVE_OPLINE(); + value = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (i_zend_is_true(value)) { - EX_T(opline->result.u.var).tmp_var = *value; - zendi_zval_copy_ctor(EX_T(opline->result.u.var).tmp_var); + ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, value); + zendi_zval_copy_ctor(EX_T(opline->result.var).tmp_var); FREE_OP1(); #if DEBUG_ZEND>=2 - printf("Conditional jmp to %d\n", opline->op2.u.opline_num); + printf("Conditional jmp to %d\n", opline->op2.opline_num); #endif - ZEND_VM_JMP(opline->op2.u.jmp_addr); + ZEND_VM_JMP(opline->op2.jmp_addr); } FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *value = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *value; - EX_T(opline->result.u.var).tmp_var = *value; + SAVE_OPLINE(); + value = GET_OP1_ZVAL_PTR(BP_VAR_R); + + ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, value); if (!IS_OP1_TMP_FREE()) { - zval_copy_ctor(&EX_T(opline->result.u.var).tmp_var); + zval_copy_ctor(&EX_T(opline->result.var).tmp_var); } FREE_OP1_IF_VAR(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(101, ZEND_EXT_STMT, ANY, ANY) { + USE_OPLINE + + SAVE_OPLINE(); if (!EG(no_extensions)) { zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_statement_handler, EX(op_array) TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(102, ZEND_EXT_FCALL_BEGIN, ANY, ANY) { + USE_OPLINE + + SAVE_OPLINE(); if (!EG(no_extensions)) { zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_begin_handler, EX(op_array) TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(103, ZEND_EXT_FCALL_END, ANY, ANY) { + SAVE_OPLINE(); if (!EG(no_extensions)) { zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_fcall_end_handler, EX(op_array) TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(139, ZEND_DECLARE_CLASS, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - EX_T(opline->result.u.var).class_entry = do_bind_class(opline, EG(class_table), 0 TSRMLS_CC); + SAVE_OPLINE(); + EX_T(opline->result.var).class_entry = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(140, ZEND_DECLARE_INHERITED_CLASS, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - EX_T(opline->result.u.var).class_entry = do_bind_inherited_class(opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC); + SAVE_OPLINE(); + EX_T(opline->result.var).class_entry = do_bind_inherited_class(EX(op_array), opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(145, ZEND_DECLARE_INHERITED_CLASS_DELAYED, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_class_entry **pce, **pce_orig; - if (zend_hash_find(EG(class_table), Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant)+1, (void**)&pce) == FAILURE || - (zend_hash_find(EG(class_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), (void**)&pce_orig) == SUCCESS && + SAVE_OPLINE(); + if (zend_hash_quick_find(EG(class_table), Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv)+1, Z_HASH_P(opline->op2.zv), (void**)&pce) == FAILURE || + (zend_hash_quick_find(EG(class_table), Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), Z_HASH_P(opline->op1.zv), (void**)&pce_orig) == SUCCESS && *pce != *pce_orig)) { - do_bind_inherited_class(opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC); + do_bind_inherited_class(EX(op_array), opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) { - do_bind_function(EX(opline), EG(function_table), 0); + USE_OPLINE + + SAVE_OPLINE(); + do_bind_function(EX(op_array), opline, EG(function_table), 0); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(105, ZEND_TICKS, CONST, ANY) +ZEND_VM_HANDLER(105, ZEND_TICKS, ANY, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE - if (++EG(ticks_count)>=Z_LVAL(opline->op1.u.constant)) { + SAVE_OPLINE(); + if (++EG(ticks_count)>=opline->extended_value) { EG(ticks_count)=0; if (zend_ticks_function) { - zend_ticks_function(Z_LVAL(opline->op1.u.constant)); + zend_ticks_function(opline->extended_value); } } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(138, ZEND_INSTANCEOF, TMP|VAR|CV, ANY) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1; - zval *expr = GET_OP1_ZVAL_PTR(BP_VAR_R); + zval *expr; zend_bool result; + SAVE_OPLINE(); + expr = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (Z_TYPE_P(expr) == IS_OBJECT && Z_OBJ_HT_P(expr)->get_class_entry) { - result = instanceof_function(Z_OBJCE_P(expr), EX_T(opline->op2.u.var).class_entry TSRMLS_CC); + result = instanceof_function(Z_OBJCE_P(expr), EX_T(opline->op2.var).class_entry TSRMLS_CC); } else { result = 0; } - ZVAL_BOOL(&EX_T(opline->result.u.var).tmp_var, result); + ZVAL_BOOL(&EX_T(opline->result.var).tmp_var, result); FREE_OP1(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4239,17 +4597,21 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, CONST) { - zend_op *opline = EX(opline); - zend_class_entry *ce = EX_T(opline->op1.u.var).class_entry; - zend_class_entry *iface = zend_fetch_class(Z_STRVAL(opline->op2.u.constant), Z_STRLEN(opline->op2.u.constant), opline->extended_value TSRMLS_CC); + USE_OPLINE + zend_class_entry *ce = EX_T(opline->op1.var).class_entry; + zend_class_entry *iface; + SAVE_OPLINE(); + iface = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, opline->extended_value TSRMLS_CC); + if (iface) { - if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) { + if (UNEXPECTED((iface->ce_flags & ZEND_ACC_INTERFACE) == 0)) { zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); } zend_do_implement_interface(ce, iface TSRMLS_CC); } + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -4257,11 +4619,11 @@ { zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes; int i; - zend_uint catch_op_num; + zend_uint catch_op_num = 0; int catched = 0; zval restored_error_reporting; - void **stack_frame = (void**)(((char*)EX(Ts)) + + void **stack_frame = (void**)(((char*)EX_Ts()) + (ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)) * EX(op_array)->T)); while (zend_vm_stack_top(TSRMLS_C) != stack_frame) { @@ -4311,13 +4673,13 @@ switch (brk_opline->opcode) { case ZEND_SWITCH_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zend_switch_free(&EX_T(brk_opline->op1.u.var), brk_opline->extended_value TSRMLS_CC); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zend_switch_free(&EX_T(brk_opline->op1.var), brk_opline->extended_value TSRMLS_CC); } break; case ZEND_FREE: - if (brk_opline->op1.u.EA.type != EXT_TYPE_FREE_ON_RETURN) { - zendi_zval_dtor(EX_T(brk_opline->op1.u.var).tmp_var); + if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) { + zendi_zval_dtor(EX_T(brk_opline->op1.var).tmp_var); } break; } @@ -4345,13 +4707,22 @@ ZEND_VM_HANDLER(146, ZEND_VERIFY_ABSTRACT_CLASS, ANY, ANY) { - zend_verify_abstract_class(EX_T(EX(opline)->op1.u.var).class_entry TSRMLS_CC); + USE_OPLINE + + SAVE_OPLINE(); + zend_verify_abstract_class(EX_T(opline->op1.var).class_entry TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY) { - int ret = zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL); + USE_OPLINE + int ret; + + SAVE_OPLINE(); + ret = zend_user_opcode_handlers[opline->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL); + LOAD_OPLINE(); switch (ret) { case ZEND_USER_OPCODE_CONTINUE: @@ -4363,24 +4734,29 @@ case ZEND_USER_OPCODE_LEAVE: ZEND_VM_LEAVE(); case ZEND_USER_OPCODE_DISPATCH: - ZEND_VM_DISPATCH(EX(opline)->opcode, EX(opline)); + ZEND_VM_DISPATCH(opline->opcode, opline); default: - ZEND_VM_DISPATCH((zend_uchar)(ret & 0xff), EX(opline)); + ZEND_VM_DISPATCH((zend_uchar)(ret & 0xff), opline); } } ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST) { - zend_op *opline = EX(opline); + USE_OPLINE zend_free_op free_op1, free_op2; - zval *name = GET_OP1_ZVAL_PTR(BP_VAR_R); - zval *val = GET_OP2_ZVAL_PTR(BP_VAR_R); + zval *name; + zval *val; zend_constant c; + SAVE_OPLINE(); + name = GET_OP1_ZVAL_PTR(BP_VAR_R); + val = GET_OP2_ZVAL_PTR(BP_VAR_R); + if ((Z_TYPE_P(val) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT || Z_TYPE_P(val) == IS_CONSTANT_ARRAY) { - zval tmp = *val; + zval tmp; zval *tmp_ptr = &tmp; + ZVAL_COPY_VALUE(&tmp, val); if (Z_TYPE_P(val) == IS_CONSTANT_ARRAY) { zval_copy_ctor(&tmp); } @@ -4388,11 +4764,11 @@ zval_update_constant(&tmp_ptr, NULL TSRMLS_CC); c.value = *tmp_ptr; } else { - c.value = *val; + INIT_PZVAL_COPY(&c.value, val); zval_copy_ctor(&c.value); } c.flags = CONST_CS; /* non persistent, case sensetive */ - c.name = zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); + c.name = IS_INTERNED(Z_STRVAL_P(name)) ? Z_STRVAL_P(name) : zend_strndup(Z_STRVAL_P(name), Z_STRLEN_P(name)); c.name_len = Z_STRLEN_P(name)+1; c.module_number = PHP_USER_CONSTANT; @@ -4401,21 +4777,25 @@ FREE_OP1(); FREE_OP2(); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, CONST) +ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED) { - zend_op *opline = EX(opline); + USE_OPLINE zend_function *op_array; - if (zend_hash_quick_find(EG(function_table), Z_STRVAL(opline->op1.u.constant), Z_STRLEN(opline->op1.u.constant), Z_LVAL(opline->op2.u.constant), (void *) &op_array) == FAILURE || - op_array->type != ZEND_USER_FUNCTION) { + SAVE_OPLINE(); + + if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), Z_HASH_P(opline->op1.zv), (void *) &op_array) == FAILURE) || + UNEXPECTED(op_array->type != ZEND_USER_FUNCTION)) { zend_error_noreturn(E_ERROR, "Base lambda function for closure not found"); } - zend_create_closure(&EX_T(opline->result.u.var).tmp_var, op_array TSRMLS_CC); + zend_create_closure(&EX_T(opline->result.var).tmp_var, op_array TSRMLS_CC); + CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } Index: Zend/Makefile.am =================================================================== --- Zend/Makefile.am (revision 297868) +++ Zend/Makefile.am (working copy) @@ -17,7 +17,7 @@ zend_objects_API.c zend_ts_hash.c zend_stream.c \ zend_default_classes.c \ zend_iterators.c zend_interfaces.c zend_exceptions.c \ - zend_strtod.c zend_closures.c zend_float.c + zend_strtod.c zend_closures.c zend_float.c zend_string.c libZend_la_LDFLAGS = libZend_la_LIBADD = @ZEND_EXTRA_LIBS@ Index: Zend/zend_opcode.c =================================================================== --- Zend/zend_opcode.c (revision 297868) +++ Zend/zend_opcode.c (working copy) @@ -67,7 +67,7 @@ op_array->opcodes = NULL; op_array_alloc_ops(op_array); - op_array->size_var = 0; /* FIXME:??? */ + op_array->size_var = 0; op_array->last_var = 0; op_array->vars = NULL; @@ -103,6 +103,10 @@ op_array->early_binding = -1; + op_array->size_literal = 0; + op_array->last_literal = 0; + op_array->literals = NULL; + memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); @@ -220,8 +224,8 @@ ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC) { - zend_op *opline = op_array->opcodes; - zend_op *end = op_array->opcodes+op_array->last; + zend_literal *literal = op_array->literals; + zend_literal *end; zend_uint i; if (op_array->static_variables) { @@ -239,25 +243,20 @@ i = op_array->last_var; while (i > 0) { i--; - efree(op_array->vars[i].name); + if (!IS_INTERNED(op_array->vars[i].name)) { + efree(op_array->vars[i].name); + } } efree(op_array->vars); } - while (oplineop1.op_type==IS_CONST) { -#if DEBUG_ZEND>2 - printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op1.u.constant); -#endif - zval_dtor(&opline->op1.u.constant); + if (literal) { + end = literal + op_array->last_literal; + while (literal < end) { + zval_dtor(&literal->constant); + literal++; } - if (opline->op2.op_type==IS_CONST) { -#if DEBUG_ZEND>2 - printf("Reducing refcount for %x 1=>0 (destroying)\n", &opline->op2.u.constant); -#endif - zval_dtor(&opline->op2.u.constant); - } - opline++; + efree(op_array->literals); } efree(op_array->opcodes); @@ -278,8 +277,10 @@ } if (op_array->arg_info) { for (i=0; inum_args; i++) { - efree((char*)op_array->arg_info[i].name); - if (op_array->arg_info[i].class_name) { + if (!IS_INTERNED(op_array->arg_info[i].name)) { + efree((char*)op_array->arg_info[i].name); + } + if (op_array->arg_info[i].class_name && !IS_INTERNED(op_array->arg_info[i].class_name)) { efree((char*)op_array->arg_info[i].class_name); } } @@ -377,39 +378,41 @@ op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last); op_array->size = op_array->last; } + if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && op_array->size_literal != op_array->last_literal) { + op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal); + op_array->size_literal = op_array->last_literal; + } opline = op_array->opcodes; end = opline + op_array->last; while (opline < end) { - if (opline->op1.op_type == IS_CONST) { - Z_SET_ISREF(opline->op1.u.constant); - Z_SET_REFCOUNT(opline->op1.u.constant, 2); /* Make sure is_ref won't be reset */ + if (opline->op1_type == IS_CONST) { + opline->op1.zv = &op_array->literals[opline->op1.constant].constant; } - if (opline->op2.op_type == IS_CONST) { - Z_SET_ISREF(opline->op2.u.constant); - Z_SET_REFCOUNT(opline->op2.u.constant, 2); + if (opline->op2_type == IS_CONST) { + opline->op2.zv = &op_array->literals[opline->op2.constant].constant; } switch (opline->opcode) { case ZEND_GOTO: - if (Z_TYPE(opline->op2.u.constant) != IS_LONG) { + if (Z_TYPE_P(opline->op2.zv) != IS_LONG) { zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC); } /* break omitted intentionally */ case ZEND_JMP: - opline->op1.u.jmp_addr = &op_array->opcodes[opline->op1.u.opline_num]; + opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num]; break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_JMP_SET: - opline->op2.u.jmp_addr = &op_array->opcodes[opline->op2.u.opline_num]; + opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num]; break; } ZEND_VM_SET_OPCODE_HANDLER(opline); opline++; } - + op_array->done_pass_two = 1; return 0; } Index: Zend/zend_vm_execute.skl =================================================================== --- Zend/zend_vm_execute.skl (revision 297868) +++ Zend/zend_vm_execute.skl (working copy) @@ -2,6 +2,7 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) { + DCL_OPLINE zend_execute_data *execute_data; zend_bool nested = 0; zend_bool original_in_execution = EG(in_execution); @@ -36,29 +37,27 @@ EX(nested) = nested; nested = 1; - if (op_array->start_op) { - ZEND_VM_SET_OPCODE(op_array->start_op); - } else { - ZEND_VM_SET_OPCODE(op_array->opcodes); - } + LOAD_REGS(); if (op_array->this_var != -1 && EG(This)) { Z_ADDREF_P(EG(This)); /* For $this pointer */ if (!EG(active_symbol_table)) { - EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var); - *EX(CVs)[op_array->this_var] = EG(This); + EX_CV(op_array->this_var) = (zval**)EX_CVs() + (op_array->last_var + op_array->this_var); + *EX_CV(op_array->this_var) = EG(This); } else { - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX_CV(op_array->this_var))==FAILURE) { Z_DELREF_P(EG(This)); } } } + EX(opline) = op_array->start_op ? op_array->start_op : op_array->opcodes; EG(opline_ptr) = &EX(opline); + LOAD_OPLINE(); EX(function_state).function = (zend_function *) op_array; EX(function_state).arguments = NULL; - + while (1) { {%ZEND_VM_CONTINUE_LABEL%} #ifdef ZEND_WIN32 Index: main/main.c =================================================================== --- main/main.c (revision 297868) +++ main/main.c (working copy) @@ -668,7 +668,7 @@ EG(current_execute_data)->opline && EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL ) { - switch (EG(current_execute_data)->opline->op2.u.constant.value.lval) { + switch (EG(current_execute_data)->opline->extended_value) { case ZEND_EVAL: function = "eval"; is_function = 1; @@ -1509,6 +1509,7 @@ /* used to close fd's in the 3..255 range here, but it's problematic */ shutdown_memory_manager(1, 1 TSRMLS_CC); + CG(interned_strings_restore)(TSRMLS_C); } /* }}} */ @@ -1551,6 +1552,8 @@ shutdown_memory_manager(CG(unclean_shutdown), 0 TSRMLS_CC); } zend_end_try(); + CG(interned_strings_restore)(TSRMLS_C); + zend_try { zend_unset_timeout(TSRMLS_C); } zend_end_try(); @@ -1649,6 +1652,7 @@ zend_try { shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0 TSRMLS_CC); } zend_end_try(); + CG(interned_strings_restore)(TSRMLS_C); /* 12. Reset max_execution_time */ zend_try { @@ -2110,6 +2114,7 @@ module_startup = 0; shutdown_memory_manager(1, 0 TSRMLS_CC); + CG(interned_strings_snapshot)(TSRMLS_C); /* we're done */ return SUCCESS; Index: win32/build/config.w32 =================================================================== --- win32/build/config.w32 (revision 297868) +++ win32/build/config.w32 (working copy) @@ -325,7 +325,7 @@ zend_stream.c zend_iterators.c zend_interfaces.c zend_objects.c \ zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c \ - zend_float.c"); + zend_float.c zend_string.c"); if (VCVERS == 1200) { AC_DEFINE('ZEND_DVAL_TO_LVAL_CAST_OK', 1);