diff options
author | Zeev Suraski <zeev@php.net> | 1999-05-15 15:47:24 +0000 |
---|---|---|
committer | Zeev Suraski <zeev@php.net> | 1999-05-15 15:47:24 +0000 |
commit | b0bfa458b5c30a2992eb3f433d9e57b32195e3fb (patch) | |
tree | 0abf2dafddf9d636aefe460db52766af220b2c9d /Zend | |
parent | d2c16bf5bd084dce9893061f9d878c379aba3ce1 (diff) | |
download | php-git-b0bfa458b5c30a2992eb3f433d9e57b32195e3fb.tar.gz |
* Fix all hash checks that checked Bucket.arKey for NULL, when it was changed
to char[1], these checks should have been changed to Bucket.nKeyLength==0
* Support runtime declaration of functions. I ended up changing the grammar
to catch top level functions vs. nested functions. The reason is simple -
if we don't have functions properly declared at compile-time, function calls
cannot be resolved at compile time, and have to be resolved at runtime, which
ends up being much much slower (without the optimizer, that is).
It's no biggy though, the grammar change isn't that bad.
Diffstat (limited to 'Zend')
-rw-r--r-- | Zend/zend-parser.y | 60 | ||||
-rw-r--r-- | Zend/zend.c | 2 | ||||
-rw-r--r-- | Zend/zend.h | 2 | ||||
-rw-r--r-- | Zend/zend_compile.c | 76 | ||||
-rw-r--r-- | Zend/zend_compile.h | 17 | ||||
-rw-r--r-- | Zend/zend_execute.c | 5 | ||||
-rw-r--r-- | Zend/zend_hash.c | 6 |
7 files changed, 136 insertions, 32 deletions
diff --git a/Zend/zend-parser.y b/Zend/zend-parser.y index 660b490fae..7d338c97e2 100644 --- a/Zend/zend-parser.y +++ b/Zend/zend-parser.y @@ -125,16 +125,34 @@ %% /* Rules */ -statement_list: - statement_list { do_extended_info(CLS_C); } statement { ELS_FETCH(); HANDLE_INTERACTIVE(); } +top_statement_list: + top_statement_list { do_extended_info(CLS_C); } top_statement { ELS_FETCH(); HANDLE_INTERACTIVE(); } | /* empty */ ; +top_statement: + statement + | declaration_statement { do_early_binding(CLS_C); } +; + + +inner_statement_list: + inner_statement_list { do_extended_info(CLS_C); } inner_statement { ELS_FETCH(); HANDLE_INTERACTIVE(); } + | /* empty */ +; + + +inner_statement: + statement + | declaration_statement +; + + statement: - '{' statement_list '}' + '{' inner_statement_list '}' | T_IF '(' expr ')' { do_if_cond(&$3, &$4 CLS_CC); } statement { do_if_after_statement(&$4, 1 CLS_CC); } elseif_list else_single { do_if_end(CLS_C); } - | T_IF '(' expr ')' ':' { do_if_cond(&$3, &$4 CLS_CC); } statement_list { do_if_after_statement(&$4, 1 CLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { do_if_end(CLS_C); } + | T_IF '(' expr ')' ':' { do_if_cond(&$3, &$4 CLS_CC); } inner_statement_list { do_if_after_statement(&$4, 1 CLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { do_if_end(CLS_C); } | T_WHILE '(' { $1.u.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { do_while_cond(&$4, &$5 CLS_CC); } while_statement { do_while_end(&$1, &$5 CLS_CC); } | T_DO { $1.u.opline_num = get_next_op_number(CG(active_op_array)); do_do_while_begin(CLS_C); } statement T_WHILE '(' expr ')' ';' { do_do_while_end(&$1, &$6 CLS_CC); } | T_FOR @@ -151,16 +169,10 @@ statement: | T_BREAK expr ';' { do_brk_cont(ZEND_BRK, &$2 CLS_CC); } | T_CONTINUE ';' { do_brk_cont(ZEND_CONT, NULL CLS_CC); } | T_CONTINUE expr ';' { do_brk_cont(ZEND_CONT, &$2 CLS_CC); } - | T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); } - '(' parameter_list ')' '{' statement_list '}' { do_end_function_declaration(&$1 CLS_CC); } - | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); } - parameter_list '(' statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); } | T_RETURN ';' { do_return(NULL CLS_CC); } | T_RETURN expr ';' { do_return(&$2 CLS_CC); } | T_GLOBAL global_var_list | T_STATIC static_var_list - | T_CLASS T_STRING { do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); } - | T_CLASS T_STRING T_EXTENDS T_STRING { do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); } | T_ECHO echo_expr_list ';' | T_INLINE_HTML { do_echo(&$1 CLS_CC); } | expr ';' { do_free(&$1 CLS_CC); } @@ -172,6 +184,16 @@ statement: ; +declaration_statement: + T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); } + '(' parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); } + | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 0 CLS_CC); } + parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); } + | T_CLASS T_STRING { do_begin_class_declaration(&$2, NULL CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); } + | T_CLASS T_STRING T_EXTENDS T_STRING { do_begin_class_declaration(&$2, &$4 CLS_CC); } '{' class_statement_list '}' { do_end_class_declaration(CLS_C); } +; + + foreach_optional_arg: /* empty */ { $$.op_type = IS_UNUSED; } | T_DOUBLE_ARROW w_cvar { $$ = $2; } @@ -180,13 +202,13 @@ foreach_optional_arg: for_statement: statement - | ':' statement_list T_ENDFOR ';' + | ':' inner_statement_list T_ENDFOR ';' ; foreach_statement: statement - | ':' statement_list T_ENDFOREACH ';' + | ':' inner_statement_list T_ENDFOREACH ';' ; @@ -200,8 +222,8 @@ switch_case_list: case_list: /* empty */ { $$.u.opline_num = -1; } - | case_list T_CASE expr case_separator { do_case_before_statement(&$1, &$2, &$3 CLS_CC); } statement_list { do_case_after_statement(&$$, &$2 CLS_CC); } - | case_list T_DEFAULT case_separator { do_default_before_statement(&$1, &$2 CLS_CC); } statement_list { do_case_after_statement(&$$, &$2 CLS_CC); } + | case_list T_CASE expr case_separator { do_case_before_statement(&$1, &$2, &$3 CLS_CC); } inner_statement_list { do_case_after_statement(&$$, &$2 CLS_CC); } + | case_list T_DEFAULT case_separator { do_default_before_statement(&$1, &$2 CLS_CC); } inner_statement_list { do_case_after_statement(&$$, &$2 CLS_CC); } ; @@ -213,7 +235,7 @@ case_separator: while_statement: statement - | ':' statement_list T_ENDWHILE ';' + | ':' inner_statement_list T_ENDWHILE ';' ; @@ -226,7 +248,7 @@ elseif_list: new_elseif_list: /* empty */ - | new_elseif_list T_ELSEIF '(' expr ')' ':' { do_if_cond(&$4, &$5 CLS_CC); } statement_list { do_if_after_statement(&$5, 0 CLS_CC); } + | new_elseif_list T_ELSEIF '(' expr ')' ':' { do_if_cond(&$4, &$5 CLS_CC); } inner_statement_list { do_if_after_statement(&$5, 0 CLS_CC); } ; @@ -238,7 +260,7 @@ else_single: new_else_single: /* empty */ - | T_ELSE ':' statement_list + | T_ELSE ':' inner_statement_list ; @@ -310,9 +332,9 @@ class_statement_list: class_statement: T_VAR class_variable_decleration ';' | T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); } '(' - parameter_list ')' '{' statement_list '}' { do_end_function_declaration(&$1 CLS_CC); } + parameter_list ')' '{' inner_statement_list '}' { do_end_function_declaration(&$1 CLS_CC); } | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } T_STRING { do_begin_function_declaration(&$1, &$3, 1 CLS_CC); } - parameter_list '(' statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); } + parameter_list '(' inner_statement_list ')' ';' { do_end_function_declaration(&$1 CLS_CC); } ; diff --git a/Zend/zend.c b/Zend/zend.c index f9b0640d09..0ede40804b 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -320,6 +320,7 @@ void zenderror(char *error) } +BEGIN_EXTERN_C() ZEND_API void zend_bailout() { CLS_FETCH(); @@ -328,6 +329,7 @@ ZEND_API void zend_bailout() CG(unclean_shutdown) = 1; longjmp(EG(bailout), FAILURE); } +END_EXTERN_C() void zend_append_version_info(zend_extension *extension) diff --git a/Zend/zend.h b/Zend/zend.h index 0f4bd25744..2a397b9a53 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -173,7 +173,9 @@ typedef struct { int zend_startup(zend_utility_functions *utility_functions, char **extensions); void zend_shutdown(); void zend_set_utility_values(zend_utility_values *utility_values); +BEGIN_EXTERN_C() ZEND_API void zend_bailout(); +END_EXTERN_C() ZEND_API char *get_zend_version(); ZEND_API int zend_print_zval(zval *expr, int indent); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index bb4d1ee2aa..cf5a1dcc16 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -622,7 +622,18 @@ void do_begin_function_declaration(znode *function_token, znode *function_name, if (is_method) { zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); } else { - zend_hash_add(CG(function_table), name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); + zend_op *opline = get_next_op(CG(active_op_array) CLS_CC); + + opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS; + opline->op1.op_type = IS_CONST; + opline->op1.u.constant.type = IS_LONG; + opline->op1.u.constant.value.lval = zend_hash_next_free_element(CG(function_table)); + opline->op2.op_type = IS_CONST; + opline->op2.u.constant.type = IS_STRING; + opline->op2.u.constant.value.str.val = estrndup(name, name_len); + opline->op2.u.constant.value.str.len = name_len; + opline->extended_value = ZEND_DECLARE_FUNCTION; + zend_hash_next_index_insert(CG(function_table), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); } if (CG(extended_info)) { @@ -825,6 +836,53 @@ void do_return(znode *expr CLS_DC) } +void do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table) +{ + switch (opline->extended_value) { + case ZEND_DECLARE_FUNCTION: { + zend_function *function; + + zend_hash_index_find(function_table, opline->op1.u.constant.value.lval, (void **) &function); + (*function->op_array.refcount)++; + 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) { + zend_error(E_ERROR, "Cannot redeclare %s()", opline->op2.u.constant.value.str.val); + } + } + break; + case ZEND_DECLARE_CLASS: { + zend_class_entry *ce; + + zend_hash_index_find(class_table, opline->op1.u.constant.value.lval, (void **) &ce); + (*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) { + zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); + } + } + break; + } +} + + +void do_early_binding(CLS_D) +{ + zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; + + do_bind_function_or_class(opline, CG(function_table), CG(class_table)); + switch (opline->extended_value) { + case ZEND_DECLARE_FUNCTION: + zend_hash_index_del(CG(function_table), opline->op1.u.constant.value.lval); + break; + case ZEND_DECLARE_CLASS: + zend_hash_index_del(CG(class_table), opline->op1.u.constant.value.lval); + break; + } + zval_dtor(&opline->op2.u.constant); + opline->opcode = ZEND_NOP; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); +} + + void do_boolean_or_begin(znode *expr1, znode *op_token CLS_DC) { int next_op_number = get_next_op_number(CG(active_op_array)); @@ -1101,6 +1159,8 @@ static void function_add_ref(zend_function *function) void do_begin_class_declaration(znode *class_name, znode *parent_class_name CLS_DC) { + zend_op *opline = get_next_op(CG(active_op_array) CLS_CC); + if (CG(active_class_entry)) { zend_error(E_COMPILE_ERROR, "Class declarations may not be nested"); return; @@ -1141,9 +1201,17 @@ void do_begin_class_declaration(znode *class_name, znode *parent_class_name CLS_ CG(class_entry).handle_property_set = NULL; CG(class_entry).handle_property_get = NULL; - if (zend_hash_add(CG(class_table), CG(class_entry).name, CG(class_entry).name_length+1, &CG(class_entry), sizeof(zend_class_entry), (void **) &CG(active_class_entry))==FAILURE) { - zend_error(E_COMPILE_ERROR, "Class %s cannot be redeclared", CG(class_entry).name); - } + opline->opcode = ZEND_DECLARE_FUNCTION_OR_CLASS; + opline->op1.op_type = IS_CONST; + opline->op1.u.constant.type = IS_LONG; + opline->op1.u.constant.value.lval = zend_hash_next_free_element(CG(function_table)); + opline->op2.op_type = IS_CONST; + opline->op2.u.constant.type = IS_STRING; + opline->op2.u.constant.value.str.val = estrndup(CG(class_entry).name, CG(class_entry).name_length); + opline->op2.u.constant.value.str.len = CG(class_entry).name_length; + opline->extended_value = ZEND_DECLARE_CLASS; + + zend_hash_next_index_insert(CG(class_table), &CG(class_entry), sizeof(zend_class_entry), (void **) &CG(active_class_entry)); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 8002c66ce1..1a1f46dfcd 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -257,6 +257,8 @@ void do_begin_dynamic_function_call(znode *function_name CLS_DC); void do_begin_class_member_function_call(znode *class_name, znode *function_name CLS_DC); void do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method CLS_DC); void do_return(znode *expr CLS_DC); +void do_bind_function_or_class(zend_op *opline, HashTable *function_table, HashTable *class_table); +void do_early_binding(CLS_D); void do_pass_param(znode *param, int op, int offset CLS_DC); @@ -476,12 +478,14 @@ int zendlex(znode *zendlval CLS_DC); #define ZEND_FETCH_DIM_TMP_VAR 89 #define ZEND_FETCH_CONSTANT 90 -#define ZEND_INIT_GLOBALS 91 +#define ZEND_DECLARE_FUNCTION_OR_CLASS 91 -#define ZEND_EXT_STMT 92 -#define ZEND_EXT_FCALL_BEGIN 93 -#define ZEND_EXT_FCALL_END 94 -#define ZEND_EXT_NOP 95 +#define ZEND_INIT_GLOBALS 92 + +#define ZEND_EXT_STMT 93 +#define ZEND_EXT_FCALL_BEGIN 94 +#define ZEND_EXT_FCALL_END 95 +#define ZEND_EXT_NOP 96 /* end of block */ @@ -524,4 +528,7 @@ int zendlex(znode *zendlval CLS_DC); #define ZEND_HANDLE_FP 2 #define ZEND_HANDLE_ISTREAM 3 +#define ZEND_DECLARE_CLASS 1 +#define ZEND_DECLARE_FUNCTION 2 + #endif /* _COMPILE_H */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index ee56394f1e..2c6f04120e 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1304,7 +1304,7 @@ binary_assign_op_addr: { active_function_table = EG(function_table); } if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { - zend_error(E_ERROR, "Call to undefined function: %s()\n", function_name->value.str.val); + zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); } zval_dtor(&tmp); function_being_called = function; @@ -1890,6 +1890,9 @@ send_by_ref: zend_llist_apply_with_argument(&zend_extensions, (void (*)(void *, void *)) zend_extension_fcall_end_handler, op_array); } break; + case ZEND_DECLARE_FUNCTION_OR_CLASS: + do_bind_function_or_class(opline, EG(function_table), EG(class_table)); + break; case ZEND_INIT_GLOBALS: { zval *globals = (zval *) emalloc(sizeof(zval)); diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 4cb93c9c69..710d2418dd 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -779,7 +779,7 @@ ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct) (void *)) q = p; p = p->pListNext; if (destruct(q->pData)) { - if (q->arKey == NULL) { + if (q->nKeyLength==0) { zend_hash_index_del(ht, q->h); } else { zend_hash_del(ht,q->arKey,q->nKeyLength); @@ -798,7 +798,7 @@ ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct) (void q = p; p = p->pListNext; if (destruct(q->pData, argument)) { - if (q->arKey == NULL) { + if (q->nKeyLength == 0) { zend_hash_index_del(ht, q->h); } else { zend_hash_del(ht,q->arKey,q->nKeyLength); @@ -837,7 +837,7 @@ ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, void (*pCopy p = source->pListHead; while (p) { memcpy(tmp, p->pData, size); - if (p->arKey) { + if (p->nKeyLength>0) { if (zend_hash_add(target, p->arKey, p->nKeyLength, tmp, size, &t)==SUCCESS && pCopyConstructor) { pCopyConstructor(t); } |