Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:49610 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 55202 invoked from network); 13 Sep 2010 11:59:16 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 13 Sep 2010 11:59:16 -0000 Authentication-Results: pb1.pair.com smtp.mail=dmitry@zend.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=dmitry@zend.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 212.25.124.185 as permitted sender) X-PHP-List-Original-Sender: dmitry@zend.com X-Host-Fingerprint: 212.25.124.185 il-mr1.zend.com Received: from [212.25.124.185] ([212.25.124.185:53706] helo=il-mr1.zend.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 4D/44-17717-E021E8C4 for ; Mon, 13 Sep 2010 07:59:16 -0400 Received: from il-gw1.zend.com (unknown [10.1.1.22]) by il-mr1.zend.com (Postfix) with ESMTP id CB71C5053A for ; Mon, 13 Sep 2010 13:57:03 +0200 (IST) Received: from ws.home (10.1.10.12) by il-ex2.zend.net (10.1.1.22) with Microsoft SMTP Server id 14.0.689.0; Mon, 13 Sep 2010 13:58:42 +0200 Message-ID: <4C8E11FD.3070707@zend.com> Date: Mon, 13 Sep 2010 15:58:53 +0400 User-Agent: Thunderbird 2.0.0.23 (X11/20090825) MIME-Version: 1.0 To: PHP Internals CC: Zeev Suraski Content-Type: multipart/mixed; boundary="------------050400000701060201050802" Subject: [PATCH] Reduce heap memory consumption From: dmitry@zend.com (Dmitry Stogov) --------------050400000701060201050802 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit Hi, The attached patch modifies internal ZE data structures. It gives 4% less heap memory usage on waiting PHP process (2210KB instead of 2304KB) and up to 7% improvement on applications with many classes (ZendFramework benchmark uses 17.7M instead of 19M). It also makes small speedup on some big applications with opcode caches, because of less memory transfer. The patch performs the following optimizations: 1) zend_function.pass_rest_by_reference is replaced by ZEND_ACC_PASS_REST_BY_REFERENCE in zend_function.fn_flags 2) zend_function.return_reference is replaced by ZEND_ACC_RETURN_REFERENCE in zend_function.fn_flags 3) zend_arg_info.required_num_args removed. it was needed only for internal functions. Now the first arg_info for internal function (which has special meaning) is represented by zend_internal_function_info structure. 4) zend_op_array.size, size_var, size_literal, current_brk_cont, backpatch_count moved into CG(context), because they are used only during compilation. 5) zend_op_array.start_op is moved into EG(start_op), because it's used only for 'interactive' execution of single top-level op-array. 6) zend_op_array.done_pass_two is replaced by ZEND_ACC_DONE_PASS_TWO in zend_op_array.fn_flags. 7) the sise of op_array.vars is reduced during pass_two. 8) zend_class_entry.constants_updated is replaced by ZEND_ACC_CONSTANTS_UPDATED in zend_class_entry.ce_flags 9) The size of zend_class_entry is reduced by sharing the same memory space by different information for internal and user classes. See zend_class_inttry.info union. Of course the patch will affect some extensions (e.g. APC and xdebug), but it shouldn't be difficult to fix them. I'm going to commit the patch by the end of this week in case of no objections. I'll also add corresponding notes into UPGRADING.INTERNALS. Thanks. Dmitry. --------------050400000701060201050802 Content-Type: text/plain; name="mem.diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="mem.diff.txt" Index: ext/soap/soap.c =================================================================== --- ext/soap/soap.c (revision 303306) +++ ext/soap/soap.c (working copy) @@ -703,7 +703,6 @@ fe.prototype = NULL; fe.num_args = 2; fe.arg_info = NULL; - fe.pass_rest_by_reference = 0; INIT_OVERLOADED_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions, (zend_function *)&fe, NULL, NULL); Index: ext/pdo/pdo_dbh.c =================================================================== --- ext/pdo/pdo_dbh.c (revision 303306) +++ ext/pdo/pdo_dbh.c (working copy) @@ -1308,28 +1308,36 @@ ifunc->function_name = (char*)funcs->fname; ifunc->scope = dbh->std.ce; ifunc->prototype = NULL; + if (funcs->flags) { + ifunc->fn_flags = funcs->flags; + } else { + ifunc->fn_flags = ZEND_ACC_PUBLIC; + } if (funcs->arg_info) { + zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info; + ifunc->arg_info = (zend_arg_info*)funcs->arg_info + 1; ifunc->num_args = funcs->num_args; - if (funcs->arg_info[0].required_num_args == -1) { + if (info->required_num_args == -1) { ifunc->required_num_args = funcs->num_args; } else { - ifunc->required_num_args = funcs->arg_info[0].required_num_args; + ifunc->required_num_args = info->required_num_args; } - ifunc->pass_rest_by_reference = funcs->arg_info[0].pass_by_reference; - ifunc->return_reference = funcs->arg_info[0].return_reference; + if (info->pass_rest_by_reference) { + if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) { + ifunc->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF; + } else { + ifunc->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE; + } + } + if (info->return_reference) { + ifunc->fn_flags |= ZEND_ACC_RETURN_REFERENCE; + } } else { ifunc->arg_info = NULL; ifunc->num_args = 0; ifunc->required_num_args = 0; - ifunc->pass_rest_by_reference = 0; - ifunc->return_reference = 0; } - if (funcs->flags) { - ifunc->fn_flags = funcs->flags; - } else { - ifunc->fn_flags = ZEND_ACC_PUBLIC; - } namelen = strlen(funcs->fname); lc_name = emalloc(namelen+1); zend_str_tolower_copy(lc_name, funcs->fname, namelen); Index: ext/reflection/php_reflection.c =================================================================== --- ext/reflection/php_reflection.c (revision 303306) +++ ext/reflection/php_reflection.c (working copy) @@ -356,8 +356,8 @@ string_printf(&sub_indent, "%s ", indent); /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */ - if (ce->type == ZEND_USER_CLASS && ce->doc_comment) { - string_printf(str, "%s%s", indent, ce->doc_comment); + if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) { + string_printf(str, "%s%s", indent, ce->info.user.doc_comment); string_write(str, "\n", 1); } @@ -373,8 +373,8 @@ string_printf(str, "%s%s [ ", indent, kind); } string_printf(str, (ce->type == ZEND_USER_CLASS) ? "module) { - string_printf(str, ":%s", ce->module->name); + if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) { + string_printf(str, ":%s", ce->info.internal.module->name); } string_printf(str, "> "); if (ce->get_iterator != NULL) { @@ -414,8 +414,8 @@ /* The information where a class is declared is only available for user classes */ if (ce->type == ZEND_USER_CLASS) { - string_printf(str, "%s @@ %s %d-%d\n", indent, ce->filename, - ce->line_start, ce->line_end); + string_printf(str, "%s @@ %s %d-%d\n", indent, ce->info.user.filename, + ce->info.user.line_start, ce->info.user.line_end); } /* Constants */ @@ -891,7 +891,7 @@ string_printf(str, "function "); } - if (fptr->op_array.return_reference) { + if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { string_printf(str, "&"); } string_printf(str, "%s ] {\n", fptr->common.function_name); @@ -997,7 +997,7 @@ struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); int *num_classes = va_arg(args, int*); - if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) { + if (((*pce)->type == ZEND_INTERNAL_CLASS) && (*pce)->info.internal.module && !strcasecmp((*pce)->info.internal.module->name, module->name)) { string_printf(str, "\n"); _class_string(str, *pce, NULL, indent TSRMLS_CC); (*num_classes)++; @@ -1940,7 +1940,7 @@ METHOD_NOTSTATIC(reflection_function_abstract_ptr); GET_REFLECTION_OBJECT_PTR(fptr); - RETURN_BOOL(fptr->op_array.return_reference); + RETURN_BOOL((fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0); } /* }}} */ @@ -3521,7 +3521,7 @@ } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_CLASS) { - RETURN_STRING(ce->filename, 1); + RETURN_STRING(ce->info.user.filename, 1); } RETURN_FALSE; } @@ -3539,7 +3539,7 @@ } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_FUNCTION) { - RETURN_LONG(ce->line_start); + RETURN_LONG(ce->info.user.line_start); } RETURN_FALSE; } @@ -3557,7 +3557,7 @@ } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_CLASS) { - RETURN_LONG(ce->line_end); + RETURN_LONG(ce->info.user.line_end); } RETURN_FALSE; } @@ -3574,8 +3574,8 @@ return; } GET_REFLECTION_OBJECT_PTR(ce); - if (ce->type == ZEND_USER_CLASS && ce->doc_comment) { - RETURN_STRINGL(ce->doc_comment, ce->doc_comment_len, 1); + if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) { + RETURN_STRINGL(ce->info.user.doc_comment, ce->info.user.doc_comment_len, 1); } RETURN_FALSE; } @@ -4548,8 +4548,8 @@ METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->module) { - reflection_extension_factory(return_value, ce->module->name TSRMLS_CC); + if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) { + reflection_extension_factory(return_value, ce->info.internal.module->name TSRMLS_CC); } } /* }}} */ @@ -4568,8 +4568,8 @@ METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->module) { - RETURN_STRING(ce->module->name, 1); + if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) { + RETURN_STRING(ce->info.internal.module->name, 1); } else { RETURN_FALSE; } @@ -5271,7 +5271,7 @@ struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); int add_reflection_class = va_arg(args, int); - if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) { + if (((*pce)->type == ZEND_INTERNAL_CLASS) && (*pce)->info.internal.module && !strcasecmp((*pce)->info.internal.module->name, module->name)) { if (add_reflection_class) { ALLOC_ZVAL(zclass); zend_reflection_class_factory(*pce, zclass TSRMLS_CC); Index: Zend/zend.h =================================================================== --- Zend/zend.h (revision 303306) +++ Zend/zend.h (working copy) @@ -465,7 +465,6 @@ zend_uint name_length; struct _zend_class_entry *parent; int refcount; - zend_bool constants_updated; zend_uint ce_flags; HashTable function_table; @@ -476,7 +475,6 @@ HashTable constants_table; int default_properties_count; int default_static_members_count; - const struct _zend_function_entry *builtin_functions; union _zend_function *constructor; union _zend_function *destructor; @@ -511,13 +509,19 @@ zend_trait_alias **trait_aliases; zend_trait_precedence **trait_precedences; - char *filename; - zend_uint line_start; - zend_uint line_end; - char *doc_comment; - zend_uint doc_comment_len; - - struct _zend_module_entry *module; + union { + struct { + char *filename; + zend_uint line_start; + zend_uint line_end; + char *doc_comment; + zend_uint doc_comment_len; + } user; + struct { + const struct _zend_function_entry *builtin_functions; + struct _zend_module_entry *module; + } internal; + } info; }; #include "zend_stream.h" Index: Zend/zend_execute.c =================================================================== --- Zend/zend_execute.c (revision 303306) +++ Zend/zend_execute.c (working copy) @@ -1476,7 +1476,7 @@ 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.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); + ((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.fn_flags & ZEND_ACC_RETURN_REFERENCE)?return_value_ptr:NULL, execute_data_ptr->object, return_value_used TSRMLS_CC); } #define ZEND_VM_NEXT_OPCODE() \ Index: Zend/zend_closures.c =================================================================== --- Zend/zend_closures.c (revision 303306) +++ Zend/zend_closures.c (working copy) @@ -129,7 +129,7 @@ invoke->common = closure->func.common; invoke->type = ZEND_INTERNAL_FUNCTION; - invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER; + invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE); invoke->internal_function.handler = ZEND_MN(Closure___invoke); invoke->internal_function.module = 0; invoke->internal_function.scope = zend_ce_closure; Index: Zend/zend_object_handlers.c =================================================================== --- Zend/zend_object_handlers.c (revision 303306) +++ Zend/zend_object_handlers.c (working copy) @@ -938,15 +938,13 @@ { zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function)); call_user_call->type = ZEND_INTERNAL_FUNCTION; - call_user_call->module = ce->module; + call_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL; call_user_call->handler = zend_std_call_user_call; call_user_call->arg_info = NULL; call_user_call->num_args = 0; call_user_call->scope = ce; call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER; call_user_call->function_name = estrndup(method_name, method_len); - call_user_call->pass_rest_by_reference = 0; - call_user_call->return_reference = ZEND_RETURN_VALUE; return (union _zend_function *)call_user_call; } @@ -1083,15 +1081,13 @@ { zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function)); callstatic_user_call->type = ZEND_INTERNAL_FUNCTION; - callstatic_user_call->module = ce->module; + callstatic_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL; callstatic_user_call->handler = zend_std_callstatic_user_call; callstatic_user_call->arg_info = NULL; callstatic_user_call->num_args = 0; callstatic_user_call->scope = ce; callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER; callstatic_user_call->function_name = estrndup(method_name, method_len); - callstatic_user_call->pass_rest_by_reference = 0; - callstatic_user_call->return_reference = ZEND_RETURN_VALUE; return (zend_function *)callstatic_user_call; } Index: Zend/zend_compile.c =================================================================== --- Zend/zend_compile.c (revision 303306) +++ Zend/zend_compile.c (working copy) @@ -170,6 +170,16 @@ } /* }}} */ +void zend_init_compiler_context(TSRMLS_D) /* {{{ */ +{ + CG(context).opcodes_size = (CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) ? INITIAL_INTERACTIVE_OP_ARRAY_SIZE : INITIAL_OP_ARRAY_SIZE; + CG(context).vars_size = 0; + CG(context).literals_size = 0; + CG(context).current_brk_cont = -1; + CG(context).backpatch_count = 0; + CG(context).labels = NULL; +} +/* }}} */ void zend_init_compiler_data_structures(TSRMLS_D) /* {{{ */ { @@ -190,8 +200,7 @@ CG(has_bracketed_namespaces) = 0; CG(current_import) = NULL; init_compiler_declarables(TSRMLS_C); - zend_stack_init(&CG(labels_stack)); - CG(labels) = NULL; + zend_stack_init(&CG(context_stack)); #ifdef ZEND_MULTIBYTE CG(script_encoding_list) = NULL; @@ -238,7 +247,7 @@ zend_stack_destroy(&CG(list_stack)); zend_hash_destroy(&CG(filenames_table)); zend_llist_destroy(&CG(open_files)); - zend_stack_destroy(&CG(labels_stack)); + zend_stack_destroy(&CG(context_stack)); #ifdef ZEND_MULTIBYTE if (CG(script_encoding_list)) { @@ -317,9 +326,9 @@ } i = op_array->last_var; op_array->last_var++; - if (op_array->last_var > op_array->size_var) { - op_array->size_var += 16; /* FIXME */ - op_array->vars = erealloc(op_array->vars, op_array->size_var*sizeof(zend_compiled_variable)); + if (op_array->last_var > CG(context).vars_size) { + CG(context).vars_size += 16; /* FIXME */ + op_array->vars = erealloc(op_array->vars, CG(context).vars_size * sizeof(zend_compiled_variable)); } op_array->vars[i].name = zend_new_interned_string(name, name_len + 1, 1 TSRMLS_CC); op_array->vars[i].name_len = name_len; @@ -343,9 +352,9 @@ { 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 (i >= CG(context).literals_size) { + CG(context).literals_size += 16; /* FIXME */ + op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal)); } if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) { zval *z = (zval*)zv; @@ -1049,8 +1058,8 @@ zend_brk_cont_element *brk_cont_element; int parent; - parent = CG(active_op_array)->current_brk_cont; - CG(active_op_array)->current_brk_cont = CG(active_op_array)->last_brk_cont; + parent = CG(context).current_brk_cont; + CG(context).current_brk_cont = CG(active_op_array)->last_brk_cont; brk_cont_element = get_next_brk_cont_element(CG(active_op_array)); brk_cont_element->start = get_next_op_number(CG(active_op_array)); brk_cont_element->parent = parent; @@ -1063,11 +1072,11 @@ /* The start fileld is used to free temporary variables in case of exceptions. * We won't try to free something of we don't have loop variable. */ - CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].start = -1; + CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].start = -1; } - CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].cont = cont_addr; - CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].brk = get_next_op_number(CG(active_op_array)); - CG(active_op_array)->current_brk_cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].parent; + CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = cont_addr; + CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array)); + CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent; } /* }}} */ @@ -1539,9 +1548,10 @@ CG(interactive) = orig_interactive; op_array.function_name = name; - op_array.return_reference = return_reference; + if (return_reference) { + op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE; + } op_array.fn_flags |= fn_flags; - op_array.pass_rest_by_reference = 0; op_array.scope = is_method?CG(active_class_entry):NULL; op_array.prototype = NULL; @@ -1555,6 +1565,9 @@ zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name); } + zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); + zend_init_compiler_context(TSRMLS_C); + if (fn_flags & ZEND_ACC_ABSTRACT) { CG(active_class_entry)->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; } @@ -1683,6 +1696,8 @@ CALCULATE_LITERAL_HASH(opline->op2.constant); opline->extended_value = ZEND_DECLARE_FUNCTION; 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)); + zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); + zend_init_compiler_context(TSRMLS_C); } if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) { @@ -1721,9 +1736,6 @@ CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } - - zend_stack_push(&CG(labels_stack), (void *) &CG(labels), sizeof(HashTable*)); - CG(labels) = NULL; } /* }}} */ @@ -2225,18 +2237,17 @@ void zend_do_label(znode *label TSRMLS_DC) /* {{{ */ { - zend_op_array *oparray = CG(active_op_array); zend_label dest; - if (!CG(labels)) { - ALLOC_HASHTABLE(CG(labels)); - zend_hash_init(CG(labels), 4, NULL, NULL, 0); + if (!CG(context).labels) { + ALLOC_HASHTABLE(CG(context).labels); + zend_hash_init(CG(context).labels, 4, NULL, NULL, 0); } - dest.brk_cont = oparray->current_brk_cont; - dest.opline_num = get_next_op_number(oparray); + dest.brk_cont = CG(context).current_brk_cont; + dest.opline_num = get_next_op_number(CG(active_op_array)); - if (zend_hash_add(CG(labels), Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) { + if (zend_hash_add(CG(context).labels, Z_STRVAL(label->u.constant), Z_STRLEN(label->u.constant) + 1, (void**)&dest, sizeof(zend_label), NULL) == FAILURE) { zend_error(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL(label->u.constant)); } @@ -2256,8 +2267,8 @@ } else { label = &CONSTANT_EX(op_array, opline->op2.constant); } - if (CG(labels) == NULL || - zend_hash_find(CG(labels), Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) { + if (CG(context).labels == NULL || + zend_hash_find(CG(context).labels, Z_STRVAL_P(label), Z_STRLEN_P(label)+1, (void**)&dest) == FAILURE) { if (pass2) { CG(in_compilation) = 1; @@ -2310,7 +2321,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_GOTO; - opline->extended_value = CG(active_op_array)->current_brk_cont; + opline->extended_value = CG(context).current_brk_cont; SET_UNUSED(opline->op1); SET_NODE(opline->op2, label); zend_resolve_goto_label(CG(active_op_array), opline, 0 TSRMLS_CC); @@ -2319,18 +2330,16 @@ void zend_release_labels(TSRMLS_D) /* {{{ */ { - if (CG(labels)) { - zend_hash_destroy(CG(labels)); - FREE_HASHTABLE(CG(labels)); + if (CG(context).labels) { + zend_hash_destroy(CG(context).labels); + FREE_HASHTABLE(CG(context).labels); } - if (!zend_stack_is_empty(&CG(labels_stack))) { - HashTable **pht; + if (!zend_stack_is_empty(&CG(context_stack))) { + zend_compiler_context *ctx; - zend_stack_top(&CG(labels_stack), (void**)&pht); - CG(labels) = *pht; - zend_stack_del_top(&CG(labels_stack)); - } else { - CG(labels) = NULL; + zend_stack_top(&CG(context_stack), (void**)&ctx); + CG(context) = *ctx; + zend_stack_del_top(&CG(context_stack)); } } /* }}} */ @@ -2611,7 +2620,7 @@ int start_op_number, end_op_number; if (do_end_vparse) { - if (CG(active_op_array)->return_reference && !zend_is_function_or_method_call(expr)) { + if ((CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) && !zend_is_function_or_method_call(expr)) { zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC); } else { zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC); @@ -2636,7 +2645,7 @@ opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = (CG(active_op_array)->return_reference == ZEND_RETURN_REF) ? ZEND_RETURN_BY_REF : ZEND_RETURN; + opline->opcode = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) ? ZEND_RETURN_BY_REF : ZEND_RETURN; if (expr) { SET_NODE(opline->op1, expr); @@ -2942,12 +2951,13 @@ } if (fe->common.type != ZEND_USER_FUNCTION - && proto->common.pass_rest_by_reference - && !fe->common.pass_rest_by_reference) { + && (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0 + && (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) { return 0; } - if (fe->common.return_reference != proto->common.return_reference) { + if ((fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != + (proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) { return 0; } @@ -2976,7 +2986,7 @@ } } - if (proto->common.pass_rest_by_reference) { + if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) { for (i=proto->common.num_args; i < fe->common.num_args; i++) { if (!fe->common.arg_info[i].pass_by_reference) { return 0; @@ -3543,7 +3553,6 @@ } } fe->op_array.opcodes = opcode_copy; - fe->op_array.start_op = fe->op_array.opcodes; fe->op_array.function_name = newname; /* was setting it to fe which does not work since fe is stack allocated and not a stable address */ @@ -3570,9 +3579,9 @@ fe->op_array.brk_cont_array = (zend_brk_cont_element*)estrndup((char*)fe->op_array.brk_cont_array, sizeof(zend_brk_cont_element) * fe->op_array.last_brk_cont); /* TODO: check whether there is something similar and whether that is ok */ - literals_copy = (zend_literal*)emalloc(fe->op_array.size_literal * sizeof(zend_literal)); + literals_copy = (zend_literal*)emalloc(fe->op_array.last_literal * sizeof(zend_literal)); - for (i = 0; i < fe->op_array.size_literal; i++) { + for (i = 0; i < fe->op_array.last_literal; i++) { literals_copy[i] = fe->op_array.literals[i]; zval_copy_ctor(&literals_copy[i].constant); } @@ -4320,7 +4329,7 @@ zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = op; - opline->op1.opline_num = CG(active_op_array)->current_brk_cont; + opline->op1.opline_num = CG(context).current_brk_cont; SET_UNUSED(opline->op1); if (expr) { SET_NODE(opline->op2, expr); @@ -4369,8 +4378,8 @@ } /* remember break/continue loop information */ - CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].brk = get_next_op_number(CG(active_op_array)); - CG(active_op_array)->current_brk_cont = CG(active_op_array)->brk_cont_array[CG(active_op_array)->current_brk_cont].parent; + CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].brk = get_next_op_number(CG(active_op_array)); + CG(context).current_brk_cont = CG(active_op_array)->brk_cont_array[CG(context).current_brk_cont].parent; if (switch_entry_ptr->cond.op_type==IS_VAR || switch_entry_ptr->cond.op_type==IS_TMP_VAR) { /* emit free for the switch condition*/ @@ -4525,8 +4534,8 @@ new_class_entry->name_length = Z_STRLEN(class_name->u.constant); 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.op.opline_num; + new_class_entry->info.user.filename = zend_get_compiled_filename(TSRMLS_C); + new_class_entry->info.user.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) { @@ -4572,8 +4581,8 @@ GET_NODE(&CG(implementing_class), opline->result); if (CG(doc_comment)) { - CG(active_class_entry)->doc_comment = CG(doc_comment); - CG(active_class_entry)->doc_comment_len = CG(doc_comment_len); + CG(active_class_entry)->info.user.doc_comment = CG(doc_comment); + CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len); CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } @@ -4613,7 +4622,7 @@ } } - ce->line_end = zend_get_compiled_lineno(TSRMLS_C); + ce->info.user.line_end = zend_get_compiled_lineno(TSRMLS_C); /* Check for traits and proceed like with interfaces. * The only difference will be a combined handling of them in the end. @@ -6205,12 +6214,8 @@ dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ZVAL_INTERNAL_PTR_DTOR : ZVAL_PTR_DTOR); ce->refcount = 1; - ce->constants_updated = 0; ce->ce_flags = 0; - ce->doc_comment = NULL; - ce->doc_comment_len = 0; - ce->default_properties_table = NULL; ce->default_static_members_table = NULL; zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); @@ -6233,6 +6238,8 @@ #endif } else { ce->static_members_table = ce->default_static_members_table; + ce->info.user.doc_comment = NULL; + ce->info.user.doc_comment_len = 0; } ce->default_properties_count = 0; @@ -6261,12 +6268,14 @@ ce->traits = NULL; ce->trait_aliases = NULL; ce->trait_precedences = NULL; - ce->module = NULL; ce->serialize = NULL; ce->unserialize = NULL; ce->serialize_func = NULL; ce->unserialize_func = NULL; - ce->builtin_functions = NULL; + if (ce->type == ZEND_INTERNAL_CLASS) { + ce->info.internal.module = NULL; + ce->info.internal.builtin_functions = NULL; + } } } /* }}} */ @@ -6456,7 +6465,7 @@ efree(c_ns_name); } else if (zend_hash_find(CG(class_table), lcname, Z_STRLEN_P(name)+1, (void**)&pce) == SUCCESS && (*pce)->type == ZEND_USER_CLASS && - (*pce)->filename == CG(compiled_filename)) { + (*pce)->info.user.filename == CG(compiled_filename)) { char *c_tmp = zend_str_tolower_dup(Z_STRVAL_P(ns), Z_STRLEN_P(ns)); if (Z_STRLEN_P(ns) != Z_STRLEN_P(name) || Index: Zend/zend_compile.h =================================================================== --- Zend/zend_compile.h (revision 303306) +++ Zend/zend_compile.h (working copy) @@ -36,8 +36,8 @@ #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--); } +#define INC_BPC(op_array) if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { (CG(context).backpatch_count++); } +#define DEC_BPC(op_array) if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { (CG(context).backpatch_count--); } #define HANDLE_INTERACTIVE() if (CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) { execute_new_code(TSRMLS_C); } #define RESET_DOC_COMMENT() \ @@ -52,6 +52,15 @@ typedef struct _zend_op_array zend_op_array; typedef struct _zend_op zend_op; +typedef struct _zend_compiler_context { + zend_uint opcodes_size; + int vars_size; + int literals_size; + int current_brk_cont; + int backpatch_count; + HashTable *labels; +} zend_compiler_context; + typedef struct _zend_literal { zval constant; zend_ulong hash_value; @@ -171,6 +180,9 @@ #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000 #define ZEND_ACC_IMPLEMENT_TRAITS 0x400000 +/* class constants updated */ +#define ZEND_ACC_CONSTANTS_UPDATED 0x100000 + /* user class has methods with static variables */ #define ZEND_HAS_STATIC_IN_METHODS 0x800000 @@ -180,6 +192,12 @@ /* function flag for internal user call handlers __call, __callstatic */ #define ZEND_ACC_CALL_VIA_HANDLER 0x200000 +#define ZEND_ACC_PASS_REST_BY_REFERENCE 0x1000000 +#define ZEND_ACC_PASS_REST_PREFER_REF 0x2000000 + +#define ZEND_ACC_RETURN_REFERENCE 0x4000000 +#define ZEND_ACC_DONE_PASS_TWO 0x8000000 + char *zend_visibility_string(zend_uint fn_flags); @@ -203,10 +221,22 @@ zend_uchar type_hint; zend_bool allow_null; zend_bool pass_by_reference; - zend_bool return_reference; - int required_num_args; } zend_arg_info; +/* the following structure repeats the layout of zend_arg_info, + * but its fields have different meaning. It's used as the first element of + * arg_info array to define properties of internal functions. + */ +typedef struct _zend_internal_function_info { + const char *_name; + zend_uint _name_len; + const char *_class_name; + zend_uint required_num_args; + zend_uchar _type_hint; + zend_bool return_reference; + zend_bool pass_rest_by_reference; +} zend_internal_function_info; + typedef struct _zend_compiled_variable { char *name; int name_len; @@ -223,25 +253,20 @@ zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; - zend_bool pass_rest_by_reference; - unsigned char return_reference; /* END of common elements */ - zend_bool done_pass_two; - zend_uint *refcount; zend_op *opcodes; - zend_uint last, size; + zend_uint last; zend_compiled_variable *vars; - int last_var, size_var; + int last_var; zend_uint T; zend_brk_cont_element *brk_cont_array; int last_brk_cont; - int current_brk_cont; zend_try_catch_element *try_catch_array; int last_try_catch; @@ -249,9 +274,6 @@ /* static variables support */ HashTable *static_variables; - zend_op *start_op; - int backpatch_count; - zend_uint this_var; char *filename; @@ -262,7 +284,7 @@ zend_uint early_binding; /* the linked list of delayed declarations */ zend_literal *literals; - int last_literal, size_literal; + int last_literal; void **run_time_cache; int last_cache_slot; @@ -284,8 +306,6 @@ zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; - zend_bool pass_rest_by_reference; - unsigned char return_reference; /* END of common elements */ void (*handler)(INTERNAL_FUNCTION_PARAMETERS); @@ -306,8 +326,6 @@ zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; - zend_bool pass_rest_by_reference; - unsigned char return_reference; } common; zend_op_array op_array; @@ -374,6 +392,7 @@ void init_compiler(TSRMLS_D); void shutdown_compiler(TSRMLS_D); void zend_init_compiler_data_structures(TSRMLS_D); +void zend_init_compiler_context(TSRMLS_D); extern ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type TSRMLS_DC); extern ZEND_API zend_op_array *(*zend_compile_string)(zval *source_string, char *filename TSRMLS_DC); @@ -602,6 +621,7 @@ ZEND_API void function_add_ref(zend_function *function); #define INITIAL_OP_ARRAY_SIZE 64 +#define INITIAL_INTERACTIVE_OP_ARRAY_SIZE 8192 /* helper functions in zend_language_scanner.l */ @@ -766,22 +786,21 @@ #define ZEND_SEND_BY_REF 1 #define ZEND_SEND_PREFER_REF 2 -#define ARG_SEND_TYPE(zf, arg_num) \ - ((zf) ? \ - ((((zend_function*)(zf))->common.arg_info && \ - arg_num<=((zend_function*)(zf))->common.num_args) ? \ - ((zend_function *)(zf))->common.arg_info[arg_num-1].pass_by_reference : \ - ((zend_function *)(zf))->common.pass_rest_by_reference) : \ - ZEND_SEND_BY_VAL) +#define CHECK_ARG_SEND_TYPE(zf, arg_num, m1, m2) \ + ((zf) && \ + ((((zend_function*)(zf))->common.arg_info && \ + arg_num <= ((zend_function*)(zf))->common.num_args) ? \ + (((zend_function *)(zf))->common.arg_info[arg_num-1].pass_by_reference & (m1)) : \ + (((zend_function *)(zf))->common.fn_flags & (m2)))) #define ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \ - (ARG_SEND_TYPE(zf, arg_num) == ZEND_SEND_BY_REF) + CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF, ZEND_ACC_PASS_REST_BY_REFERENCE) #define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \ - (ARG_SEND_TYPE(zf, arg_num) & (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)) + CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF, ZEND_ACC_PASS_REST_BY_REFERENCE|ZEND_ACC_PASS_REST_PREFER_REF) #define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \ - (ARG_SEND_TYPE(zf, arg_num) == ZEND_SEND_PREFER_REF) + CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_PREFER_REF, ZEND_ACC_PASS_REST_PREFER_REF) #define ZEND_RETURN_VAL 0 #define ZEND_RETURN_REF 1 Index: Zend/zend_vm_def.h =================================================================== --- Zend/zend_vm_def.h (revision 303306) +++ Zend/zend_vm_def.h (working copy) @@ -2578,7 +2578,7 @@ 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; + ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; if (fbc->common.arg_info) { zend_uint i=0; @@ -2593,7 +2593,7 @@ if (!zend_execute_internal) { /* saves one function call if zend_execute_internal is not used */ - 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); + fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_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); } @@ -2612,7 +2612,7 @@ 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; + ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; } if (EXPECTED(zend_execute == execute)) { Index: Zend/zend_vm_execute.skl =================================================================== --- Zend/zend_vm_execute.skl (revision 303306) +++ Zend/zend_vm_execute.skl (working copy) @@ -55,7 +55,7 @@ } } - EX(opline) = op_array->start_op ? op_array->start_op : op_array->opcodes; + EX(opline) = UNEXPECTED((op_array->fn_flags & ZEND_ACC_INTERACTIVE) != 0) && EG(start_op) ? EG(start_op) : op_array->opcodes; EG(opline_ptr) = &EX(opline); LOAD_OPLINE(); Index: Zend/zend_language_scanner.l =================================================================== --- Zend/zend_language_scanner.l (revision 303306) +++ Zend/zend_language_scanner.l (working copy) @@ -351,6 +351,7 @@ init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); CG(in_compilation) = 1; CG(active_op_array) = op_array; + zend_init_compiler_context(TSRMLS_C); compiler_result = zendparse(TSRMLS_C); zend_do_return(&retval_znode, 0 TSRMLS_CC); CG(in_compilation) = original_in_compilation; @@ -515,6 +516,7 @@ init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); CG(interactive) = orig_interactive; CG(active_op_array) = op_array; + zend_init_compiler_context(TSRMLS_C); BEGIN(ST_IN_SCRIPTING); compiler_result = zendparse(TSRMLS_C); Index: Zend/zend_API.c =================================================================== --- Zend/zend_API.c (revision 303306) +++ Zend/zend_API.c (working copy) @@ -1015,7 +1015,7 @@ ZEND_API void zend_update_class_constants(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ { - if (!class_type->constants_updated || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) { + if ((class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) == 0 || (!CE_STATIC_MEMBERS(class_type) && class_type->default_static_members_count)) { zend_class_entry **scope = EG(in_execution)?&EG(scope):&CG(active_class_entry); zend_class_entry *old_scope = *scope; int i; @@ -1070,7 +1070,7 @@ } *scope = old_scope; - class_type->constants_updated = 1; + class_type->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED; } } /* }}} */ @@ -1953,36 +1953,44 @@ internal_function->function_name = (char*)ptr->fname; internal_function->scope = scope; internal_function->prototype = NULL; + if (ptr->flags) { + if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { + if (ptr->flags != ZEND_ACC_DEPRECATED || scope) { + zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : "", scope ? "::" : "", ptr->fname); + } + internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags; + } else { + internal_function->fn_flags = ptr->flags; + } + } else { + internal_function->fn_flags = ZEND_ACC_PUBLIC; + } if (ptr->arg_info) { + zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info; + internal_function->arg_info = (zend_arg_info*)ptr->arg_info+1; internal_function->num_args = ptr->num_args; /* Currently you cannot denote that the function can accept less arguments than num_args */ - if (ptr->arg_info[0].required_num_args == -1) { + if (info->required_num_args == -1) { internal_function->required_num_args = ptr->num_args; } else { - internal_function->required_num_args = ptr->arg_info[0].required_num_args; + internal_function->required_num_args = info->required_num_args; } - internal_function->pass_rest_by_reference = ptr->arg_info[0].pass_by_reference; - internal_function->return_reference = ptr->arg_info[0].return_reference; + if (info->pass_rest_by_reference) { + if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) { + internal_function->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF; + } else { + internal_function->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE; + } + } + if (info->return_reference) { + internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE; + } } else { internal_function->arg_info = NULL; internal_function->num_args = 0; internal_function->required_num_args = 0; - internal_function->pass_rest_by_reference = 0; - internal_function->return_reference = 0; } - if (ptr->flags) { - if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { - if (ptr->flags != ZEND_ACC_DEPRECATED || scope) { - zend_error(error_type, "Invalid access level for %s%s%s() - access must be exactly one of public, protected or private", scope ? scope->name : "", scope ? "::" : "", ptr->fname); - } - internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags; - } else { - internal_function->fn_flags = ptr->flags; - } - } else { - internal_function->fn_flags = ZEND_ACC_PUBLIC; - } if (ptr->flags & ZEND_ACC_ABSTRACT) { if (scope) { /* This is a class that must be abstract itself. Here we set the check info. */ @@ -2353,10 +2361,10 @@ class_entry->type = ZEND_INTERNAL_CLASS; zend_initialize_class_data(class_entry, 0 TSRMLS_CC); class_entry->ce_flags = ce_flags; - class_entry->module = EG(current_module); + class_entry->info.internal.module = EG(current_module); - if (class_entry->builtin_functions) { - zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC); + if (class_entry->info.internal.builtin_functions) { + zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC); } zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length); @@ -2712,15 +2720,13 @@ if (strict_class && ce_org->__call) { fcc->function_handler = emalloc(sizeof(zend_internal_function)); fcc->function_handler->internal_function.type = ZEND_INTERNAL_FUNCTION; - fcc->function_handler->internal_function.module = ce_org->module; + fcc->function_handler->internal_function.module = (ce_org->type == ZEND_INTERNAL_CLASS) ? ce_org->info.internal.module : NULL; fcc->function_handler->internal_function.handler = zend_std_call_user_call; fcc->function_handler->internal_function.arg_info = NULL; fcc->function_handler->internal_function.num_args = 0; fcc->function_handler->internal_function.scope = ce_org; fcc->function_handler->internal_function.fn_flags = ZEND_ACC_CALL_VIA_HANDLER; fcc->function_handler->internal_function.function_name = estrndup(mname, mlen); - fcc->function_handler->internal_function.pass_rest_by_reference = 0; - fcc->function_handler->internal_function.return_reference = ZEND_RETURN_VALUE; call_via_handler = 1; retval = 1; } else if (Z_OBJ_HT_P(fcc->object_ptr)->get_method) { Index: Zend/zend_API.h =================================================================== --- Zend/zend_API.h (revision 303306) +++ Zend/zend_API.h (working copy) @@ -96,14 +96,14 @@ #define ZEND_NS_FALIAS(ns, name, alias, arg_info) ZEND_NS_FENTRY(ns, name, ZEND_FN(alias), arg_info, 0) #define ZEND_NS_DEP_FALIAS(ns, name, alias, arg_info) ZEND_NS_FENTRY(ns, name, ZEND_FN(alias), arg_info, ZEND_ACC_DEPRECATED) -#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref, 0, 0 }, -#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_CLASS, allow_null, pass_by_ref, 0, 0 }, -#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref, 0, 0 }, -#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref, 0, 0 }, +#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref}, +#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref}, +#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_CLASS, allow_null, pass_by_ref}, +#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref}, +#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref}, #define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \ static const zend_arg_info name[] = { \ - { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args }, + { NULL, 0, NULL, required_num_args, 0, return_reference, pass_rest_by_reference}, #define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) \ ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() }; @@ -173,7 +173,6 @@ class_container.name = zend_strndup(cl_name, _len); \ } \ class_container.name_length = _len; \ - class_container.builtin_functions = functions; \ class_container.constructor = NULL; \ class_container.destructor = NULL; \ class_container.clone = NULL; \ @@ -202,7 +201,8 @@ class_container.interfaces = NULL; \ class_container.get_iterator = NULL; \ class_container.iterator_funcs.funcs = NULL; \ - class_container.module = NULL; \ + class_container.info.internal.module = NULL; \ + class_container.info.internal.builtin_functions = functions; \ } #define INIT_OVERLOADED_CLASS_ENTRY(class_container, class_name, functions, handle_fcall, handle_propget, handle_propset) \ Index: Zend/zend_globals.h =================================================================== --- Zend/zend_globals.h (revision 303306) +++ Zend/zend_globals.h (working copy) @@ -139,8 +139,8 @@ zend_bool in_namespace; zend_bool has_bracketed_namespaces; - HashTable *labels; - zend_stack labels_stack; + zend_compiler_context context; + zend_stack context_stack; /* interned strings */ char *interned_strings_start; @@ -265,6 +265,8 @@ zend_bool active; + zend_op *start_op; + void *saved_fpu_cw_ptr; #if XPFPA_HAVE_CW XPFPA_CW_DATATYPE saved_fpu_cw; Index: Zend/zend_execute_API.c =================================================================== --- Zend/zend_execute_API.c (revision 303306) +++ Zend/zend_execute_API.c (working copy) @@ -194,6 +194,7 @@ EG(active_op_array) = NULL; EG(active) = 1; + EG(start_op) = NULL; } /* }}} */ @@ -1256,7 +1257,7 @@ int orig_interactive; if (!(CG(active_op_array)->fn_flags & ZEND_ACC_INTERACTIVE) - || CG(active_op_array)->backpatch_count>0 + || CG(context).backpatch_count>0 || CG(active_op_array)->function_name || CG(active_op_array)->type!=ZEND_USER_FUNCTION) { return; @@ -1268,11 +1269,11 @@ 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) { - CG(active_op_array)->start_op = CG(active_op_array)->opcodes; + if (!EG(start_op)) { + EG(start_op) = CG(active_op_array)->opcodes; } - opline=CG(active_op_array)->start_op; + opline=EG(start_op); end=CG(active_op_array)->opcodes+CG(active_op_array)->last; while (oplinelast -= 1; /* get rid of that ZEND_RETURN */ - CG(active_op_array)->start_op = CG(active_op_array)->opcodes+CG(active_op_array)->last; + EG(start_op) = CG(active_op_array)->opcodes+CG(active_op_array)->last; } /* }}} */ Index: Zend/zend_opcode.c =================================================================== --- Zend/zend_opcode.c (revision 303306) +++ Zend/zend_opcode.c (working copy) @@ -43,31 +43,28 @@ } } -static void op_array_alloc_ops(zend_op_array *op_array) +static void op_array_alloc_ops(zend_op_array *op_array, zend_uint size) { - op_array->opcodes = erealloc(op_array->opcodes, (op_array->size)*sizeof(zend_op)); + op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op)); } void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC) { op_array->type = type; - op_array->backpatch_count = 0; if (CG(interactive)) { /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants * will become invalid */ - initial_ops_size = 8192; + initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE; } op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint)); *op_array->refcount = 1; - op_array->size = initial_ops_size; op_array->last = 0; op_array->opcodes = NULL; - op_array_alloc_ops(op_array); + op_array_alloc_ops(op_array, initial_ops_size); - op_array->size_var = 0; op_array->last_var = 0; op_array->vars = NULL; @@ -87,23 +84,16 @@ op_array->brk_cont_array = NULL; op_array->try_catch_array = NULL; op_array->last_brk_cont = 0; - op_array->current_brk_cont = -1; op_array->static_variables = NULL; op_array->last_try_catch = 0; - op_array->return_reference = 0; - op_array->done_pass_two = 0; - op_array->this_var = -1; - op_array->start_op = NULL; - op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0; op_array->early_binding = -1; - op_array->size_literal = 0; op_array->last_literal = 0; op_array->literals = NULL; @@ -309,8 +299,8 @@ if (ce->num_interfaces > 0 && ce->interfaces) { efree(ce->interfaces); } - if (ce->doc_comment) { - efree(ce->doc_comment); + if (ce->info.user.doc_comment) { + efree(ce->info.user.doc_comment); } _destroy_zend_class_traits_info(ce); @@ -345,9 +335,6 @@ if (ce->num_interfaces > 0) { free(ce->interfaces); } - if (ce->doc_comment) { - free(ce->doc_comment); - } free(ce); break; } @@ -410,7 +397,7 @@ if (op_array->try_catch_array) { efree(op_array->try_catch_array); } - if (op_array->done_pass_two) { + if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) { zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC); } if (op_array->arg_info) { @@ -436,15 +423,15 @@ zend_uint next_op_num = op_array->last++; zend_op *next_op; - if (next_op_num >= op_array->size) { + if (next_op_num >= CG(context).opcodes_size) { if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) { /* we messed up */ zend_printf("Ran out of opcode space!\n" "You should probably consider writing this huge script into a file!\n"); zend_bailout(); } - op_array->size *= 4; - op_array_alloc_ops(op_array); + CG(context).opcodes_size *= 4; + op_array_alloc_ops(op_array, CG(context).opcodes_size); } next_op = &(op_array->opcodes[next_op_num]); @@ -510,13 +497,17 @@ zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC); } - if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && op_array->size != op_array->last) { + if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) { + op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var); + CG(context).vars_size = op_array->last_var; + } + if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) { op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last); - op_array->size = op_array->last; + CG(context).opcodes_size = op_array->last; } - if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && op_array->size_literal != op_array->last_literal) { + if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != 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; + CG(context).literals_size = op_array->last_literal; } opline = op_array->opcodes; @@ -549,7 +540,7 @@ opline++; } - op_array->done_pass_two = 1; + op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO; return 0; } --------------050400000701060201050802--