. ZEND_FETCH_DIM_? may fetch array and dimension operans in a different order
. ZEND_RETURN is splitted into two new instructions ZEND_RETURN and
ZEND_RETURN_BY_REF
+ . optimized access to global constants using values with pre-calculated
+ hash_values from litersls table
- Added concept of interned strings. All strings constants known at compile
time are allocated in a single copy and never changed. (Dmitry)
- Added an optimization which saves memory and emalloc/efree calls for empty
}
}
+define('TEST', null);
+
+function read_const($n) {
+ for ($i = 0; $i < $n; ++$i) {
+ $x = TEST;
+ }
+}
+
/*****/
function empty_loop($n) {
$t = end_test($t, '$x = Foo::TEST', $overhead);
create_object(N);
$t = end_test($t, 'new Foo()', $overhead);
+read_const(N);
+$t = end_test($t, '$x = TEST', $overhead);
total($t0, "Total");
#define IS_CONSTANT_ARRAY 9
/* Ugly hack to support constants as static array indices */
-#define IS_CONSTANT_TYPE_MASK 0x0f
-#define IS_CONSTANT_UNQUALIFIED 0x10
-#define IS_CONSTANT_INDEX 0x80
-#define IS_LEXICAL_VAR 0x20
-#define IS_LEXICAL_REF 0x40
+#define IS_CONSTANT_TYPE_MASK 0x00f
+#define IS_CONSTANT_UNQUALIFIED 0x010
+#define IS_CONSTANT_INDEX 0x080
+#define IS_LEXICAL_VAR 0x020
+#define IS_LEXICAL_REF 0x040
+#define IS_CONSTANT_IN_NAMESPACE 0x100
/* overloaded elements data types */
#define OE_IS_ARRAY (1<<0)
}
/* }}} */
+int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unqualified TSRMLS_DC) /* {{{ */
+{
+ int ret, tmp_literal;
+ char *name, *tmp_name, *ns_separator;
+ int name_len, ns_len;
+ zval c;
+
+ if (op_array->last_literal > 0 &&
+ &op_array->literals[op_array->last_literal - 1].constant == zv) {
+ /* we already have function name as last literal (do nothing) */
+ ret = op_array->last_literal - 1;
+ } else {
+ ret = zend_add_literal(op_array, zv);
+ }
+
+ /* skip leading '\\' */
+ if (Z_STRVAL_P(zv)[0] == '\\') {
+ name_len = Z_STRLEN_P(zv) - 1;
+ name = Z_STRVAL_P(zv) + 1;
+ } else {
+ name_len = Z_STRLEN_P(zv);
+ name = Z_STRVAL_P(zv);
+ }
+ ns_separator = zend_memrchr(name, '\\', name_len);
+ if (ns_separator) {
+ ns_len = ns_separator - name;
+ } else {
+ ns_len = 0;
+ }
+
+ if (ns_len) {
+ /* lowercased namespace name & original constant name */
+ tmp_name = estrndup(name, name_len);
+ zend_str_tolower(tmp_name, ns_len);
+ ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+ tmp_literal = zend_add_literal(CG(active_op_array), &c);
+ CALCULATE_LITERAL_HASH(tmp_literal);
+
+ /* lowercased namespace name & lowercased constant name */
+ tmp_name = zend_str_tolower_dup(name, name_len);
+ ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+ tmp_literal = zend_add_literal(CG(active_op_array), &c);
+ CALCULATE_LITERAL_HASH(tmp_literal);
+ }
+
+ if (ns_len) {
+ if (!unqualified) {
+ return ret;
+ }
+ ns_len++;
+ name += ns_len;
+ name_len -= ns_len;
+ }
+
+ /* original constant name */
+ tmp_name = estrndup(name, name_len);
+ ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+ tmp_literal = zend_add_literal(CG(active_op_array), &c);
+ CALCULATE_LITERAL_HASH(tmp_literal);
+
+ /* lowercased constant name */
+ tmp_name = zend_str_tolower_dup(name, name_len);
+ ZVAL_STRINGL(&c, tmp_name, name_len, 0);
+ tmp_literal = zend_add_literal(CG(active_op_array), &c);
+ CALCULATE_LITERAL_HASH(tmp_literal);
+
+ return ret;
+}
+/* }}} */
+
#define LITERAL_STRINGL(op, str, len, copy) do { \
zval _c; \
ZVAL_STRINGL(&_c, str, len, copy); \
opline->result.var = get_temporary_variable(CG(active_op_array));
GET_NODE(result, opline->result);
SET_UNUSED(opline->op1);
- if(compound) {
+ opline->op2_type = IS_CONST;
+ if (compound) {
/* the name is unambiguous */
opline->extended_value = 0;
- } else {
+ opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
+ } else {
opline->extended_value = IS_CONSTANT_UNQUALIFIED;
+ if (CG(current_namespace)) {
+ opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
+ opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 1 TSRMLS_CC);
+ } else {
+ opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
+ }
}
- SET_NODE(opline->op2, constant_name);
- CALCULATE_LITERAL_HASH(opline->op2.constant);
break;
}
}
zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number TSRMLS_CC);
}
+static int zend_get_halt_offset_constant(const char *name, uint name_len, zend_constant **c TSRMLS_DC)
+{
+ int ret;
+ static char haltoff[] = "__COMPILER_HALT_OFFSET__";
+
+ if (!EG(in_execution)) {
+ return 0;
+ } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
+ !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
+ char *cfilename, *haltname;
+ int len, clen;
+
+ cfilename = zend_get_executed_filename(TSRMLS_C);
+ clen = strlen(cfilename);
+ /* check for __COMPILER_HALT_OFFSET__ */
+ zend_mangle_property_name(&haltname, &len, haltoff,
+ sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
+ ret = zend_hash_find(EG(zend_constants), haltname, len+1, (void **) c);
+ efree(haltname);
+ return (ret == SUCCESS);
+ } else {
+ return 0;
+ }
+}
+
ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSRMLS_DC)
{
retval=0;
}
} else {
- static char haltoff[] = "__COMPILER_HALT_OFFSET__";
-
- if (!EG(in_execution)) {
- retval = 0;
- } else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
- !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
- char *cfilename, *haltname;
- int len, clen;
-
- cfilename = zend_get_executed_filename(TSRMLS_C);
- clen = strlen(cfilename);
- /* check for __COMPILER_HALT_OFFSET__ */
- zend_mangle_property_name(&haltname, &len, haltoff,
- sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
- if (zend_hash_find(EG(zend_constants), haltname, len+1, (void **) &c) == SUCCESS) {
- retval = 1;
- } else {
- retval=0;
- }
- pefree(haltname, 0);
- } else {
- retval=0;
- }
+ retval = zend_get_halt_offset_constant(name, name_len, &c TSRMLS_CC);
}
efree(lookup_name);
}
return zend_get_constant(name, name_len, result TSRMLS_CC);
}
+int zend_quick_get_constant(const zend_literal *key, zval *result, ulong flags TSRMLS_DC)
+{
+ zend_constant *c;
+
+ if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE) {
+ key++;
+ if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE ||
+ (c->flags & CONST_CS) != 0) {
+ if ((flags & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
+ key++;
+ if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE) {
+ key++;
+ if (zend_hash_quick_find(EG(zend_constants), Z_STRVAL(key->constant), Z_STRLEN(key->constant) + 1, key->hash_value, (void **) &c) == FAILURE ||
+ (c->flags & CONST_CS) != 0) {
+
+ key--;
+ if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+ return 0;
+ }
+ }
+ }
+ } else {
+ key--;
+ if (!zend_get_halt_offset_constant(Z_STRVAL(key->constant), Z_STRLEN(key->constant), &c TSRMLS_CC)) {
+ return 0;
+ }
+ }
+ }
+ }
+
+ INIT_PZVAL_COPY(result, &c->value);
+ zval_copy_ctor(result);
+ return 1;
+}
+
ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
{
char *lowercase_name = NULL;
ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC);
void zend_copy_constants(HashTable *target, HashTable *sourc);
void copy_zend_constant(zend_constant *c);
+int zend_quick_get_constant(const zend_literal *key, zval *result, ulong flags TSRMLS_DC);
END_EXTERN_C()
#define ZEND_CONSTANT_DTOR (void (*)(void *)) free_zend_constant
SAVE_OPLINE();
if (OP1_TYPE == IS_UNUSED) {
/* namespaced constant */
- 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 (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
if(!actual) {
SAVE_OPLINE();
if (IS_CONST == IS_UNUSED) {
/* namespaced constant */
- 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 (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
if(!actual) {
SAVE_OPLINE();
if (IS_VAR == IS_UNUSED) {
/* namespaced constant */
- 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 (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
if(!actual) {
SAVE_OPLINE();
if (IS_UNUSED == IS_UNUSED) {
/* namespaced constant */
- 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 (!zend_quick_get_constant(opline->op2.literal + 1, &EX_T(opline->result.var).tmp_var, opline->extended_value TSRMLS_CC)) {
if ((opline->extended_value & IS_CONSTANT_UNQUALIFIED) != 0) {
char *actual = (char *)zend_memrchr(Z_STRVAL_P(opline->op2.zv), '\\', Z_STRLEN_P(opline->op2.zv));
if(!actual) {