php-src/Zend/zend_compile.c

10290 lines
299 KiB
C
Raw Normal View History

1999-04-07 18:10:10 +00:00
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2019-01-30 09:23:29 +00:00
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
1999-04-07 18:10:10 +00:00
+----------------------------------------------------------------------+
2001-12-11 15:16:21 +00:00
| 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: |
2001-12-11 15:16:21 +00:00
| http://www.zend.com/license/2_00.txt. |
1999-07-16 14:58:16 +00:00
| 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. |
1999-04-07 18:10:10 +00:00
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Nikita Popov <nikic@php.net> |
1999-04-07 18:10:10 +00:00
+----------------------------------------------------------------------+
*/
#include <zend_language_parser.h>
1999-04-07 18:10:10 +00:00
#include "zend.h"
#include "zend_attributes.h"
1999-04-07 18:10:10 +00:00
#include "zend_compile.h"
2003-04-10 17:02:31 +00:00
#include "zend_constants.h"
1999-04-07 18:10:10 +00:00
#include "zend_llist.h"
#include "zend_API.h"
#include "zend_exceptions.h"
#include "zend_interfaces.h"
#include "zend_virtual_cwd.h"
#include "zend_multibyte.h"
#include "zend_language_scanner.h"
#include "zend_inheritance.h"
#include "zend_vm.h"
#include "zend_enum.h"
#define SET_NODE(target, src) do { \
target ## _type = (src)->op_type; \
if ((src)->op_type == IS_CONST) { \
target.constant = zend_add_literal(&(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) { \
ZVAL_COPY_VALUE(&(target)->u.constant, CT_CONSTANT(src)); \
} else { \
(target)->u.op = src; \
} \
} while (0)
#define FC(member) (CG(file_context).member)
2015-07-10 11:30:25 +00:00
typedef struct _zend_loop_var {
zend_uchar opcode;
zend_uchar var_type;
uint32_t var_num;
uint32_t try_catch_offset;
2015-07-10 11:30:25 +00:00
} zend_loop_var;
static inline uint32_t zend_alloc_cache_slots(unsigned count) {
if (count == 0) {
/* Even if no cache slots are desired, the VM handler may still want to acquire
* CACHE_ADDR() unconditionally. Returning zero makes sure that the address
* calculation is still legal and ubsan does not complain. */
return 0;
}
zend_op_array *op_array = CG(active_op_array);
uint32_t ret = op_array->cache_size;
op_array->cache_size += count * sizeof(void*);
return ret;
}
static inline uint32_t zend_alloc_cache_slot(void) {
return zend_alloc_cache_slots(1);
}
2014-12-13 22:06:14 +00:00
ZEND_API zend_op_array *(*zend_compile_file)(zend_file_handle *file_handle, int type);
ZEND_API zend_op_array *(*zend_compile_string)(zend_string *source_string, const char *filename);
1999-04-07 18:10:10 +00:00
#ifndef ZTS
ZEND_API zend_compiler_globals compiler_globals;
ZEND_API zend_executor_globals executor_globals;
#endif
static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2);
static bool zend_try_ct_eval_array(zval *result, zend_ast *ast);
static void init_op(zend_op *op)
{
MAKE_NOP(op);
op->extended_value = 0;
op->lineno = CG(zend_lineno);
}
static zend_always_inline uint32_t get_next_op_number(void)
{
return CG(active_op_array)->last;
}
static zend_op *get_next_op(void)
{
zend_op_array *op_array = CG(active_op_array);
uint32_t next_op_num = op_array->last++;
zend_op *next_op;
if (UNEXPECTED(next_op_num >= CG(context).opcodes_size)) {
CG(context).opcodes_size *= 4;
op_array->opcodes = erealloc(op_array->opcodes, CG(context).opcodes_size * sizeof(zend_op));
}
next_op = &(op_array->opcodes[next_op_num]);
init_op(next_op);
return next_op;
}
static zend_brk_cont_element *get_next_brk_cont_element(void)
{
CG(context).last_brk_cont++;
CG(context).brk_cont_array = erealloc(CG(context).brk_cont_array, sizeof(zend_brk_cont_element) * CG(context).last_brk_cont);
return &CG(context).brk_cont_array[CG(context).last_brk_cont-1];
}
static zend_string *zend_build_runtime_definition_key(zend_string *name, uint32_t start_lineno) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_string *filename = CG(active_op_array)->filename;
zend_string *result = zend_strpprintf(0, "%c%s%s:%" PRIu32 "$%" PRIx32,
'\0', ZSTR_VAL(name), ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
2014-12-13 22:06:14 +00:00
return zend_new_interned_string(result);
}
2014-08-29 05:05:58 +00:00
/* }}} */
static bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */
{
const char *ns_separator = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (ns_separator != NULL) {
*result = ns_separator + 1;
*result_len = ZSTR_VAL(name) + ZSTR_LEN(name) - *result;
return 1;
}
return 0;
}
/* }}} */
struct reserved_class_name {
const char *name;
size_t len;
};
static const struct reserved_class_name reserved_class_names[] = {
{ZEND_STRL("bool")},
{ZEND_STRL("false")},
{ZEND_STRL("float")},
{ZEND_STRL("int")},
{ZEND_STRL("null")},
{ZEND_STRL("parent")},
{ZEND_STRL("self")},
{ZEND_STRL("static")},
{ZEND_STRL("string")},
{ZEND_STRL("true")},
2015-10-14 18:15:32 +00:00
{ZEND_STRL("void")},
{ZEND_STRL("never")},
2016-06-03 22:42:04 +00:00
{ZEND_STRL("iterable")},
{ZEND_STRL("object")},
{ZEND_STRL("mixed")},
{NULL, 0}
};
static bool zend_is_reserved_class_name(const zend_string *name) /* {{{ */
{
const struct reserved_class_name *reserved = reserved_class_names;
const char *uqname = ZSTR_VAL(name);
size_t uqname_len = ZSTR_LEN(name);
zend_get_unqualified_name(name, &uqname, &uqname_len);
for (; reserved->name; ++reserved) {
if (uqname_len == reserved->len
&& zend_binary_strcasecmp(uqname, uqname_len, reserved->name, reserved->len) == 0
) {
return 1;
}
}
return 0;
}
/* }}} */
void zend_assert_valid_class_name(const zend_string *name) /* {{{ */
{
if (zend_is_reserved_class_name(name)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use '%s' as class name as it is reserved", ZSTR_VAL(name));
}
}
/* }}} */
typedef struct _builtin_type_info {
2015-02-01 14:22:48 +00:00
const char* name;
const size_t name_len;
const zend_uchar type;
} builtin_type_info;
2015-02-01 14:22:48 +00:00
static const builtin_type_info builtin_types[] = {
{ZEND_STRL("null"), IS_NULL},
{ZEND_STRL("false"), IS_FALSE},
2015-11-09 11:15:58 +00:00
{ZEND_STRL("int"), IS_LONG},
{ZEND_STRL("float"), IS_DOUBLE},
{ZEND_STRL("string"), IS_STRING},
{ZEND_STRL("bool"), _IS_BOOL},
2015-10-14 18:15:32 +00:00
{ZEND_STRL("void"), IS_VOID},
{ZEND_STRL("never"), IS_NEVER},
2016-06-03 22:42:04 +00:00
{ZEND_STRL("iterable"), IS_ITERABLE},
{ZEND_STRL("object"), IS_OBJECT},
{ZEND_STRL("mixed"), IS_MIXED},
2015-02-01 14:22:48 +00:00
{NULL, 0, IS_UNDEF}
};
typedef struct {
const char *name;
size_t name_len;
const char *correct_name;
} confusable_type_info;
static const confusable_type_info confusable_types[] = {
{ZEND_STRL("boolean"), "bool"},
{ZEND_STRL("integer"), "int"},
{ZEND_STRL("double"), "float"},
{ZEND_STRL("resource"), NULL},
{NULL, 0, NULL},
};
static zend_always_inline zend_uchar zend_lookup_builtin_type_by_name(const zend_string *name) /* {{{ */
2015-02-01 14:22:48 +00:00
{
const builtin_type_info *info = &builtin_types[0];
for (; info->name; ++info) {
if (ZSTR_LEN(name) == info->name_len
&& zend_binary_strcasecmp(ZSTR_VAL(name), ZSTR_LEN(name), info->name, info->name_len) == 0
) {
return info->type;
2015-02-01 14:22:48 +00:00
}
}
return 0;
2015-02-01 14:22:48 +00:00
}
/* }}} */
static zend_always_inline bool zend_is_confusable_type(const zend_string *name, const char **correct_name) /* {{{ */
{
const confusable_type_info *info = confusable_types;
/* Intentionally using case-sensitive comparison here, because "integer" is likely intended
* as a scalar type, while "Integer" is likely a class type. */
for (; info->name; ++info) {
if (ZSTR_LEN(name) == info->name_len
&& memcmp(ZSTR_VAL(name), info->name, info->name_len) == 0
) {
*correct_name = info->correct_name;
return 1;
}
}
return 0;
}
/* }}} */
static bool zend_is_not_imported(zend_string *name) {
/* Assuming "name" is unqualified here. */
return !FC(imports) || zend_hash_find_ptr_lc(FC(imports), name) == NULL;
}
2015-02-01 14:22:48 +00:00
void zend_oparray_context_begin(zend_oparray_context *prev_context) /* {{{ */
{
*prev_context = CG(context);
CG(context).opcodes_size = INITIAL_OP_ARRAY_SIZE;
CG(context).vars_size = 0;
CG(context).literals_size = 0;
CG(context).fast_call_var = -1;
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
CG(context).try_catch_offset = -1;
CG(context).current_brk_cont = -1;
CG(context).last_brk_cont = 0;
CG(context).brk_cont_array = NULL;
CG(context).labels = NULL;
}
/* }}} */
void zend_oparray_context_end(zend_oparray_context *prev_context) /* {{{ */
{
if (CG(context).brk_cont_array) {
efree(CG(context).brk_cont_array);
CG(context).brk_cont_array = NULL;
}
if (CG(context).labels) {
zend_hash_destroy(CG(context).labels);
FREE_HASHTABLE(CG(context).labels);
CG(context).labels = NULL;
}
CG(context) = *prev_context;
}
/* }}} */
static void zend_reset_import_tables(void) /* {{{ */
{
if (FC(imports)) {
zend_hash_destroy(FC(imports));
efree(FC(imports));
FC(imports) = NULL;
}
if (FC(imports_function)) {
zend_hash_destroy(FC(imports_function));
efree(FC(imports_function));
FC(imports_function) = NULL;
}
if (FC(imports_const)) {
zend_hash_destroy(FC(imports_const));
efree(FC(imports_const));
FC(imports_const) = NULL;
}
}
/* }}} */
static void zend_end_namespace(void) /* {{{ */ {
FC(in_namespace) = 0;
zend_reset_import_tables();
if (FC(current_namespace)) {
zend_string_release_ex(FC(current_namespace), 0);
FC(current_namespace) = NULL;
}
}
/* }}} */
void zend_file_context_begin(zend_file_context *prev_context) /* {{{ */
{
*prev_context = CG(file_context);
FC(imports) = NULL;
FC(imports_function) = NULL;
FC(imports_const) = NULL;
FC(current_namespace) = NULL;
FC(in_namespace) = 0;
FC(has_bracketed_namespaces) = 0;
FC(declarables).ticks = 0;
zend_hash_init(&FC(seen_symbols), 8, NULL, NULL, 0);
}
/* }}} */
void zend_file_context_end(zend_file_context *prev_context) /* {{{ */
{
zend_end_namespace();
zend_hash_destroy(&FC(seen_symbols));
CG(file_context) = *prev_context;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_init_compiler_data_structures(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
2015-07-10 11:30:25 +00:00
zend_stack_init(&CG(loop_var_stack), sizeof(zend_loop_var));
zend_stack_init(&CG(delayed_oplines_stack), sizeof(zend_op));
zend_stack_init(&CG(short_circuiting_opnums), sizeof(uint32_t));
1999-04-07 18:10:10 +00:00
CG(active_class_entry) = NULL;
CG(in_compilation) = 0;
CG(skip_shebang) = 0;
CG(encoding_declared) = 0;
CG(memoized_exprs) = NULL;
CG(memoize_mode) = 0;
}
2009-07-27 14:11:53 +00:00
/* }}} */
static void zend_register_seen_symbol(zend_string *name, uint32_t kind) {
zval *zv = zend_hash_find(&FC(seen_symbols), name);
if (zv) {
Z_LVAL_P(zv) |= kind;
} else {
zval tmp;
ZVAL_LONG(&tmp, kind);
zend_hash_add_new(&FC(seen_symbols), name, &tmp);
}
}
static bool zend_have_seen_symbol(zend_string *name, uint32_t kind) {
zval *zv = zend_hash_find(&FC(seen_symbols), name);
return zv && (Z_LVAL_P(zv) & kind) != 0;
}
2014-12-13 22:06:14 +00:00
void init_compiler(void) /* {{{ */
{
CG(arena) = zend_arena_create(64 * 1024);
CG(active_op_array) = NULL;
2012-11-14 13:45:10 +00:00
memset(&CG(context), 0, sizeof(CG(context)));
2014-12-13 22:06:14 +00:00
zend_init_compiler_data_structures();
zend_init_rsrc_list();
zend_stream_init();
CG(unclean_shutdown) = 0;
Support full variance if autoloading is used Keep track of delayed variance obligations and check them after linking a class is otherwise finished. Obligations may either be unresolved method compatibility (because the necessecary classes aren't available yet) or open parent/interface dependencies. The latter occur because we allow the use of not fully linked classes as parents/interfaces now. An important aspect of the implementation is we do not require classes involved in variance checks to be fully linked in order for the class to be fully linked. Because the involved types do have to exist in the class table (as partially linked classes) and we do check these for correct variance, we have the guarantee that either those classes will successfully link lateron or generate an error, but there is no way to actually use them until that point and as such no possibility of violating the variance contract. This is important because it ensures that a class declaration always either errors or will produce an immediately usable class afterwards -- there are no cases where the finalization of the class declaration has to be delayed until a later time, as earlier variants of this patch did. Because variance checks deal with classes in various stages of linking, we need to use a special instanceof implementation that supports this, and also introduce finer-grained flags that tell us which parts have been linked already and which haven't. Class autoloading for variance checks is delayed into a separate stage after the class is otherwise linked and before delayed variance obligations are processed. This separation is needed to handle cases like A extends B extends C, where B is the autoload root, but C is required to check variance. This could end up loading C while the class structure of B is in an inconsistent state.
2019-05-27 09:39:56 +00:00
CG(delayed_variance_obligations) = NULL;
CG(delayed_autoloads) = NULL;
CG(unlinked_uses) = NULL;
CG(current_linking_class) = NULL;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void shutdown_compiler(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
/* Reset filename before destroying the arena, as file cache may use arena allocated strings. */
zend_restore_compiled_filename(NULL);
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
zend_stack_destroy(&CG(loop_var_stack));
zend_stack_destroy(&CG(delayed_oplines_stack));
zend_stack_destroy(&CG(short_circuiting_opnums));
Support full variance if autoloading is used Keep track of delayed variance obligations and check them after linking a class is otherwise finished. Obligations may either be unresolved method compatibility (because the necessecary classes aren't available yet) or open parent/interface dependencies. The latter occur because we allow the use of not fully linked classes as parents/interfaces now. An important aspect of the implementation is we do not require classes involved in variance checks to be fully linked in order for the class to be fully linked. Because the involved types do have to exist in the class table (as partially linked classes) and we do check these for correct variance, we have the guarantee that either those classes will successfully link lateron or generate an error, but there is no way to actually use them until that point and as such no possibility of violating the variance contract. This is important because it ensures that a class declaration always either errors or will produce an immediately usable class afterwards -- there are no cases where the finalization of the class declaration has to be delayed until a later time, as earlier variants of this patch did. Because variance checks deal with classes in various stages of linking, we need to use a special instanceof implementation that supports this, and also introduce finer-grained flags that tell us which parts have been linked already and which haven't. Class autoloading for variance checks is delayed into a separate stage after the class is otherwise linked and before delayed variance obligations are processed. This separation is needed to handle cases like A extends B extends C, where B is the autoload root, but C is required to check variance. This could end up loading C while the class structure of B is in an inconsistent state.
2019-05-27 09:39:56 +00:00
if (CG(delayed_variance_obligations)) {
zend_hash_destroy(CG(delayed_variance_obligations));
FREE_HASHTABLE(CG(delayed_variance_obligations));
CG(delayed_variance_obligations) = NULL;
}
if (CG(delayed_autoloads)) {
zend_hash_destroy(CG(delayed_autoloads));
FREE_HASHTABLE(CG(delayed_autoloads));
CG(delayed_autoloads) = NULL;
}
if (CG(unlinked_uses)) {
zend_hash_destroy(CG(unlinked_uses));
FREE_HASHTABLE(CG(unlinked_uses));
CG(unlinked_uses) = NULL;
}
CG(current_linking_class) = NULL;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_string *zend_set_compiled_filename(zend_string *new_compiled_filename) /* {{{ */
1999-04-07 18:10:10 +00:00
{
CG(compiled_filename) = zend_string_copy(new_compiled_filename);
2015-09-11 02:58:24 +00:00
return new_compiled_filename;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API void zend_restore_compiled_filename(zend_string *original_compiled_filename) /* {{{ */
1999-04-07 18:10:10 +00:00
{
if (CG(compiled_filename)) {
zend_string_release(CG(compiled_filename));
CG(compiled_filename) = NULL;
}
1999-04-07 18:10:10 +00:00
CG(compiled_filename) = original_compiled_filename;
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
ZEND_API zend_string *zend_get_compiled_filename(void) /* {{{ */
{
return CG(compiled_filename);
}
2009-07-27 14:11:53 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
ZEND_API int zend_get_compiled_lineno(void) /* {{{ */
{
return CG(zend_lineno);
}
2009-07-27 14:11:53 +00:00
/* }}} */
ZEND_API bool zend_is_compiling(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
return CG(in_compilation);
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static zend_always_inline uint32_t get_temporary_variable(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
return (uint32_t)CG(active_op_array)->T++;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static int lookup_cv(zend_string *name) /* {{{ */{
zend_op_array *op_array = CG(active_op_array);
int i = 0;
2014-08-25 17:24:55 +00:00
zend_ulong hash_value = zend_string_hash_val(name);
while (i < op_array->last_var) {
2018-12-07 16:21:26 +00:00
if (ZSTR_H(op_array->vars[i]) == hash_value
&& zend_string_equals(op_array->vars[i], name)) {
return EX_NUM_TO_VAR(i);
}
i++;
}
i = op_array->last_var;
op_array->last_var++;
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_string*));
}
op_array->vars[i] = zend_string_copy(name);
return EX_NUM_TO_VAR(i);
}
2009-07-27 14:11:53 +00:00
/* }}} */
static inline zend_string *zval_make_interned_string(zval *zv) /* {{{ */
{
ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
Z_STR_P(zv) = zend_new_interned_string(Z_STR_P(zv));
if (ZSTR_IS_INTERNED(Z_STR_P(zv))) {
2018-01-16 22:58:51 +00:00
Z_TYPE_FLAGS_P(zv) = 0;
}
return Z_STR_P(zv);
}
/* Common part of zend_add_literal and zend_append_individual_literal */
2014-12-13 22:06:14 +00:00
static inline void zend_insert_literal(zend_op_array *op_array, zval *zv, int literal_position) /* {{{ */
{
zval *lit = CT_CONSTANT_EX(op_array, literal_position);
if (Z_TYPE_P(zv) == IS_STRING) {
zval_make_interned_string(zv);
}
ZVAL_COPY_VALUE(lit, zv);
Z_EXTRA_P(lit) = 0;
}
/* }}} */
/* Is used while compiling a function, using the context to keep track
of an approximate size to avoid to relocate to often.
Literals are truncated to actual size in the second compiler pass (pass_two()). */
static int zend_add_literal(zval *zv) /* {{{ */
{
zend_op_array *op_array = CG(active_op_array);
int i = op_array->last_literal;
op_array->last_literal++;
if (i >= CG(context).literals_size) {
while (i >= CG(context).literals_size) {
CG(context).literals_size += 16; /* FIXME */
}
op_array->literals = (zval*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zval));
}
2014-12-13 22:06:14 +00:00
zend_insert_literal(op_array, zv, i);
return i;
}
/* }}} */
static inline int zend_add_literal_string(zend_string **str) /* {{{ */
{
int ret;
zval zv;
ZVAL_STR(&zv, *str);
ret = zend_add_literal(&zv);
*str = Z_STR(zv);
return ret;
}
2014-12-02 14:21:19 +00:00
/* }}} */
static int zend_add_func_name_literal(zend_string *name) /* {{{ */
{
/* Original name */
int ret = zend_add_literal_string(&name);
/* Lowercased name */
zend_string *lc_name = zend_string_tolower(name);
zend_add_literal_string(&lc_name);
return ret;
}
/* }}} */
static int zend_add_ns_func_name_literal(zend_string *name) /* {{{ */
{
const char *unqualified_name;
size_t unqualified_name_len;
/* Original name */
int ret = zend_add_literal_string(&name);
/* Lowercased name */
zend_string *lc_name = zend_string_tolower(name);
zend_add_literal_string(&lc_name);
/* Lowercased unqualified name */
if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) {
lc_name = zend_string_alloc(unqualified_name_len, 0);
zend_str_tolower_copy(ZSTR_VAL(lc_name), unqualified_name, unqualified_name_len);
zend_add_literal_string(&lc_name);
}
return ret;
}
/* }}} */
static int zend_add_class_name_literal(zend_string *name) /* {{{ */
2014-09-23 17:32:02 +00:00
{
/* Original name */
int ret = zend_add_literal_string(&name);
2014-07-19 21:30:07 +00:00
/* Lowercased name */
zend_string *lc_name = zend_string_tolower(name);
zend_add_literal_string(&lc_name);
return ret;
}
/* }}} */
static int zend_add_const_name_literal(zend_string *name, bool unqualified) /* {{{ */
{
zend_string *tmp_name;
int ret = zend_add_literal_string(&name);
size_t ns_len = 0, after_ns_len = ZSTR_LEN(name);
const char *after_ns = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (after_ns) {
after_ns += 1;
ns_len = after_ns - ZSTR_VAL(name) - 1;
after_ns_len = ZSTR_LEN(name) - ns_len - 1;
/* lowercased namespace name & original constant name */
tmp_name = zend_string_init(ZSTR_VAL(name), ZSTR_LEN(name), 0);
zend_str_tolower(ZSTR_VAL(tmp_name), ns_len);
zend_add_literal_string(&tmp_name);
if (!unqualified) {
return ret;
}
} else {
after_ns = ZSTR_VAL(name);
}
/* original unqualified constant name */
tmp_name = zend_string_init(after_ns, after_ns_len, 0);
zend_add_literal_string(&tmp_name);
return ret;
}
/* }}} */
#define LITERAL_STR(op, str) do { \
zval _c; \
ZVAL_STR(&_c, str); \
op.constant = zend_add_literal(&_c); \
} while (0)
void zend_stop_lexing(void)
{
2016-07-22 22:12:11 +00:00
if (LANG_SCNG(on_event)) {
LANG_SCNG(on_event)(ON_STOP, END, 0, NULL, 0, LANG_SCNG(on_event_context));
2016-07-22 22:12:11 +00:00
}
2014-07-22 13:50:23 +00:00
LANG_SCNG(yy_cursor) = LANG_SCNG(yy_limit);
}
static inline void zend_begin_loop(
zend_uchar free_opcode, const znode *loop_var, bool is_switch) /* {{{ */
{
1999-04-07 18:10:10 +00:00
zend_brk_cont_element *brk_cont_element;
int parent = CG(context).current_brk_cont;
2015-07-10 11:30:25 +00:00
zend_loop_var info = {0};
CG(context).current_brk_cont = CG(context).last_brk_cont;
brk_cont_element = get_next_brk_cont_element();
1999-04-07 18:10:10 +00:00
brk_cont_element->parent = parent;
brk_cont_element->is_switch = is_switch;
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
2015-07-10 11:30:25 +00:00
if (loop_var && (loop_var->op_type & (IS_VAR|IS_TMP_VAR))) {
uint32_t start = get_next_op_number();
info.opcode = free_opcode;
info.var_type = loop_var->op_type;
info.var_num = loop_var->u.op.var;
brk_cont_element->start = start;
} else {
2015-07-10 11:30:25 +00:00
info.opcode = ZEND_NOP;
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
/* The start field is used to free temporary variables in case of exceptions.
* We won't try to free something of we don't have loop variable. */
brk_cont_element->start = -1;
}
2015-07-10 11:30:25 +00:00
zend_stack_push(&CG(loop_var_stack), &info);
}
/* }}} */
static inline void zend_end_loop(int cont_addr, const znode *var_node) /* {{{ */
1999-04-07 18:10:10 +00:00
{
uint32_t end = get_next_op_number();
zend_brk_cont_element *brk_cont_element
= &CG(context).brk_cont_array[CG(context).current_brk_cont];
brk_cont_element->cont = cont_addr;
brk_cont_element->brk = end;
CG(context).current_brk_cont = brk_cont_element->parent;
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
2015-07-10 11:30:25 +00:00
zend_stack_del_top(&CG(loop_var_stack));
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_do_free(znode *op1) /* {{{ */
1999-04-07 18:10:10 +00:00
{
2016-03-17 13:10:08 +00:00
if (op1->op_type == IS_TMP_VAR) {
1999-04-07 18:10:10 +00:00
zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
while (opline->opcode == ZEND_END_SILENCE ||
opline->opcode == ZEND_OP_DATA) {
2016-03-17 13:10:08 +00:00
opline--;
}
if (opline->result_type == IS_TMP_VAR && opline->result.var == op1->u.op.var) {
switch (opline->opcode) {
case ZEND_BOOL:
case ZEND_BOOL_NOT:
/* boolean results don't have to be freed */
return;
case ZEND_POST_INC_STATIC_PROP:
case ZEND_POST_DEC_STATIC_PROP:
case ZEND_POST_INC_OBJ:
case ZEND_POST_DEC_OBJ:
case ZEND_POST_INC:
case ZEND_POST_DEC:
/* convert $i++ to ++$i */
opline->opcode -= 2;
opline->result_type = IS_UNUSED;
return;
case ZEND_ASSIGN:
case ZEND_ASSIGN_DIM:
case ZEND_ASSIGN_OBJ:
case ZEND_ASSIGN_STATIC_PROP:
case ZEND_ASSIGN_OP:
case ZEND_ASSIGN_DIM_OP:
case ZEND_ASSIGN_OBJ_OP:
case ZEND_ASSIGN_STATIC_PROP_OP:
case ZEND_PRE_INC_STATIC_PROP:
case ZEND_PRE_DEC_STATIC_PROP:
case ZEND_PRE_INC_OBJ:
case ZEND_PRE_DEC_OBJ:
case ZEND_PRE_INC:
case ZEND_PRE_DEC:
opline->result_type = IS_UNUSED;
return;
2016-03-17 13:10:08 +00:00
}
}
2016-03-20 00:34:56 +00:00
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
2016-03-17 13:10:08 +00:00
} else if (op1->op_type == IS_VAR) {
1999-04-07 18:10:10 +00:00
zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
2016-03-17 13:10:08 +00:00
while (opline->opcode == ZEND_END_SILENCE ||
opline->opcode == ZEND_EXT_FCALL_END ||
opline->opcode == ZEND_OP_DATA) {
1999-12-20 20:01:19 +00:00
opline--;
}
if (opline->result_type == IS_VAR
&& opline->result.var == op1->u.op.var) {
2018-06-26 13:18:30 +00:00
if (opline->opcode == ZEND_FETCH_THIS) {
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
opline->opcode = ZEND_NOP;
opline->result_type = IS_UNUSED;
} else {
opline->result_type = IS_UNUSED;
}
1999-04-07 18:10:10 +00:00
} else {
while (opline >= CG(active_op_array)->opcodes) {
if ((opline->opcode == ZEND_FETCH_LIST_R ||
opline->opcode == ZEND_FETCH_LIST_W) &&
opline->op1_type == IS_VAR &&
opline->op1.var == op1->u.op.var) {
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
return;
}
2016-03-17 13:10:08 +00:00
if (opline->result_type == IS_VAR
&& opline->result.var == op1->u.op.var) {
if (opline->opcode == ZEND_NEW) {
zend_emit_op(NULL, ZEND_FREE, op1, NULL);
}
break;
1999-04-07 18:10:10 +00:00
}
opline--;
}
}
} else if (op1->op_type == IS_CONST) {
/* Destroy value without using GC: When opcache moves arrays into SHM it will
* free the zend_array structure, so references to it from outside the op array
* become invalid. GC would cause such a reference in the root buffer. */
zval_ptr_dtor_nogc(&op1->u.constant);
}
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
{
uint32_t new_flags = flags | new_flag;
if ((flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flag & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
zend_throw_exception(zend_ce_compile_error,
"Multiple abstract modifiers are not allowed", 0);
return 0;
}
if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
return 0;
}
if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) {
zend_throw_exception(zend_ce_compile_error,
"Cannot use the final modifier on an abstract class", 0);
return 0;
}
return new_flags;
}
/* }}} */
2014-08-29 05:05:58 +00:00
uint32_t zend_add_member_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
{
uint32_t new_flags = flags | new_flag;
2014-07-27 10:17:36 +00:00
if ((flags & ZEND_ACC_PPP_MASK) && (new_flag & ZEND_ACC_PPP_MASK)) {
zend_throw_exception(zend_ce_compile_error,
"Multiple access type modifiers are not allowed", 0);
return 0;
}
2014-07-27 10:17:36 +00:00
if ((flags & ZEND_ACC_ABSTRACT) && (new_flag & ZEND_ACC_ABSTRACT)) {
zend_throw_exception(zend_ce_compile_error, "Multiple abstract modifiers are not allowed", 0);
return 0;
}
2014-07-27 10:17:36 +00:00
if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) {
zend_throw_exception(zend_ce_compile_error, "Multiple static modifiers are not allowed", 0);
return 0;
}
2014-07-27 10:17:36 +00:00
if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) {
zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0);
return 0;
}
2014-07-27 10:17:36 +00:00
if ((new_flags & ZEND_ACC_ABSTRACT) && (new_flags & ZEND_ACC_FINAL)) {
zend_throw_exception(zend_ce_compile_error,
"Cannot use the final modifier on an abstract class member", 0);
return 0;
}
2014-07-27 10:17:36 +00:00
return new_flags;
}
2014-08-29 05:05:58 +00:00
/* }}} */
ZEND_API zend_string *zend_create_member_string(zend_string *class_name, zend_string *member_name) {
return zend_string_concat3(
ZSTR_VAL(class_name), ZSTR_LEN(class_name),
"::", sizeof("::") - 1,
ZSTR_VAL(member_name), ZSTR_LEN(member_name));
}
2014-07-16 21:23:25 +00:00
zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2, size_t name2_len) {
2020-04-09 13:06:53 +00:00
return zend_string_concat3(name1, name1_len, "\\", 1, name2, name2_len);
2014-07-16 21:23:25 +00:00
}
2014-12-13 22:06:14 +00:00
zend_string *zend_prefix_with_ns(zend_string *name) {
if (FC(current_namespace)) {
zend_string *ns = FC(current_namespace);
return zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name));
} else {
return zend_string_copy(name);
}
2014-07-22 11:30:26 +00:00
}
zend_string *zend_resolve_non_class_name(
zend_string *name, uint32_t type, bool *is_fully_qualified,
bool case_sensitive, HashTable *current_import_sub
) {
char *compound;
2014-07-22 11:25:47 +00:00
*is_fully_qualified = 0;
if (ZSTR_VAL(name)[0] == '\\') {
2014-07-04 22:11:00 +00:00
/* Remove \ prefix (only relevant if this is a string rather than a label) */
2016-05-01 11:04:08 +00:00
*is_fully_qualified = 1;
return zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
}
1999-04-07 18:10:10 +00:00
2014-07-22 11:25:47 +00:00
if (type == ZEND_NAME_FQ) {
*is_fully_qualified = 1;
return zend_string_copy(name);
1999-04-07 18:10:10 +00:00
}
2014-07-22 11:25:47 +00:00
if (type == ZEND_NAME_RELATIVE) {
*is_fully_qualified = 1;
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns(name);
2014-07-22 11:25:47 +00:00
}
if (current_import_sub) {
2014-07-04 22:11:00 +00:00
/* If an unqualified name is a function/const alias, replace it. */
zend_string *import_name;
if (case_sensitive) {
2014-07-04 22:11:00 +00:00
import_name = zend_hash_find_ptr(current_import_sub, name);
} else {
import_name = zend_hash_find_ptr_lc(current_import_sub, name);
}
2014-07-04 22:11:00 +00:00
if (import_name) {
*is_fully_qualified = 1;
return zend_string_copy(import_name);
}
}
compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (compound) {
*is_fully_qualified = 1;
}
if (compound && FC(imports)) {
2014-07-04 22:11:00 +00:00
/* If the first part of a qualified name is an alias, substitute it. */
size_t len = compound - ZSTR_VAL(name);
zend_string *import_name = zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
2014-07-04 22:11:00 +00:00
if (import_name) {
return zend_concat_names(
ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
}
}
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns(name);
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
zend_string *zend_resolve_function_name(zend_string *name, uint32_t type, bool *is_fully_qualified) /* {{{ */
2014-08-29 05:05:58 +00:00
{
return zend_resolve_non_class_name(
name, type, is_fully_qualified, 0, FC(imports_function));
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bool *is_fully_qualified) /* {{{ */ {
return zend_resolve_non_class_name(
name, type, is_fully_qualified, 1, FC(imports_const));
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2007-09-28 19:52:53 +00:00
char *compound;
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
if (type == ZEND_NAME_FQ) {
zend_error_noreturn(E_COMPILE_ERROR,
"'\\%s' is an invalid class name", ZSTR_VAL(name));
}
if (type == ZEND_NAME_RELATIVE) {
zend_error_noreturn(E_COMPILE_ERROR,
"'namespace\\%s' is an invalid class name", ZSTR_VAL(name));
}
ZEND_ASSERT(type == ZEND_NAME_NOT_FQ);
return zend_string_copy(name);
}
2014-07-22 11:25:47 +00:00
if (type == ZEND_NAME_RELATIVE) {
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns(name);
2014-07-22 11:25:47 +00:00
}
if (type == ZEND_NAME_FQ) {
if (ZSTR_VAL(name)[0] == '\\') {
/* Remove \ prefix (only relevant if this is a string rather than a label) */
name = zend_string_init(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1, 0);
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(name)) {
zend_error_noreturn(E_COMPILE_ERROR,
"'\\%s' is an invalid class name", ZSTR_VAL(name));
}
return name;
}
return zend_string_copy(name);
}
if (FC(imports)) {
compound = memchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
2014-07-04 21:45:20 +00:00
if (compound) {
/* If the first part of a qualified name is an alias, substitute it. */
size_t len = compound - ZSTR_VAL(name);
zend_string *import_name =
zend_hash_str_find_ptr_lc(FC(imports), ZSTR_VAL(name), len);
2014-07-04 21:45:20 +00:00
2014-07-04 22:11:00 +00:00
if (import_name) {
2014-07-04 21:45:20 +00:00
return zend_concat_names(
ZSTR_VAL(import_name), ZSTR_LEN(import_name), ZSTR_VAL(name) + len + 1, ZSTR_LEN(name) - len - 1);
}
2014-07-04 21:45:20 +00:00
} else {
/* If an unqualified name is an alias, replace it. */
2014-07-04 22:11:00 +00:00
zend_string *import_name
= zend_hash_find_ptr_lc(FC(imports), name);
2014-07-04 21:45:20 +00:00
2014-07-04 22:11:00 +00:00
if (import_name) {
return zend_string_copy(import_name);
2007-09-28 19:52:53 +00:00
}
}
2014-07-04 21:45:20 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-04 21:45:20 +00:00
/* If not fully qualified and not an alias, prepend the current namespace */
2014-12-13 22:06:14 +00:00
return zend_prefix_with_ns(name);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_string *zend_resolve_class_name_ast(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zval *class_name = zend_ast_get_zval(ast);
if (Z_TYPE_P(class_name) != IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
}
return zend_resolve_class_name(Z_STR_P(class_name), ast->attr);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2015-08-12 03:15:09 +00:00
static void label_ptr_dtor(zval *zv) /* {{{ */
1999-04-07 18:10:10 +00:00
{
2015-08-12 03:15:09 +00:00
efree_size(Z_PTR_P(zv), sizeof(zend_label));
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-08-29 05:05:58 +00:00
static void str_dtor(zval *zv) /* {{{ */ {
zend_string_release_ex(Z_STR_P(zv), 0);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static bool zend_is_call(zend_ast *ast);
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
2014-12-13 22:06:14 +00:00
static uint32_t zend_add_try_element(uint32_t try_op) /* {{{ */
1999-04-07 18:10:10 +00:00
{
zend_op_array *op_array = CG(active_op_array);
uint32_t try_catch_offset = op_array->last_try_catch++;
zend_try_catch_element *elem;
1999-04-07 18:10:10 +00:00
op_array->try_catch_array = safe_erealloc(
op_array->try_catch_array, sizeof(zend_try_catch_element), op_array->last_try_catch, 0);
1999-04-07 18:10:10 +00:00
elem = &op_array->try_catch_array[try_catch_offset];
elem->try_op = try_op;
elem->catch_op = 0;
elem->finally_op = 0;
elem->finally_end = 0;
2004-07-20 08:58:18 +00:00
return try_catch_offset;
2001-12-16 19:45:49 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
void zend_init_static_variables_map_ptr(zend_op_array *op_array)
{
if (op_array->static_variables) {
ZEND_MAP_PTR_INIT(op_array->static_variables_ptr,
zend_arena_alloc(&CG(arena), sizeof(HashTable *)));
ZEND_MAP_PTR_SET(op_array->static_variables_ptr, NULL);
}
}
2009-07-27 14:11:53 +00:00
ZEND_API void function_add_ref(zend_function *function) /* {{{ */
1999-04-07 18:10:10 +00:00
{
if (function->type == ZEND_USER_FUNCTION) {
zend_op_array *op_array = &function->op_array;
if (op_array->refcount) {
(*op_array->refcount)++;
}
ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void *)));
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
zend_init_static_variables_map_ptr(op_array);
}
if (function->common.function_name) {
zend_string_addref(function->common.function_name);
1999-04-07 18:10:10 +00:00
}
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static zend_never_inline ZEND_COLD ZEND_NORETURN void do_bind_function_error(zend_string *lcname, zend_op_array *op_array, bool compile_time) /* {{{ */
{
zval *zv = zend_hash_find_ex(compile_time ? CG(function_table) : EG(function_table), lcname, 1);
int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
zend_function *old_function;
ZEND_ASSERT(zv != NULL);
old_function = (zend_function*)Z_PTR_P(zv);
if (old_function->type == ZEND_USER_FUNCTION
&& old_function->op_array.last > 0) {
zend_error_noreturn(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name),
ZSTR_VAL(old_function->op_array.filename),
old_function->op_array.opcodes[0].lineno);
} else {
zend_error_noreturn(error_level, "Cannot redeclare %s()",
op_array ? ZSTR_VAL(op_array->function_name) : ZSTR_VAL(old_function->common.function_name));
}
}
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname) /* {{{ */
{
zend_function *added_func = zend_hash_add_ptr(EG(function_table), Z_STR_P(lcname), func);
if (UNEXPECTED(!added_func)) {
do_bind_function_error(Z_STR_P(lcname), &func->op_array, 0);
return FAILURE;
}
if (func->op_array.refcount) {
++*func->op_array.refcount;
}
if (func->common.function_name) {
zend_string_addref(func->common.function_name);
2018-08-27 09:47:32 +00:00
}
return SUCCESS;
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */
2001-08-30 15:26:30 +00:00
{
zend_class_entry *ce;
zval *rtd_key, *zv;
rtd_key = lcname + 1;
2007-09-28 19:52:53 +00:00
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
2001-08-30 15:26:30 +00:00
if (UNEXPECTED(!zv)) {
ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
if (ce) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
return FAILURE;
} else {
do {
2020-03-12 19:26:30 +00:00
ZEND_ASSERT(EG(current_execute_data)->func->op_array.fn_flags & ZEND_ACC_PRELOADED);
if (zend_preload_autoload
&& zend_preload_autoload(EG(current_execute_data)->func->op_array.filename) == SUCCESS) {
zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
if (EXPECTED(zv != NULL)) {
break;
}
}
zend_error_noreturn(E_ERROR, "Class %s wasn't preloaded", Z_STRVAL_P(lcname));
return FAILURE;
} while (0);
}
}
/* Register the derived class */
ce = (zend_class_entry*)Z_PTR_P(zv);
zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, Z_STR_P(lcname));
if (UNEXPECTED(!zv)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
return FAILURE;
2012-08-14 00:59:40 +00:00
}
if (ce->ce_flags & ZEND_ACC_LINKED) {
return SUCCESS;
}
ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
if (!ce) {
/* Reload bucket pointer, the hash table may have been reallocated */
zv = zend_hash_find(EG(class_table), Z_STR_P(lcname));
zend_hash_set_bucket_key(EG(class_table), (Bucket *) zv, Z_STR_P(rtd_key));
return FAILURE;
}
return SUCCESS;
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
static zend_string *add_type_string(zend_string *type, zend_string *new_type) {
zend_string *result;
if (type == NULL) {
return zend_string_copy(new_type);
}
2020-04-14 15:17:38 +00:00
result = zend_string_concat3(
ZSTR_VAL(type), ZSTR_LEN(type), "|", 1, ZSTR_VAL(new_type), ZSTR_LEN(new_type));
zend_string_release(type);
return result;
}
static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scope) {
if (scope) {
if (zend_string_equals_literal_ci(name, "self")) {
name = scope->name;
} else if (zend_string_equals_literal_ci(name, "parent") && scope->parent) {
name = scope->parent->name;
}
}
/* The resolved name for anonymous classes contains null bytes. Cut off everything after the
* null byte here, to avoid larger parts of the type being omitted by printing code later. */
size_t len = strlen(ZSTR_VAL(name));
if (len != ZSTR_LEN(name)) {
ZEND_ASSERT(scope && "This should only happen with resolved types");
return zend_string_init(ZSTR_VAL(name), len, 0);
}
return zend_string_copy(name);
}
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
zend_string *str = NULL;
if (ZEND_TYPE_HAS_LIST(type)) {
zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
if (ZEND_TYPE_HAS_CE(*list_type)) {
str = add_type_string(str, ZEND_TYPE_CE(*list_type)->name);
} else {
zend_string *name = ZEND_TYPE_NAME(*list_type);
if (ZSTR_HAS_CE_CACHE(name)
&& ZSTR_GET_CE_CACHE(name)) {
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
zend_string *tmp = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
str = add_type_string(str, tmp);
} else {
str = add_type_string(str, ce->name);
}
} else {
zend_string *resolved = resolve_class_name(name, scope);
str = add_type_string(str, resolved);
zend_string_release(resolved);
}
}
} ZEND_TYPE_LIST_FOREACH_END();
} else if (ZEND_TYPE_HAS_NAME(type)) {
zend_string *name = ZEND_TYPE_NAME(type);
if (ZSTR_HAS_CE_CACHE(name)
&& ZSTR_GET_CE_CACHE(name)) {
zend_class_entry *ce = ZSTR_GET_CE_CACHE(name);
if (ce->ce_flags & ZEND_ACC_ANON_CLASS) {
str = zend_string_init(ZSTR_VAL(ce->name), strlen(ZSTR_VAL(ce->name)), 0);
} else {
str = zend_string_copy(ce->name);
}
} else {
str = resolve_class_name(name, scope);
}
} else if (ZEND_TYPE_HAS_CE(type)) {
str = zend_string_copy(ZEND_TYPE_CE(type)->name);
}
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
if (type_mask == MAY_BE_ANY) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_MIXED));
return str;
}
if (type_mask & MAY_BE_STATIC) {
zend_string *name = ZSTR_KNOWN(ZEND_STR_STATIC);
if (scope) {
zend_class_entry *called_scope = zend_get_called_scope(EG(current_execute_data));
if (called_scope) {
name = called_scope->name;
}
}
str = add_type_string(str, name);
}
if (type_mask & MAY_BE_CALLABLE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_CALLABLE));
}
if (type_mask & MAY_BE_ITERABLE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_ITERABLE));
}
if (type_mask & MAY_BE_OBJECT) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_OBJECT));
}
if (type_mask & MAY_BE_ARRAY) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_ARRAY));
}
if (type_mask & MAY_BE_STRING) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_STRING));
}
if (type_mask & MAY_BE_LONG) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_INT));
}
if (type_mask & MAY_BE_DOUBLE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_FLOAT));
}
if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_BOOL));
} else if (type_mask & MAY_BE_FALSE) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_FALSE));
}
if (type_mask & MAY_BE_VOID) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_VOID));
}
if (type_mask & MAY_BE_NEVER) {
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_NEVER));
}
if (type_mask & MAY_BE_NULL) {
bool is_union = !str || memchr(ZSTR_VAL(str), '|', ZSTR_LEN(str)) != NULL;
if (!is_union) {
2020-04-14 15:17:38 +00:00
zend_string *nullable_str = zend_string_concat2("?", 1, ZSTR_VAL(str), ZSTR_LEN(str));
zend_string_release(str);
return nullable_str;
}
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_NULL_LOWERCASE));
}
return str;
}
ZEND_API zend_string *zend_type_to_string(zend_type type) {
return zend_type_to_string_resolved(type, NULL);
}
static bool is_generator_compatible_class_type(zend_string *name) {
return zend_string_equals_literal_ci(name, "Traversable")
|| zend_string_equals_literal_ci(name, "Iterator")
|| zend_string_equals_literal_ci(name, "Generator");
}
static void zend_mark_function_as_generator(void) /* {{{ */
{
if (!CG(active_op_array)->function_name) {
zend_error_noreturn(E_COMPILE_ERROR,
"The \"yield\" expression can only be used inside a function");
}
if (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
zend_type return_type = CG(active_op_array)->arg_info[-1].type;
bool valid_type = (ZEND_TYPE_FULL_MASK(return_type) & (MAY_BE_ITERABLE | MAY_BE_OBJECT)) != 0;
if (!valid_type) {
zend_type *single_type;
ZEND_TYPE_FOREACH(return_type, single_type) {
if (ZEND_TYPE_HAS_NAME(*single_type)
&& is_generator_compatible_class_type(ZEND_TYPE_NAME(*single_type))) {
valid_type = 1;
break;
}
} ZEND_TYPE_FOREACH_END();
}
if (!valid_type) {
zend_string *str = zend_type_to_string(return_type);
zend_error_noreturn(E_COMPILE_ERROR,
"Generator return type must be a supertype of Generator, %s given",
ZSTR_VAL(str));
}
}
CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
}
/* }}} */
2018-01-11 16:15:52 +00:00
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array) /* {{{ */
{
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
uint32_t first_early_binding_opline = (uint32_t)-1;
uint32_t *prev_opline_num = &first_early_binding_opline;
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
while (opline < end) {
if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
2018-01-11 16:15:52 +00:00
*prev_opline_num = opline - op_array->opcodes;
prev_opline_num = &opline->result.opline_num;
}
++opline;
}
*prev_opline_num = -1;
return first_early_binding_opline;
}
return (uint32_t)-1;
}
/* }}} */
ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */
2001-08-30 15:26:30 +00:00
{
2018-01-11 16:15:52 +00:00
if (first_early_binding_opline != (uint32_t)-1) {
bool orig_in_compilation = CG(in_compilation);
2018-01-11 16:15:52 +00:00
uint32_t opline_num = first_early_binding_opline;
void **run_time_cache;
if (!ZEND_MAP_PTR(op_array->run_time_cache)) {
void *ptr;
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE);
ptr = emalloc(op_array->cache_size + sizeof(void*));
ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr);
ptr = (char*)ptr + sizeof(void*);
ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr);
memset(ptr, 0, op_array->cache_size);
}
run_time_cache = RUN_TIME_CACHE(op_array);
CG(in_compilation) = 1;
2014-12-12 18:57:34 +00:00
while (opline_num != (uint32_t)-1) {
const zend_op *opline = &op_array->opcodes[opline_num];
zval *lcname = RT_CONSTANT(opline, opline->op1);
zval *zv = zend_hash_find_ex(EG(class_table), Z_STR_P(lcname + 1), 1);
if (zv) {
zend_class_entry *ce = Z_CE_P(zv);
zend_string *lc_parent_name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
zend_class_entry *parent_ce = zend_hash_find_ex_ptr(EG(class_table), lc_parent_name, 1);
2019-06-26 23:13:06 +00:00
if (parent_ce) {
ce = zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv);
if (ce) {
/* Store in run-time cache */
((void**)((char*)run_time_cache + opline->extended_value))[0] = ce;
}
}
}
opline_num = op_array->opcodes[opline_num].result.opline_num;
}
CG(in_compilation) = orig_in_compilation;
}
2001-08-30 15:26:30 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
2001-08-30 15:26:30 +00:00
ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, bool internal) /* {{{ */
{
size_t prop_name_length = 1 + src1_length + 1 + src2_length;
zend_string *prop_name = zend_string_alloc(prop_name_length, internal);
ZSTR_VAL(prop_name)[0] = '\0';
memcpy(ZSTR_VAL(prop_name) + 1, src1, src1_length+1);
memcpy(ZSTR_VAL(prop_name) + 1 + src1_length + 1, src2, src2_length+1);
return prop_name;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2015-04-28 03:30:25 +00:00
static zend_always_inline size_t zend_strnlen(const char* s, size_t maxlen) /* {{{ */
{
size_t len = 0;
while (*s++ && maxlen--) len++;
return len;
}
2009-07-27 14:11:53 +00:00
/* }}} */
ZEND_API zend_result zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */
1999-07-27 20:34:31 +00:00
{
size_t class_name_len;
size_t anonclass_src_len;
*class_name = NULL;
if (!ZSTR_LEN(name) || ZSTR_VAL(name)[0] != '\0') {
*prop_name = ZSTR_VAL(name);
if (prop_len) {
*prop_len = ZSTR_LEN(name);
}
return SUCCESS;
}
if (ZSTR_LEN(name) < 3 || ZSTR_VAL(name)[1] == '\0') {
zend_error(E_NOTICE, "Illegal member variable name");
*prop_name = ZSTR_VAL(name);
if (prop_len) {
*prop_len = ZSTR_LEN(name);
}
return FAILURE;
}
class_name_len = zend_strnlen(ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 2);
if (class_name_len >= ZSTR_LEN(name) - 2 || ZSTR_VAL(name)[class_name_len + 1] != '\0') {
zend_error(E_NOTICE, "Corrupt member variable name");
*prop_name = ZSTR_VAL(name);
if (prop_len) {
*prop_len = ZSTR_LEN(name);
}
return FAILURE;
}
*class_name = ZSTR_VAL(name) + 1;
anonclass_src_len = zend_strnlen(*class_name + class_name_len + 1, ZSTR_LEN(name) - class_name_len - 2);
if (class_name_len + anonclass_src_len + 2 != ZSTR_LEN(name)) {
class_name_len += anonclass_src_len + 1;
}
*prop_name = ZSTR_VAL(name) + class_name_len + 2;
if (prop_len) {
*prop_len = ZSTR_LEN(name) - class_name_len - 2;
}
return SUCCESS;
1999-07-27 20:34:31 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-07-27 20:34:31 +00:00
static bool can_ct_eval_const(zend_constant *c) {
if (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED) {
return 0;
}
if ((ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)
&& !(CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION)
&& !((ZEND_CONSTANT_FLAGS(c) & CONST_NO_FILE_CACHE)
&& (CG(compiler_options) & ZEND_COMPILE_WITH_FILE_CACHE))) {
return 1;
}
if (Z_TYPE(c->value) < IS_OBJECT
&& !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
return 1;
}
return 0;
}
static bool zend_try_ct_eval_const(zval *zv, zend_string *name, bool is_fully_qualified) /* {{{ */
{
zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
if (c && can_ct_eval_const(c)) {
ZVAL_COPY_OR_DUP(zv, &c->value);
return 1;
}
{
/* Substitute true, false and null (including unqualified usage in namespaces) */
const char *lookup_name = ZSTR_VAL(name);
size_t lookup_len = ZSTR_LEN(name);
if (!is_fully_qualified) {
zend_get_unqualified_name(name, &lookup_name, &lookup_len);
}
if ((c = zend_get_special_const(lookup_name, lookup_len))) {
ZVAL_COPY_VALUE(zv, &c->value);
return 1;
}
return 0;
}
}
2009-07-27 14:11:53 +00:00
/* }}} */
static inline bool zend_is_scope_known(void) /* {{{ */
{
if (!CG(active_op_array)) {
/* This can only happen when evaluating a default value string. */
return 0;
}
if (CG(active_op_array)->fn_flags & ZEND_ACC_CLOSURE) {
/* Closures can be rebound to a different scope */
return 0;
}
if (!CG(active_class_entry)) {
/* The scope is known if we're in a free function (no scope), but not if we're in
* a file/eval (which inherits including/eval'ing scope). */
return CG(active_op_array)->function_name != NULL;
}
/* For traits self etc refers to the using class, not the trait itself */
return (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) == 0;
}
/* }}} */
static inline bool class_name_refers_to_active_ce(zend_string *class_name, uint32_t fetch_type) /* {{{ */
{
if (!CG(active_class_entry)) {
return 0;
}
if (fetch_type == ZEND_FETCH_CLASS_SELF && zend_is_scope_known()) {
return 1;
}
return fetch_type == ZEND_FETCH_CLASS_DEFAULT
&& zend_string_equals_ci(class_name, CG(active_class_entry)->name);
}
/* }}} */
2015-05-25 20:58:30 +00:00
uint32_t zend_get_class_fetch_type(zend_string *name) /* {{{ */
{
if (zend_string_equals_literal_ci(name, "self")) {
return ZEND_FETCH_CLASS_SELF;
} else if (zend_string_equals_literal_ci(name, "parent")) {
return ZEND_FETCH_CLASS_PARENT;
} else if (zend_string_equals_literal_ci(name, "static")) {
return ZEND_FETCH_CLASS_STATIC;
} else {
return ZEND_FETCH_CLASS_DEFAULT;
}
}
/* }}} */
static uint32_t zend_get_class_fetch_type_ast(zend_ast *name_ast) /* {{{ */
{
/* Fully qualified names are always default refs */
if (name_ast->attr == ZEND_NAME_FQ) {
return ZEND_FETCH_CLASS_DEFAULT;
}
return zend_get_class_fetch_type(zend_ast_get_str(name_ast));
}
/* }}} */
static zend_string *zend_resolve_const_class_name_reference(zend_ast *ast, const char *type)
{
zend_string *class_name = zend_ast_get_str(ast);
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type_ast(ast)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use '%s' as %s, as it is reserved",
ZSTR_VAL(class_name), type);
}
return zend_resolve_class_name(class_name, ast->attr);
}
2015-05-25 20:58:30 +00:00
static void zend_ensure_valid_class_fetch_type(uint32_t fetch_type) /* {{{ */
{
if (fetch_type != ZEND_FETCH_CLASS_DEFAULT && zend_is_scope_known()) {
zend_class_entry *ce = CG(active_class_entry);
if (!ce) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"%s\" when no class scope is active",
fetch_type == ZEND_FETCH_CLASS_SELF ? "self" :
fetch_type == ZEND_FETCH_CLASS_PARENT ? "parent" : "static");
} else if (fetch_type == ZEND_FETCH_CLASS_PARENT && !ce->parent_name) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use \"parent\" when current class scope has no parent");
}
2015-05-25 20:58:30 +00:00
}
}
/* }}} */
static bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_ast *class_ast) /* {{{ */
2015-05-25 20:58:30 +00:00
{
uint32_t fetch_type;
zval *class_name;
2015-05-25 20:58:30 +00:00
if (class_ast->kind != ZEND_AST_ZVAL) {
return 0;
2015-05-25 20:58:30 +00:00
}
class_name = zend_ast_get_zval(class_ast);
if (Z_TYPE_P(class_name) != IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
}
fetch_type = zend_get_class_fetch_type(Z_STR_P(class_name));
2015-05-25 20:58:30 +00:00
zend_ensure_valid_class_fetch_type(fetch_type);
switch (fetch_type) {
case ZEND_FETCH_CLASS_SELF:
if (CG(active_class_entry) && zend_is_scope_known()) {
2015-05-25 20:58:30 +00:00
ZVAL_STR_COPY(zv, CG(active_class_entry)->name);
return 1;
2015-05-25 20:58:30 +00:00
}
return 0;
2015-05-25 20:58:30 +00:00
case ZEND_FETCH_CLASS_PARENT:
if (CG(active_class_entry) && CG(active_class_entry)->parent_name
&& zend_is_scope_known()) {
ZVAL_STR_COPY(zv, CG(active_class_entry)->parent_name);
return 1;
}
return 0;
case ZEND_FETCH_CLASS_STATIC:
return 0;
2015-05-25 20:58:30 +00:00
case ZEND_FETCH_CLASS_DEFAULT:
ZVAL_STR(zv, zend_resolve_class_name_ast(class_ast));
return 1;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
/* }}} */
/* We don't use zend_verify_const_access because we need to deal with unlinked classes. */
static bool zend_verify_ct_const_access(zend_class_constant *c, zend_class_entry *scope)
{
if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PUBLIC) {
return 1;
} else if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PRIVATE) {
return c->ce == scope;
} else {
zend_class_entry *ce = c->ce;
while (1) {
if (ce == scope) {
return 1;
}
if (!ce->parent) {
break;
}
if (ce->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
ce = ce->parent;
} else {
ce = zend_hash_find_ptr_lc(CG(class_table), ce->parent_name);
if (!ce) {
break;
}
}
}
/* Reverse case cannot be true during compilation */
return 0;
}
}
static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
{
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
zend_class_constant *cc;
zval *c;
if (class_name_refers_to_active_ce(class_name, fetch_type)) {
cc = zend_hash_find_ptr(&CG(active_class_entry)->constants_table, name);
} else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), class_name);
if (ce) {
cc = zend_hash_find_ptr(&ce->constants_table, name);
} else {
return 0;
}
} else {
return 0;
}
if (CG(compiler_options) & ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION) {
return 0;
}
if (!cc || !zend_verify_ct_const_access(cc, CG(active_class_entry))) {
return 0;
}
c = &cc->value;
/* Substitute case-sensitive (or lowercase) persistent class constants */
if (Z_TYPE_P(c) < IS_OBJECT) {
ZVAL_COPY_OR_DUP(zv, c);
return 1;
}
return 0;
}
/* }}} */
static void zend_add_to_list(void *result, void *item) /* {{{ */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
{
void** list = *(void**)result;
size_t n = 0;
2012-12-25 06:23:08 +00:00
if (list) {
while (list[n]) {
n++;
}
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
list = erealloc(list, sizeof(void*) * (n+2));
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
list[n] = item;
list[n+1] = NULL;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
*(void**)result = list;
}
/* }}} */
void zend_do_extended_stmt(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
zend_op *opline;
if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT)) {
1999-04-07 18:10:10 +00:00
return;
}
opline = get_next_op();
1999-04-07 18:10:10 +00:00
opline->opcode = ZEND_EXT_STMT;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_do_extended_fcall_begin(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
zend_op *opline;
if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
1999-04-07 18:10:10 +00:00
return;
}
opline = get_next_op();
1999-04-07 18:10:10 +00:00
opline->opcode = ZEND_EXT_FCALL_BEGIN;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_do_extended_fcall_end(void) /* {{{ */
1999-04-07 18:10:10 +00:00
{
zend_op *opline;
if (!(CG(compiler_options) & ZEND_COMPILE_EXTENDED_FCALL)) {
1999-04-07 18:10:10 +00:00
return;
}
opline = get_next_op();
1999-04-07 18:10:10 +00:00
opline->opcode = ZEND_EXT_FCALL_END;
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
bool zend_is_auto_global_str(const char *name, size_t len) /* {{{ */ {
zend_auto_global *auto_global;
if ((auto_global = zend_hash_str_find_ptr(CG(auto_globals), name, len)) != NULL) {
if (auto_global->armed) {
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
}
return 1;
}
return 0;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
bool zend_is_auto_global(zend_string *name) /* {{{ */
2003-03-02 13:33:31 +00:00
{
zend_auto_global *auto_global;
if ((auto_global = zend_hash_find_ptr(CG(auto_globals), name)) != NULL) {
2003-03-02 13:33:31 +00:00
if (auto_global->armed) {
2014-12-13 22:06:14 +00:00
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
}
2003-03-02 13:33:31 +00:00
return 1;
}
return 0;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2003-03-02 13:33:31 +00:00
zend_result zend_register_auto_global(zend_string *name, bool jit, zend_auto_global_callback auto_global_callback) /* {{{ */
{
zend_auto_global auto_global;
zend_result retval;
auto_global.name = name;
auto_global.auto_global_callback = auto_global_callback;
auto_global.jit = jit;
2014-12-29 06:35:08 +00:00
retval = zend_hash_add_mem(CG(auto_globals), auto_global.name, &auto_global, sizeof(zend_auto_global)) != NULL ? SUCCESS : FAILURE;
2014-04-10 11:50:25 +00:00
return retval;
}
2009-07-27 14:11:53 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
ZEND_API void zend_activate_auto_globals(void) /* {{{ */
{
zend_auto_global *auto_global;
ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) {
if (auto_global->jit) {
auto_global->armed = 1;
} else if (auto_global->auto_global_callback) {
2014-12-13 22:06:14 +00:00
auto_global->armed = auto_global->auto_global_callback(auto_global->name);
} else {
auto_global->armed = 0;
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */
int ZEND_FASTCALL zendlex(zend_parser_stack_elem *elem) /* {{{ */
1999-04-07 18:10:10 +00:00
{
2014-07-26 18:54:41 +00:00
zval zv;
int ret;
if (CG(increment_lineno)) {
CG(zend_lineno)++;
CG(increment_lineno) = 0;
}
ret = lex_scan(&zv, elem);
ZEND_ASSERT(!EG(exception) || ret == T_ERROR);
return ret;
1999-04-07 18:10:10 +00:00
}
2009-07-27 14:11:53 +00:00
/* }}} */
ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_handlers) /* {{{ */
2003-02-10 16:11:24 +00:00
{
bool persistent_hashes = ce->type == ZEND_INTERNAL_CLASS;
2003-02-10 16:46:05 +00:00
2003-02-10 16:11:24 +00:00
ce->refcount = 1;
ce->ce_flags = ZEND_ACC_CONSTANTS_UPDATED;
2015-09-20 05:23:36 +00:00
if (CG(compiler_options) & ZEND_COMPILE_GUARDS) {
ce->ce_flags |= ZEND_ACC_USE_GUARDS;
}
ce->default_properties_table = NULL;
ce->default_static_members_table = NULL;
zend_hash_init(&ce->properties_info, 8, NULL, NULL, persistent_hashes);
zend_hash_init(&ce->constants_table, 8, NULL, NULL, persistent_hashes);
zend_hash_init(&ce->function_table, 8, NULL, ZEND_FUNCTION_DTOR, persistent_hashes);
2003-02-10 16:11:24 +00:00
if (ce->type == ZEND_INTERNAL_CLASS) {
Immutable clases and op_arrays. Squashed commit of the following: commit cd0c36c3f943849e5b97a8dbe2dd029fbeab3df9 Merge: 4740dabb84 ad6738e886 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:43:38 2018 +0300 Merge branch 'master' into immutable * master: Remove the "auto" encoding Fixed bug #77025 Add vtbls for EUC-TW encoding commit 4740dabb843c6d4f7f866b4a2456073c9eaf4c77 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:12:28 2018 +0300 Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes. commit ad7a78b253be970db70c2251e66f9297d8e7f829 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:46:30 2018 +0300 Added comment commit 0276ea51875bab37be01a4dc5e5a047c5698c571 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:42:43 2018 +0300 Added type cast commit c63fc5d5f19c58498108d1698055b2b442227eb3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:36:51 2018 +0300 Moved static class members initialization into the proper place. commit b945548e9306b1826c881918858b5e5aa3eb3002 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:21:03 2018 +0300 Removed redundand assertion commit d5a41088401814c829847db212488f8aae39bcd2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:19:13 2018 +0300 Removed duplicate code commit 8dadca8864e66de70a24bdf1181bcf7dd8fb27d7 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:05:43 2018 +0300 Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros. commit 9ef07c88bd76801e2d4fbfeab3ebfd6e6a67ac5f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:48:29 2018 +0300 typo commit a06f0f3d3aba53e766046221ee44fb9720389ecc Merge: 94099586ec 3412345ffe Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:47:07 2018 +0300 Merge branch 'master' into immutable * master: Remove unused variable makefile_am_files Classify object handlers are required/optional Add support for getting SKIP_TAGSTART and SKIP_WHITE options Remove some obsolete config_vars.mk occurrences Remove bsd_converted from .gitignore Remove configuration parser and scanners ignores Remove obsolete buildconf.stamp from .gitignore [ci skip] Add magicdata.patch exception to .gitignore Remove outdated ext/spl/examples items from .gitignore Remove unused test.inc in ext/iconv/tests commit 94099586ec599117581ca01c15b1f6c5f749e23a Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 15 23:34:01 2018 +0300 Immutable clases and op_arrays
2018-10-17 12:52:50 +00:00
ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
} else {
Immutable clases and op_arrays. Squashed commit of the following: commit cd0c36c3f943849e5b97a8dbe2dd029fbeab3df9 Merge: 4740dabb84 ad6738e886 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:43:38 2018 +0300 Merge branch 'master' into immutable * master: Remove the "auto" encoding Fixed bug #77025 Add vtbls for EUC-TW encoding commit 4740dabb843c6d4f7f866b4a2456073c9eaf4c77 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:12:28 2018 +0300 Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes. commit ad7a78b253be970db70c2251e66f9297d8e7f829 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:46:30 2018 +0300 Added comment commit 0276ea51875bab37be01a4dc5e5a047c5698c571 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:42:43 2018 +0300 Added type cast commit c63fc5d5f19c58498108d1698055b2b442227eb3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:36:51 2018 +0300 Moved static class members initialization into the proper place. commit b945548e9306b1826c881918858b5e5aa3eb3002 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:21:03 2018 +0300 Removed redundand assertion commit d5a41088401814c829847db212488f8aae39bcd2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:19:13 2018 +0300 Removed duplicate code commit 8dadca8864e66de70a24bdf1181bcf7dd8fb27d7 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:05:43 2018 +0300 Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros. commit 9ef07c88bd76801e2d4fbfeab3ebfd6e6a67ac5f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:48:29 2018 +0300 typo commit a06f0f3d3aba53e766046221ee44fb9720389ecc Merge: 94099586ec 3412345ffe Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:47:07 2018 +0300 Merge branch 'master' into immutable * master: Remove unused variable makefile_am_files Classify object handlers are required/optional Add support for getting SKIP_TAGSTART and SKIP_WHITE options Remove some obsolete config_vars.mk occurrences Remove bsd_converted from .gitignore Remove configuration parser and scanners ignores Remove obsolete buildconf.stamp from .gitignore [ci skip] Add magicdata.patch exception to .gitignore Remove outdated ext/spl/examples items from .gitignore Remove unused test.inc in ext/iconv/tests commit 94099586ec599117581ca01c15b1f6c5f749e23a Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 15 23:34:01 2018 +0300 Immutable clases and op_arrays
2018-10-17 12:52:50 +00:00
ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
ce->info.user.doc_comment = NULL;
}
ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
ce->default_properties_count = 0;
ce->default_static_members_count = 0;
ce->properties_info_table = NULL;
ce->attributes = NULL;
ce->enum_backing_type = IS_UNDEF;
ce->backed_enum_table = NULL;
2003-02-10 16:11:24 +00:00
if (nullify_handlers) {
ce->constructor = NULL;
ce->destructor = NULL;
ce->clone = NULL;
ce->__get = NULL;
ce->__set = NULL;
ce->__unset = NULL;
ce->__isset = NULL;
2003-02-10 16:11:24 +00:00
ce->__call = NULL;
ce->__callstatic = NULL;
ce->__tostring = NULL;
ce->__serialize = NULL;
ce->__unserialize = NULL;
ce->__debugInfo = NULL;
2003-02-10 16:11:24 +00:00
ce->create_object = NULL;
ce->get_iterator = NULL;
ce->iterator_funcs_ptr = NULL;
ce->get_static_method = NULL;
ce->parent = NULL;
2018-10-07 09:20:38 +00:00
ce->parent_name = NULL;
ce->num_interfaces = 0;
ce->interfaces = NULL;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
ce->num_traits = 0;
ce->trait_names = NULL;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
ce->trait_aliases = NULL;
ce->trait_precedences = NULL;
ce->serialize = NULL;
ce->unserialize = NULL;
if (ce->type == ZEND_INTERNAL_CLASS) {
ce->info.internal.module = NULL;
ce->info.internal.builtin_functions = NULL;
}
2003-02-10 16:11:24 +00:00
}
}
2009-07-27 14:11:53 +00:00
/* }}} */
ZEND_API zend_string *zend_get_compiled_variable_name(const zend_op_array *op_array, uint32_t var) /* {{{ */
{
return op_array->vars[EX_VAR_TO_NUM(var)];
}
2009-07-27 14:11:53 +00:00
/* }}} */
2014-08-29 05:05:58 +00:00
zend_ast *zend_ast_append_str(zend_ast *left_ast, zend_ast *right_ast) /* {{{ */
{
2014-07-26 19:53:50 +00:00
zval *left_zv = zend_ast_get_zval(left_ast);
zend_string *left = Z_STR_P(left_zv);
zend_string *right = zend_ast_get_str(right_ast);
2014-07-26 19:53:50 +00:00
zend_string *result;
size_t left_len = ZSTR_LEN(left);
size_t len = left_len + ZSTR_LEN(right) + 1; /* left\right */
2014-07-26 19:53:50 +00:00
result = zend_string_extend(left, len, 0);
ZSTR_VAL(result)[left_len] = '\\';
memcpy(&ZSTR_VAL(result)[left_len + 1], ZSTR_VAL(right), ZSTR_LEN(right));
ZSTR_VAL(result)[len] = '\0';
zend_string_release_ex(right, 0);
2014-07-26 19:53:50 +00:00
ZVAL_STR(left_zv, result);
return left_ast;
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
zend_ast *zend_negate_num_string(zend_ast *ast) /* {{{ */
{
zval *zv = zend_ast_get_zval(ast);
if (Z_TYPE_P(zv) == IS_LONG) {
if (Z_LVAL_P(zv) == 0) {
ZVAL_NEW_STR(zv, zend_string_init("-0", sizeof("-0")-1, 0));
} else {
ZEND_ASSERT(Z_LVAL_P(zv) > 0);
Z_LVAL_P(zv) *= -1;
}
} else if (Z_TYPE_P(zv) == IS_STRING) {
size_t orig_len = Z_STRLEN_P(zv);
Z_STR_P(zv) = zend_string_extend(Z_STR_P(zv), orig_len + 1, 0);
memmove(Z_STRVAL_P(zv) + 1, Z_STRVAL_P(zv), orig_len + 1);
Z_STRVAL_P(zv)[0] = '-';
} else {
ZEND_UNREACHABLE();
}
return ast;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_verify_namespace(void) /* {{{ */
2007-09-28 19:52:53 +00:00
{
if (FC(has_bracketed_namespaces) && !FC(in_namespace)) {
zend_error_noreturn(E_COMPILE_ERROR, "No code may exist outside of namespace {}");
}
}
/* }}} */
2008-02-12 01:17:48 +00:00
/* {{{ zend_dirname
Returns directory name component of path */
ZEND_API size_t zend_dirname(char *path, size_t len)
{
char *end = path + len - 1;
unsigned int len_adjust = 0;
#ifdef ZEND_WIN32
/* Note that on Win32 CWD is per drive (heritage from CP/M).
* This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
*/
if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
/* Skip over the drive spec (if any) so as not to change */
path += 2;
len_adjust += 2;
if (2 == len) {
/* Return "c:" on Win32 for dirname("c:").
* It would be more consistent to return "c:."
* but that would require making the string *longer*.
*/
return len;
}
}
#endif
if (len == 0) {
/* Illegal use of this function */
return 0;
}
/* Strip trailing slashes */
while (end >= path && IS_SLASH_P(end)) {
end--;
}
if (end < path) {
/* The path only contained slashes */
path[0] = DEFAULT_SLASH;
path[1] = '\0';
return 1 + len_adjust;
}
/* Strip filename */
while (end >= path && !IS_SLASH_P(end)) {
end--;
}
if (end < path) {
/* No slash found, therefore return '.' */
path[0] = '.';
path[1] = '\0';
return 1 + len_adjust;
}
/* Strip slashes which came before the file name */
while (end >= path && IS_SLASH_P(end)) {
end--;
}
if (end < path) {
path[0] = DEFAULT_SLASH;
path[1] = '\0';
return 1 + len_adjust;
}
*(end+1) = '\0';
return (size_t)(end + 1 - path) + len_adjust;
}
/* }}} */
2008-02-12 01:17:48 +00:00
static void zend_adjust_for_fetch_type(zend_op *opline, znode *result, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_uchar factor = (opline->opcode == ZEND_FETCH_STATIC_PROP_R) ? 1 : 3;
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
switch (type) {
2014-06-07 11:06:53 +00:00
case BP_VAR_R:
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
2014-06-07 11:06:53 +00:00
return;
case BP_VAR_W:
opline->opcode += 1 * factor;
2014-06-07 11:06:53 +00:00
return;
case BP_VAR_RW:
opline->opcode += 2 * factor;
2014-06-07 11:06:53 +00:00
return;
case BP_VAR_IS:
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
opline->opcode += 3 * factor;
2014-06-07 11:06:53 +00:00
return;
case BP_VAR_FUNC_ARG:
opline->opcode += 4 * factor;
2014-06-07 11:06:53 +00:00
return;
case BP_VAR_UNSET:
opline->opcode += 5 * factor;
2014-06-07 11:06:53 +00:00
return;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2015-01-03 09:22:58 +00:00
static inline void zend_make_var_result(znode *result, zend_op *opline) /* {{{ */
2014-08-29 05:05:58 +00:00
{
opline->result_type = IS_VAR;
opline->result.var = get_temporary_variable();
GET_NODE(result, opline->result);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static inline void zend_make_tmp_result(znode *result, zend_op *opline) /* {{{ */
2014-08-29 05:05:58 +00:00
{
opline->result_type = IS_TMP_VAR;
opline->result.var = get_temporary_variable();
GET_NODE(result, opline->result);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2015-01-03 09:22:58 +00:00
static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline = get_next_op();
2014-06-07 11:06:53 +00:00
opline->opcode = opcode;
2018-03-13 11:34:48 +00:00
if (op1 != NULL) {
2014-06-07 11:06:53 +00:00
SET_NODE(opline->op1, op1);
}
2018-03-13 11:34:48 +00:00
if (op2 != NULL) {
2014-06-07 11:06:53 +00:00
SET_NODE(opline->op2, op2);
}
if (result) {
2014-12-13 22:06:14 +00:00
zend_make_var_result(result, opline);
2014-06-07 11:06:53 +00:00
}
return opline;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline = get_next_op();
opline->opcode = opcode;
2011-01-19 17:17:52 +00:00
2018-03-13 11:34:48 +00:00
if (op1 != NULL) {
2014-06-19 11:57:29 +00:00
SET_NODE(opline->op1, op1);
}
2018-03-13 11:34:48 +00:00
if (op2 != NULL) {
SET_NODE(opline->op2, op2);
2003-02-24 12:05:58 +00:00
}
if (result) {
2014-12-13 22:06:14 +00:00
zend_make_tmp_result(result, opline);
}
return opline;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static void zend_emit_tick(void) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2015-07-07 16:26:14 +00:00
zend_op *opline;
/* This prevents a double TICK generated by the parser statement of "declare()" */
if (CG(active_op_array)->last && CG(active_op_array)->opcodes[CG(active_op_array)->last - 1].opcode == ZEND_TICKS) {
return;
}
opline = get_next_op();
2014-07-09 22:00:48 +00:00
opline->opcode = ZEND_TICKS;
opline->extended_value = FC(declarables).ticks;
2014-07-09 22:00:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 22:00:48 +00:00
2014-12-13 22:06:14 +00:00
static inline zend_op *zend_emit_op_data(znode *value) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
return zend_emit_op(NULL, ZEND_OP_DATA, value, NULL);
2014-07-28 10:55:37 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-28 10:55:37 +00:00
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_emit_jump(uint32_t opnum_target) /* {{{ */
2014-08-29 05:05:58 +00:00
{
uint32_t opnum = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_op *opline = zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
2014-07-18 17:57:38 +00:00
opline->op1.opline_num = opnum_target;
return opnum;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 17:57:38 +00:00
ZEND_API bool zend_is_smart_branch(const zend_op *opline) /* {{{ */
{
switch (opline->opcode) {
case ZEND_IS_IDENTICAL:
case ZEND_IS_NOT_IDENTICAL:
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
case ZEND_IS_SMALLER_OR_EQUAL:
case ZEND_CASE:
case ZEND_CASE_STRICT:
case ZEND_ISSET_ISEMPTY_CV:
case ZEND_ISSET_ISEMPTY_VAR:
case ZEND_ISSET_ISEMPTY_DIM_OBJ:
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
case ZEND_ISSET_ISEMPTY_STATIC_PROP:
case ZEND_INSTANCEOF:
case ZEND_TYPE_CHECK:
case ZEND_DEFINED:
case ZEND_IN_ARRAY:
case ZEND_ARRAY_KEY_EXISTS:
return 1;
default:
return 0;
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_emit_cond_jump(zend_uchar opcode, znode *cond, uint32_t opnum_target) /* {{{ */
2014-08-29 05:05:58 +00:00
{
uint32_t opnum = get_next_op_number();
2019-10-09 14:58:35 +00:00
zend_op *opline;
if (cond->op_type == IS_TMP_VAR && opnum > 0) {
opline = CG(active_op_array)->opcodes + opnum - 1;
if (opline->result_type == IS_TMP_VAR
&& opline->result.var == cond->u.op.var
&& zend_is_smart_branch(opline)) {
if (opcode == ZEND_JMPZ) {
opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPZ;
} else {
ZEND_ASSERT(opcode == ZEND_JMPNZ);
opline->result_type = IS_TMP_VAR | IS_SMART_BRANCH_JMPNZ;
}
}
}
opline = zend_emit_op(NULL, opcode, cond, NULL);
2014-07-18 17:57:38 +00:00
opline->op2.opline_num = opnum_target;
return opnum;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 17:57:38 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_target) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-18 14:11:43 +00:00
zend_op *opline = &CG(active_op_array)->opcodes[opnum_jump];
switch (opline->opcode) {
case ZEND_JMP:
opline->op1.opline_num = opnum_target;
break;
case ZEND_JMPZ:
case ZEND_JMPNZ:
case ZEND_JMPZ_EX:
case ZEND_JMPNZ_EX:
2015-07-06 15:41:29 +00:00
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_JMP_NULL:
2014-07-18 14:11:43 +00:00
opline->op2.opline_num = opnum_target;
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 14:11:43 +00:00
2015-01-03 09:22:58 +00:00
static inline void zend_update_jump_target_to_next(uint32_t opnum_jump) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_update_jump_target(opnum_jump, get_next_op_number());
2014-07-18 14:11:43 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-18 14:11:43 +00:00
2014-12-13 22:06:14 +00:00
static inline zend_op *zend_delayed_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op tmp_opline;
2018-03-13 11:34:48 +00:00
2014-12-13 22:06:14 +00:00
init_op(&tmp_opline);
2018-03-13 11:34:48 +00:00
tmp_opline.opcode = opcode;
2018-03-13 11:34:48 +00:00
if (op1 != NULL) {
2015-02-02 17:44:16 +00:00
SET_NODE(tmp_opline.op1, op1);
}
2018-03-13 11:34:48 +00:00
if (op2 != NULL) {
2015-02-02 17:44:16 +00:00
SET_NODE(tmp_opline.op2, op2);
}
if (result) {
2014-12-13 22:06:14 +00:00
zend_make_var_result(result, &tmp_opline);
}
2002-12-07 21:46:12 +00:00
zend_stack_push(&CG(delayed_oplines_stack), &tmp_opline);
return zend_stack_top(&CG(delayed_oplines_stack));
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static inline uint32_t zend_delayed_compile_begin(void) /* {{{ */
2014-08-29 05:05:58 +00:00
{
return zend_stack_count(&CG(delayed_oplines_stack));
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-11-27 09:52:31 +00:00
zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack));
uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack));
ZEND_ASSERT(count >= offset);
for (i = offset; i < count; ++i) {
opline = get_next_op();
memcpy(opline, &oplines[i], sizeof(zend_op));
if (opline->opcode == ZEND_JMP_NULL) {
uint32_t opnum = get_next_op_number() - 1;
zend_stack_push(&CG(short_circuiting_opnums), &opnum);
}
}
CG(delayed_oplines_stack).top = offset;
return opline;
}
2014-08-29 05:05:58 +00:00
/* }}} */
static bool zend_ast_kind_is_short_circuited(zend_ast_kind ast_kind)
{
switch (ast_kind) {
case ZEND_AST_DIM:
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
case ZEND_AST_STATIC_PROP:
case ZEND_AST_METHOD_CALL:
case ZEND_AST_NULLSAFE_METHOD_CALL:
case ZEND_AST_STATIC_CALL:
return 1;
default:
return 0;
}
}
static bool zend_ast_is_short_circuited(const zend_ast *ast)
{
switch (ast->kind) {
case ZEND_AST_DIM:
case ZEND_AST_PROP:
case ZEND_AST_STATIC_PROP:
case ZEND_AST_METHOD_CALL:
case ZEND_AST_STATIC_CALL:
return zend_ast_is_short_circuited(ast->child[0]);
case ZEND_AST_NULLSAFE_PROP:
case ZEND_AST_NULLSAFE_METHOD_CALL:
return 1;
default:
return 0;
}
}
/* Mark nodes that are an inner part of a short-circuiting chain.
* We should not perform a "commit" on them, as it will be performed by the outer-most node.
* We do this to avoid passing down an argument in various compile functions. */
#define ZEND_SHORT_CIRCUITING_INNER 0x8000
static void zend_short_circuiting_mark_inner(zend_ast *ast) {
if (zend_ast_kind_is_short_circuited(ast->kind)) {
ast->attr |= ZEND_SHORT_CIRCUITING_INNER;
}
}
static uint32_t zend_short_circuiting_checkpoint(void)
{
return zend_stack_count(&CG(short_circuiting_opnums));
}
static void zend_short_circuiting_commit(uint32_t checkpoint, znode *result, zend_ast *ast)
{
bool is_short_circuited = zend_ast_kind_is_short_circuited(ast->kind)
|| ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY;
if (!is_short_circuited) {
ZEND_ASSERT(zend_stack_count(&CG(short_circuiting_opnums)) == checkpoint
&& "Short circuiting stack should be empty");
return;
}
if (ast->attr & ZEND_SHORT_CIRCUITING_INNER) {
/* Outer-most node will commit. */
return;
}
while (zend_stack_count(&CG(short_circuiting_opnums)) != checkpoint) {
uint32_t opnum = *(uint32_t *) zend_stack_top(&CG(short_circuiting_opnums));
zend_op *opline = &CG(active_op_array)->opcodes[opnum];
opline->op2.opline_num = get_next_op_number();
SET_NODE(opline->result, result);
opline->extended_value =
ast->kind == ZEND_AST_ISSET ? ZEND_SHORT_CIRCUITING_CHAIN_ISSET :
ast->kind == ZEND_AST_EMPTY ? ZEND_SHORT_CIRCUITING_CHAIN_EMPTY :
ZEND_SHORT_CIRCUITING_CHAIN_EXPR;
zend_stack_del_top(&CG(short_circuiting_opnums));
}
}
static void zend_emit_jmp_null(znode *obj_node)
{
uint32_t jmp_null_opnum = get_next_op_number();
zend_op *opline = zend_emit_op(NULL, ZEND_JMP_NULL, obj_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
zend_stack_push(&CG(short_circuiting_opnums), &jmp_null_opnum);
}
#define ZEND_MEMOIZE_NONE 0
#define ZEND_MEMOIZE_COMPILE 1
#define ZEND_MEMOIZE_FETCH 2
static void zend_compile_memoized_expr(znode *result, zend_ast *expr) /* {{{ */
{
int memoize_mode = CG(memoize_mode);
if (memoize_mode == ZEND_MEMOIZE_COMPILE) {
znode memoized_result;
/* Go through normal compilation */
CG(memoize_mode) = ZEND_MEMOIZE_NONE;
zend_compile_expr(result, expr);
CG(memoize_mode) = ZEND_MEMOIZE_COMPILE;
if (result->op_type == IS_VAR) {
zend_emit_op(&memoized_result, ZEND_COPY_TMP, result, NULL);
} else if (result->op_type == IS_TMP_VAR) {
zend_emit_op_tmp(&memoized_result, ZEND_COPY_TMP, result, NULL);
} else {
if (result->op_type == IS_CONST) {
Z_TRY_ADDREF(result->u.constant);
}
memoized_result = *result;
}
zend_hash_index_update_mem(
CG(memoized_exprs), (uintptr_t) expr, &memoized_result, sizeof(znode));
} else if (memoize_mode == ZEND_MEMOIZE_FETCH) {
znode *memoized_result = zend_hash_index_find_ptr(CG(memoized_exprs), (uintptr_t) expr);
*result = *memoized_result;
if (result->op_type == IS_CONST) {
Z_TRY_ADDREF(result->u.constant);
}
} else {
ZEND_UNREACHABLE();
}
}
/* }}} */
static size_t zend_type_get_num_classes(zend_type type) {
if (!ZEND_TYPE_HAS_CLASS(type)) {
return 0;
}
if (ZEND_TYPE_HAS_LIST(type)) {
return ZEND_TYPE_LIST(type)->num_types;
}
return 1;
}
static void zend_emit_return_type_check(
znode *expr, zend_arg_info *return_info, bool implicit) /* {{{ */
{
zend_type type = return_info->type;
if (ZEND_TYPE_IS_SET(type)) {
zend_op *opline;
/* `return ...;` is illegal in a void function (but `return;` isn't) */
if (ZEND_TYPE_CONTAINS_CODE(type, IS_VOID)) {
if (expr) {
if (expr->op_type == IS_CONST && Z_TYPE(expr->u.constant) == IS_NULL) {
zend_error_noreturn(E_COMPILE_ERROR,
"A void function must not return a value "
"(did you mean \"return;\" instead of \"return null;\"?)");
} else {
zend_error_noreturn(E_COMPILE_ERROR, "A void function must not return a value");
}
}
/* we don't need run-time check */
return;
}
/* `return` is illegal in a never-returning function */
if (ZEND_TYPE_CONTAINS_CODE(type, IS_NEVER)) {
/* Implicit case handled separately using VERIFY_NEVER_TYPE opcode. */
ZEND_ASSERT(!implicit);
zend_error_noreturn(E_COMPILE_ERROR, "A never-returning function must not return");
return;
}
if (!expr && !implicit) {
if (ZEND_TYPE_ALLOW_NULL(type)) {
zend_error_noreturn(E_COMPILE_ERROR,
"A function with return type must return a value "
"(did you mean \"return null;\" instead of \"return;\"?)");
} else {
zend_error_noreturn(E_COMPILE_ERROR,
"A function with return type must return a value");
}
}
if (expr && ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY) {
/* we don't need run-time check for mixed return type */
return;
}
if (expr && expr->op_type == IS_CONST && ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) {
/* we don't need run-time check */
return;
}
opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL);
if (expr && expr->op_type == IS_CONST) {
opline->result_type = expr->op_type = IS_TMP_VAR;
opline->result.var = expr->u.op.var = get_temporary_variable();
}
opline->op2.num = zend_alloc_cache_slots(zend_type_get_num_classes(return_info->type));
}
}
/* }}} */
void zend_emit_final_return(bool return_one) /* {{{ */
2014-08-29 05:05:58 +00:00
{
znode zn;
zend_op *ret;
bool returns_reference = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
2016-06-10 13:57:18 +00:00
&& !(CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR)) {
zend_arg_info *return_info = CG(active_op_array)->arg_info - 1;
if (ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER)) {
zend_emit_op(NULL, ZEND_VERIFY_NEVER_TYPE, NULL, NULL);
return;
}
zend_emit_return_type_check(NULL, return_info, 1);
}
zn.op_type = IS_CONST;
if (return_one) {
ZVAL_LONG(&zn.u.constant, 1);
} else {
ZVAL_NULL(&zn.u.constant);
}
ret = zend_emit_op(NULL, returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN, &zn, NULL);
ret->extended_value = -1;
}
2014-08-29 05:05:58 +00:00
/* }}} */
static inline bool zend_is_variable(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
return ast->kind == ZEND_AST_VAR
|| ast->kind == ZEND_AST_DIM
|| ast->kind == ZEND_AST_PROP
|| ast->kind == ZEND_AST_NULLSAFE_PROP
|| ast->kind == ZEND_AST_STATIC_PROP;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
static inline bool zend_is_call(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
return ast->kind == ZEND_AST_CALL
|| ast->kind == ZEND_AST_METHOD_CALL
|| ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL
2014-06-07 11:06:53 +00:00
|| ast->kind == ZEND_AST_STATIC_CALL;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
static inline bool zend_is_variable_or_call(zend_ast *ast) /* {{{ */
{
return zend_is_variable(ast) || zend_is_call(ast);
}
/* }}} */
static inline bool zend_is_unticked_stmt(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
return ast->kind == ZEND_AST_STMT_LIST || ast->kind == ZEND_AST_LABEL
|| ast->kind == ZEND_AST_PROP_DECL || ast->kind == ZEND_AST_CLASS_CONST_GROUP
|| ast->kind == ZEND_AST_USE_TRAIT || ast->kind == ZEND_AST_METHOD;
2014-07-09 22:00:48 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 22:00:48 +00:00
static inline bool zend_can_write_to_variable(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
while (
ast->kind == ZEND_AST_DIM
|| ast->kind == ZEND_AST_PROP
) {
2014-06-19 11:57:29 +00:00
ast = ast->child[0];
}
return zend_is_variable_or_call(ast) && !zend_ast_is_short_circuited(ast);
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
static inline bool zend_is_const_default_class_ref(zend_ast *name_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-28 16:03:26 +00:00
if (name_ast->kind != ZEND_AST_ZVAL) {
return 0;
}
return ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type_ast(name_ast);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static inline void zend_handle_numeric_op(znode *node) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (node->op_type == IS_CONST && Z_TYPE(node->u.constant) == IS_STRING) {
zend_ulong index;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (ZEND_HANDLE_NUMERIC(Z_STR(node->u.constant), index)) {
zval_ptr_dtor(&node->u.constant);
ZVAL_LONG(&node->u.constant, index);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2018-07-02 22:09:58 +00:00
static inline void zend_handle_numeric_dim(zend_op *opline, znode *dim_node) /* {{{ */
{
if (Z_TYPE(dim_node->u.constant) == IS_STRING) {
zend_ulong index;
if (ZEND_HANDLE_NUMERIC(Z_STR(dim_node->u.constant), index)) {
/* For numeric indexes we also keep the original value to use by ArrayAccess
2018-07-02 22:09:58 +00:00
* See bug #63217
*/
int c = zend_add_literal(&dim_node->u.constant);
2018-07-02 22:09:58 +00:00
ZEND_ASSERT(opline->op2.constant + 1 == c);
ZVAL_LONG(CT_CONSTANT(opline->op2), index);
Z_EXTRA_P(CT_CONSTANT(opline->op2)) = ZEND_EXTRA_VALUE;
return;
}
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
static inline void zend_set_class_name_op1(zend_op *opline, znode *class_node) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
if (class_node->op_type == IS_CONST) {
opline->op1_type = IS_CONST;
2014-07-19 21:30:07 +00:00
opline->op1.constant = zend_add_class_name_literal(
Z_STR(class_node->u.constant));
2014-06-19 11:57:29 +00:00
} else {
SET_NODE(opline->op1, class_node);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
static void zend_compile_class_ref(znode *result, zend_ast *name_ast, uint32_t fetch_flags) /* {{{ */
{
uint32_t fetch_type;
if (name_ast->kind != ZEND_AST_ZVAL) {
znode name_node;
zend_compile_expr(&name_node, name_ast);
if (name_node.op_type == IS_CONST) {
zend_string *name;
if (Z_TYPE(name_node.u.constant) != IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Illegal class name");
}
name = Z_STR(name_node.u.constant);
fetch_type = zend_get_class_fetch_type(name);
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name(name, ZEND_NAME_FQ));
} else {
zend_ensure_valid_class_fetch_type(fetch_type);
result->op_type = IS_UNUSED;
result->u.op.num = fetch_type | fetch_flags;
}
zend_string_release_ex(name, 0);
} else {
zend_op *opline = zend_emit_op(result, ZEND_FETCH_CLASS, NULL, &name_node);
opline->op1.num = ZEND_FETCH_CLASS_DEFAULT | fetch_flags;
}
return;
}
/* Fully qualified names are always default refs */
if (name_ast->attr == ZEND_NAME_FQ) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
return;
}
fetch_type = zend_get_class_fetch_type(zend_ast_get_str(name_ast));
if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
result->op_type = IS_CONST;
ZVAL_STR(&result->u.constant, zend_resolve_class_name_ast(name_ast));
} else {
zend_ensure_valid_class_fetch_type(fetch_type);
result->op_type = IS_UNUSED;
result->u.op.num = fetch_type | fetch_flags;
}
}
/* }}} */
static zend_result zend_try_compile_cv(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *name_ast = ast->child[0];
2014-06-28 16:03:26 +00:00
if (name_ast->kind == ZEND_AST_ZVAL) {
zval *zv = zend_ast_get_zval(name_ast);
zend_string *name;
if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
name = zval_make_interned_string(zv);
} else {
2017-12-07 16:24:55 +00:00
name = zend_new_interned_string(zval_get_string_func(zv));
}
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
if (zend_is_auto_global(name)) {
2014-06-07 11:06:53 +00:00
return FAILURE;
}
2014-06-07 11:06:53 +00:00
result->op_type = IS_CV;
result->u.op.var = lookup_cv(name);
2014-06-07 11:06:53 +00:00
if (UNEXPECTED(Z_TYPE_P(zv) != IS_STRING)) {
zend_string_release_ex(name, 0);
}
2014-06-07 11:06:53 +00:00
return SUCCESS;
}
return FAILURE;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint32_t type, bool delayed) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *name_ast = ast->child[0];
znode name_node;
zend_op *opline;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&name_node, name_ast);
if (name_node.op_type == IS_CONST) {
convert_to_string(&name_node.u.constant);
}
2015-02-02 17:44:16 +00:00
if (delayed) {
opline = zend_delayed_emit_op(result, ZEND_FETCH_R, &name_node, NULL);
} else {
opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL);
}
2014-06-07 11:06:53 +00:00
if (name_node.op_type == IS_CONST &&
zend_is_auto_global(Z_STR(name_node.u.constant))) {
opline->extended_value = ZEND_FETCH_GLOBAL;
} else {
opline->extended_value = ZEND_FETCH_LOCAL;
2003-02-04 12:12:34 +00:00
}
2014-06-07 11:06:53 +00:00
zend_adjust_for_fetch_type(opline, result, type);
2014-06-07 11:06:53 +00:00
return opline;
2003-02-04 12:12:34 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-02-04 12:12:34 +00:00
static bool is_this_fetch(zend_ast *ast) /* {{{ */
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
{
if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
zval *name = zend_ast_get_zval(ast->child[0]);
return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "this");
}
return 0;
}
/* }}} */
static bool is_globals_fetch(const zend_ast *ast)
{
if (ast->kind == ZEND_AST_VAR && ast->child[0]->kind == ZEND_AST_ZVAL) {
zval *name = zend_ast_get_zval(ast->child[0]);
return Z_TYPE_P(name) == IS_STRING && zend_string_equals_literal(Z_STR_P(name), "GLOBALS");
}
return 0;
}
static bool is_global_var_fetch(zend_ast *ast)
{
return ast->kind == ZEND_AST_DIM && is_globals_fetch(ast->child[0]);
}
static bool this_guaranteed_exists(void) /* {{{ */
{
zend_op_array *op_array = CG(active_op_array);
/* Instance methods always have a $this.
* This also includes closures that have a scope and use $this. */
return op_array->scope != NULL
&& (op_array->fn_flags & ZEND_ACC_STATIC) == 0;
}
/* }}} */
static zend_op *zend_compile_simple_var(znode *result, zend_ast *ast, uint32_t type, bool delayed) /* {{{ */
2014-08-29 05:05:58 +00:00
{
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (is_this_fetch(ast)) {
zend_op *opline = zend_emit_op(result, ZEND_FETCH_THIS, NULL, NULL);
if ((type == BP_VAR_R) || (type == BP_VAR_IS)) {
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
}
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
return opline;
} else if (is_globals_fetch(ast)) {
zend_op *opline = zend_emit_op(result, ZEND_FETCH_GLOBALS, NULL, NULL);
if (type == BP_VAR_R || type == BP_VAR_IS) {
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
}
return opline;
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
} else if (zend_try_compile_cv(result, ast) == FAILURE) {
return zend_compile_simple_var_no_cv(result, ast, type, delayed);
}
return NULL;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if (type != BP_VAR_R && type != BP_VAR_IS && zend_is_call(ast)) {
if (node->op_type == IS_VAR) {
2014-12-13 22:06:14 +00:00
zend_op *opline = zend_emit_op(NULL, ZEND_SEPARATE, node, NULL);
opline->result_type = IS_VAR;
opline->result.var = opline->op1.var;
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
}
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref);
2014-12-13 22:06:14 +00:00
void zend_compile_assign(znode *result, zend_ast *ast);
2014-12-13 22:06:14 +00:00
static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
{
znode dummy_node;
zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
zend_ast_create_znode(value_node));
zend_compile_expr(&dummy_node, assign_ast);
2014-12-13 22:06:14 +00:00
zend_do_free(&dummy_node);
}
/* }}} */
2014-12-13 22:06:14 +00:00
static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (ast->attr == ZEND_DIM_ALTERNATIVE_SYNTAX) {
zend_error(E_COMPILE_ERROR, "Array and string offset access syntax with curly braces is no longer supported");
}
2014-06-07 11:06:53 +00:00
zend_ast *var_ast = ast->child[0];
zend_ast *dim_ast = ast->child[1];
zend_op *opline;
2014-06-07 11:06:53 +00:00
znode var_node, dim_node;
2004-01-28 09:13:41 +00:00
if (is_globals_fetch(var_ast)) {
if (dim_ast == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot append to $GLOBALS");
}
zend_compile_expr(&dim_node, dim_ast);
if (dim_node.op_type == IS_CONST) {
convert_to_string(&dim_node.u.constant);
}
opline = zend_delayed_emit_op(result, ZEND_FETCH_R, &dim_node, NULL);
opline->extended_value = ZEND_FETCH_GLOBAL;
zend_adjust_for_fetch_type(opline, result, type);
return opline;
} else {
zend_short_circuiting_mark_inner(var_ast);
opline = zend_delayed_compile_var(&var_node, var_ast, type, 0);
if (opline && type == BP_VAR_W && (opline->opcode == ZEND_FETCH_STATIC_PROP_W || opline->opcode == ZEND_FETCH_OBJ_W)) {
opline->extended_value |= ZEND_FETCH_DIM_WRITE;
}
}
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write(&var_node, var_ast, type);
2014-06-07 11:06:53 +00:00
if (dim_ast == NULL) {
if (type == BP_VAR_R || type == BP_VAR_IS) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
}
2014-06-07 11:06:53 +00:00
if (type == BP_VAR_UNSET) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
}
2014-06-07 11:06:53 +00:00
dim_node.op_type = IS_UNUSED;
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&dim_node, dim_ast);
}
2004-01-28 09:13:41 +00:00
opline = zend_delayed_emit_op(result, ZEND_FETCH_DIM_R, &var_node, &dim_node);
zend_adjust_for_fetch_type(opline, result, type);
2018-07-02 22:09:58 +00:00
if (dim_node.op_type == IS_CONST) {
zend_handle_numeric_dim(opline, &dim_node);
}
return opline;
}
2014-08-29 05:05:58 +00:00
/* }}} */
static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
uint32_t offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, ast, type);
return zend_delayed_compile_end(offset);
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *obj_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
2014-06-07 11:06:53 +00:00
znode obj_node, prop_node;
zend_op *opline;
bool nullsafe = ast->kind == ZEND_AST_NULLSAFE_PROP;
2003-03-05 11:14:44 +00:00
2014-06-07 11:06:53 +00:00
if (is_this_fetch(obj_ast)) {
if (this_guaranteed_exists()) {
obj_node.op_type = IS_UNUSED;
} else {
zend_emit_op(&obj_node, ZEND_FETCH_THIS, NULL, NULL);
}
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
2020-08-11 13:22:14 +00:00
/* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
* check for a nullsafe access. */
2014-06-07 11:06:53 +00:00
} else {
zend_short_circuiting_mark_inner(obj_ast);
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write(&obj_node, obj_ast, type);
2020-08-11 13:22:14 +00:00
if (nullsafe) {
/* We will push to the short_circuiting_opnums stack in zend_delayed_compile_end(). */
opline = zend_delayed_emit_op(NULL, ZEND_JMP_NULL, &obj_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
2020-08-11 13:22:14 +00:00
}
}
2014-12-13 22:06:14 +00:00
zend_compile_expr(&prop_node, prop_ast);
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_delayed_emit_op(result, ZEND_FETCH_OBJ_R, &obj_node, &prop_node);
if (opline->op2_type == IS_CONST) {
convert_to_string(CT_CONSTANT(opline->op2));
opline->extended_value = zend_alloc_cache_slots(3);
}
zend_adjust_for_fetch_type(opline, result, type);
2014-06-07 11:06:53 +00:00
return opline;
}
2014-08-29 05:05:58 +00:00
/* }}} */
static zend_op *zend_compile_prop(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-12-13 22:06:14 +00:00
uint32_t offset = zend_delayed_compile_begin();
zend_op *opline = zend_delayed_compile_prop(result, ast, type);
if (by_ref) { /* shared with cache_slot */
opline->extended_value |= ZEND_FETCH_REF;
}
2014-12-13 22:06:14 +00:00
return zend_delayed_compile_end(offset);
}
2014-08-29 05:05:58 +00:00
/* }}} */
zend_op *zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, bool by_ref, bool delayed) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *class_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
znode class_node, prop_node;
2014-06-07 11:06:53 +00:00
zend_op *opline;
zend_short_circuiting_mark_inner(class_ast);
zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&prop_node, prop_ast);
2015-02-02 17:44:16 +00:00
if (delayed) {
opline = zend_delayed_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
2015-02-02 17:44:16 +00:00
} else {
opline = zend_emit_op(result, ZEND_FETCH_STATIC_PROP_R, &prop_node, NULL);
2015-02-02 17:44:16 +00:00
}
2014-06-07 11:06:53 +00:00
if (opline->op1_type == IS_CONST) {
convert_to_string(CT_CONSTANT(opline->op1));
opline->extended_value = zend_alloc_cache_slots(3);
2014-06-07 11:06:53 +00:00
}
if (class_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
2014-07-19 21:30:07 +00:00
opline->op2.constant = zend_add_class_name_literal(
Z_STR(class_node.u.constant));
if (opline->op1_type != IS_CONST) {
2018-02-05 17:40:21 +00:00
opline->extended_value = zend_alloc_cache_slot();
}
2014-06-07 11:06:53 +00:00
} else {
SET_NODE(opline->op2, &class_node);
}
2014-05-26 17:29:35 +00:00
if (by_ref && (type == BP_VAR_W || type == BP_VAR_FUNC_ARG)) { /* shared with cache_slot */
opline->extended_value |= ZEND_FETCH_REF;
}
zend_adjust_for_fetch_type(opline, result, type);
return opline;
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
static void zend_verify_list_assign_target(zend_ast *var_ast, zend_ast_attr array_style) /* {{{ */ {
if (var_ast->kind == ZEND_AST_ARRAY) {
if (var_ast->attr == ZEND_ARRAY_SYNTAX_LONG) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot assign to array(), use [] instead");
}
if (array_style != var_ast->attr) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix [] and list()");
}
} else if (!zend_can_write_to_variable(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Assignments can only happen to writable values");
}
}
/* }}} */
static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node);
/* Propagate refs used on leaf elements to the surrounding list() structures. */
static bool zend_propagate_list_refs(zend_ast *ast) { /* {{{ */
zend_ast_list *list = zend_ast_get_list(ast);
bool has_refs = 0;
uint32_t i;
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
if (elem_ast) {
zend_ast *var_ast = elem_ast->child[0];
if (var_ast->kind == ZEND_AST_ARRAY) {
elem_ast->attr = zend_propagate_list_refs(var_ast);
}
has_refs |= elem_ast->attr;
}
}
return has_refs;
}
/* }}} */
static bool list_is_keyed(zend_ast_list *list)
{
for (uint32_t i = 0; i < list->children; i++) {
if (list->child[i]) {
return list->child[i]->child[1] != NULL;
}
}
return false;
}
2016-09-28 19:41:56 +00:00
static void zend_compile_list_assign(
znode *result, zend_ast *ast, znode *expr_node, zend_ast_attr array_style) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2016-09-28 19:41:56 +00:00
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
bool has_elems = 0;
bool is_keyed = list_is_keyed(list);
if (list->children && expr_node->op_type == IS_CONST && Z_TYPE(expr_node->u.constant) == IS_STRING) {
zval_make_interned_string(&expr_node->u.constant);
}
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
2016-09-28 19:41:56 +00:00
zend_ast *var_ast, *key_ast;
znode fetch_result, dim_node;
2018-07-02 22:09:58 +00:00
zend_op *opline;
2014-06-07 11:06:53 +00:00
if (elem_ast == NULL) {
2016-09-28 19:41:56 +00:00
if (is_keyed) {
zend_error(E_COMPILE_ERROR,
"Cannot use empty array entries in keyed array assignment");
} else {
continue;
}
2014-06-07 11:06:53 +00:00
}
2019-11-12 07:51:55 +00:00
if (elem_ast->kind == ZEND_AST_UNPACK) {
zend_error(E_COMPILE_ERROR,
"Spread operator is not supported in assignments");
}
2016-09-28 19:41:56 +00:00
var_ast = elem_ast->child[0];
2016-09-28 19:41:56 +00:00
key_ast = elem_ast->child[1];
has_elems = 1;
2014-06-07 11:06:53 +00:00
2016-09-28 19:41:56 +00:00
if (is_keyed) {
if (key_ast == NULL) {
zend_error(E_COMPILE_ERROR,
"Cannot mix keyed and unkeyed array entries in assignments");
}
2016-09-28 19:41:56 +00:00
zend_compile_expr(&dim_node, key_ast);
} else {
if (key_ast != NULL) {
zend_error(E_COMPILE_ERROR,
"Cannot mix keyed and unkeyed array entries in assignments");
}
2016-09-28 19:41:56 +00:00
dim_node.op_type = IS_CONST;
ZVAL_LONG(&dim_node.u.constant, i);
}
Allow specifying keys on list() elements Squashed commit of the following: commit 0361dbe35616722fbe51b446ab7b43a9ca01f455 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:59:20 2016 +0000 UPGRADING and NEWS commit dca9d4a36c845bfe4fbcb9db18e184469110ea5a Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:45:18 2016 +0000 Add tests contributed by @jesseschalken commit e557f77eab692ed8bb18dbdff48777d80b6f6cbd Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:44:51 2016 +0000 Rebuild VM commit 70942e4c3cbb6b4fe6305b27e1e1b2bed78e76df Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 13:12:26 2016 +0000 Add test for evaluation order of nested list() keys commit ed3592e80c5231d9e9a95558aa768a42b75bdebc Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 12:42:04 2016 +0000 Add test for evaluation order commit 589756cbcccbb4702c90b5aa9c091af446058ca1 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:29:34 2016 +0000 Allow arbitrary expressions for key commit 3f622077c32fcd82fcf27a41bd0f22e2552ec4c5 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:45:10 2016 +0000 Remove compile-time HANDLE_NUMERIC (see bug #63217) commit bab758119aec63289a2c5bef6a5f90a7bc6441a2 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:20:26 2016 +0000 Handle numeric strings commit 14bfe93ddc34d1175bccb42a158be8842c472a9c Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:09:36 2016 +0000 Allow trailing comma commit f4c8b2cb30fc074b15b5f7aabef5444382403b5d Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 23:47:11 2016 +0000 Add tests commit 0085884a6176c3a981b53131fbb4fa0c44db2670 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 22:24:23 2016 +0000 Handle non-integer/string opcodes commit e572d2d0ada6a64b36a2c6f5e8cb57439f51b55e Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 21:10:33 2016 +0000 Disallow mixing keyed and unkeyed list() elements commit cede13ccfe0c486591fa84764271ac1b8cb90d0b Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 10 20:46:44 2016 +0000 list() with keys (no foreach or tests)
2016-03-25 17:18:42 +00:00
if (expr_node->op_type == IS_CONST) {
Z_TRY_ADDREF(expr_node->u.constant);
}
zend_verify_list_assign_target(var_ast, array_style);
2018-07-02 22:09:58 +00:00
opline = zend_emit_op(&fetch_result,
elem_ast->attr ? (expr_node->op_type == IS_CV ? ZEND_FETCH_DIM_W : ZEND_FETCH_LIST_W) : ZEND_FETCH_LIST_R, expr_node, &dim_node);
2018-07-02 22:09:58 +00:00
if (dim_node.op_type == IS_CONST) {
zend_handle_numeric_dim(opline, &dim_node);
}
if (elem_ast->attr) {
zend_emit_op(&fetch_result, ZEND_MAKE_REF, &fetch_result, NULL);
}
if (var_ast->kind == ZEND_AST_ARRAY) {
zend_compile_list_assign(NULL, var_ast, &fetch_result, var_ast->attr);
} else if (elem_ast->attr) {
zend_emit_assign_ref_znode(var_ast, &fetch_result);
} else {
zend_emit_assign_znode(var_ast, &fetch_result);
}
Allow specifying keys on list() elements Squashed commit of the following: commit 0361dbe35616722fbe51b446ab7b43a9ca01f455 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:59:20 2016 +0000 UPGRADING and NEWS commit dca9d4a36c845bfe4fbcb9db18e184469110ea5a Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:45:18 2016 +0000 Add tests contributed by @jesseschalken commit e557f77eab692ed8bb18dbdff48777d80b6f6cbd Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:44:51 2016 +0000 Rebuild VM commit 70942e4c3cbb6b4fe6305b27e1e1b2bed78e76df Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 13:12:26 2016 +0000 Add test for evaluation order of nested list() keys commit ed3592e80c5231d9e9a95558aa768a42b75bdebc Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 12:42:04 2016 +0000 Add test for evaluation order commit 589756cbcccbb4702c90b5aa9c091af446058ca1 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:29:34 2016 +0000 Allow arbitrary expressions for key commit 3f622077c32fcd82fcf27a41bd0f22e2552ec4c5 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:45:10 2016 +0000 Remove compile-time HANDLE_NUMERIC (see bug #63217) commit bab758119aec63289a2c5bef6a5f90a7bc6441a2 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:20:26 2016 +0000 Handle numeric strings commit 14bfe93ddc34d1175bccb42a158be8842c472a9c Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:09:36 2016 +0000 Allow trailing comma commit f4c8b2cb30fc074b15b5f7aabef5444382403b5d Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 23:47:11 2016 +0000 Add tests commit 0085884a6176c3a981b53131fbb4fa0c44db2670 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 22:24:23 2016 +0000 Handle non-integer/string opcodes commit e572d2d0ada6a64b36a2c6f5e8cb57439f51b55e Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 21:10:33 2016 +0000 Disallow mixing keyed and unkeyed list() elements commit cede13ccfe0c486591fa84764271ac1b8cb90d0b Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 10 20:46:44 2016 +0000 list() with keys (no foreach or tests)
2016-03-25 17:18:42 +00:00
}
2016-09-28 19:41:56 +00:00
if (has_elems == 0) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use empty list");
Allow specifying keys on list() elements Squashed commit of the following: commit 0361dbe35616722fbe51b446ab7b43a9ca01f455 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:59:20 2016 +0000 UPGRADING and NEWS commit dca9d4a36c845bfe4fbcb9db18e184469110ea5a Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:45:18 2016 +0000 Add tests contributed by @jesseschalken commit e557f77eab692ed8bb18dbdff48777d80b6f6cbd Author: Andrea Faulds <ajf@ajf.me> Date: Fri Mar 25 16:44:51 2016 +0000 Rebuild VM commit 70942e4c3cbb6b4fe6305b27e1e1b2bed78e76df Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 13:12:26 2016 +0000 Add test for evaluation order of nested list() keys commit ed3592e80c5231d9e9a95558aa768a42b75bdebc Author: Andrea Faulds <ajf@ajf.me> Date: Wed Feb 24 12:42:04 2016 +0000 Add test for evaluation order commit 589756cbcccbb4702c90b5aa9c091af446058ca1 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:29:34 2016 +0000 Allow arbitrary expressions for key commit 3f622077c32fcd82fcf27a41bd0f22e2552ec4c5 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 19 17:45:10 2016 +0000 Remove compile-time HANDLE_NUMERIC (see bug #63217) commit bab758119aec63289a2c5bef6a5f90a7bc6441a2 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:20:26 2016 +0000 Handle numeric strings commit 14bfe93ddc34d1175bccb42a158be8842c472a9c Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 17 01:09:36 2016 +0000 Allow trailing comma commit f4c8b2cb30fc074b15b5f7aabef5444382403b5d Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 23:47:11 2016 +0000 Add tests commit 0085884a6176c3a981b53131fbb4fa0c44db2670 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 22:24:23 2016 +0000 Handle non-integer/string opcodes commit e572d2d0ada6a64b36a2c6f5e8cb57439f51b55e Author: Andrea Faulds <ajf@ajf.me> Date: Sat Jan 16 21:10:33 2016 +0000 Disallow mixing keyed and unkeyed list() elements commit cede13ccfe0c486591fa84764271ac1b8cb90d0b Author: Andrea Faulds <ajf@ajf.me> Date: Sun Jan 10 20:46:44 2016 +0000 list() with keys (no foreach or tests)
2016-03-25 17:18:42 +00:00
}
if (result) {
*result = *expr_node;
} else {
zend_do_free(expr_node);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
static void zend_ensure_writable_variable(const zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if (ast->kind == ZEND_AST_CALL) {
zend_error_noreturn(E_COMPILE_ERROR, "Can't use function return value in write context");
}
if (
ast->kind == ZEND_AST_METHOD_CALL
|| ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL
|| ast->kind == ZEND_AST_STATIC_CALL
) {
2014-06-07 11:06:53 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Can't use method return value in write context");
}
if (zend_ast_is_short_circuited(ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Can't use nullsafe operator in write context");
}
if (is_globals_fetch(ast)) {
zend_error_noreturn(E_COMPILE_ERROR,
"$GLOBALS can only be modified using the $GLOBALS[$name] = $value syntax");
}
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
/* Detects $a... = $a pattern */
bool zend_is_assign_to_self(zend_ast *var_ast, zend_ast *expr_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-28 16:03:26 +00:00
if (expr_ast->kind != ZEND_AST_VAR || expr_ast->child[0]->kind != ZEND_AST_ZVAL) {
2014-06-07 11:06:53 +00:00
return 0;
}
2019-01-27 19:50:08 +00:00
while (zend_is_variable(var_ast) && var_ast->kind != ZEND_AST_VAR) {
2014-06-07 11:06:53 +00:00
var_ast = var_ast->child[0];
}
2014-05-26 17:29:35 +00:00
2014-06-28 16:03:26 +00:00
if (var_ast->kind != ZEND_AST_VAR || var_ast->child[0]->kind != ZEND_AST_ZVAL) {
2014-06-07 11:06:53 +00:00
return 0;
}
2014-06-07 11:06:53 +00:00
{
zend_string *name1 = zval_get_string(zend_ast_get_zval(var_ast->child[0]));
zend_string *name2 = zval_get_string(zend_ast_get_zval(expr_ast->child[0]));
bool result = zend_string_equals(name1, name2);
zend_string_release_ex(name1, 0);
zend_string_release_ex(name2, 0);
2014-06-07 11:06:53 +00:00
return result;
}
2003-03-05 11:14:44 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-05 11:14:44 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *var_ast = ast->child[0];
zend_ast *expr_ast = ast->child[1];
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-06-07 11:06:53 +00:00
znode var_node, expr_node;
zend_op *opline;
uint32_t offset;
2014-06-07 11:06:53 +00:00
if (is_this_fetch(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
zend_ensure_writable_variable(var_ast);
/* Treat $GLOBALS['x'] assignment like assignment to variable. */
zend_ast_kind kind = is_global_var_fetch(var_ast) ? ZEND_AST_VAR : var_ast->kind;
switch (kind) {
2014-06-07 11:06:53 +00:00
case ZEND_AST_VAR:
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(&var_node, var_ast, BP_VAR_W, 0);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
zend_delayed_compile_end(offset);
CG(zend_lineno) = zend_ast_get_lineno(var_ast);
zend_emit_op_tmp(result, ZEND_ASSIGN, &var_node, &expr_node);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_STATIC_PROP:
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(result, var_ast, BP_VAR_W, 0);
zend_compile_expr(&expr_node, expr_ast);
opline = zend_delayed_compile_end(offset);
opline->opcode = ZEND_ASSIGN_STATIC_PROP;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
zend_emit_op_data(&expr_node);
return;
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM:
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_W);
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (zend_is_assign_to_self(var_ast, expr_ast)
&& !is_this_fetch(expr_ast)) {
/* $a[0] = $a should evaluate the right $a first */
znode cv_node;
if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
} else {
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end(offset);
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_ASSIGN_DIM;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_data(&expr_node);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin();
zend_delayed_compile_prop(result, var_ast, BP_VAR_W);
zend_compile_expr(&expr_node, expr_ast);
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end(offset);
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_ASSIGN_OBJ;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op_data(&expr_node);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_ARRAY:
if (zend_propagate_list_refs(var_ast)) {
if (!zend_is_variable_or_call(expr_ast)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot assign reference to non referenceable value");
}
zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
/* MAKE_REF is usually not necessary for CVs. However, if there are
* self-assignments, this forces the RHS to evaluate first. */
zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL);
} else {
if (expr_ast->kind == ZEND_AST_VAR) {
/* list($a, $b) = $a should evaluate the right $a first */
znode cv_node;
if (zend_try_compile_cv(&cv_node, expr_ast) == FAILURE) {
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
} else {
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &cv_node, NULL);
}
} else {
zend_compile_expr(&expr_node, expr_ast);
}
}
zend_compile_list_assign(result, var_ast, &expr_node, var_ast->attr);
2014-06-07 11:06:53 +00:00
return;
EMPTY_SWITCH_DEFAULT_CASE();
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_assign_ref(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *target_ast = ast->child[0];
zend_ast *source_ast = ast->child[1];
znode target_node, source_node;
2014-06-07 11:06:53 +00:00
zend_op *opline;
uint32_t offset, flags;
2014-06-07 11:06:53 +00:00
if (is_this_fetch(target_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
}
zend_ensure_writable_variable(target_ast);
if (zend_ast_is_short_circuited(source_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain");
}
if (is_globals_fetch(source_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot acquire reference to $GLOBALS");
}
2016-02-06 15:38:59 +00:00
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(&target_node, target_ast, BP_VAR_W, 1);
zend_compile_var(&source_node, source_ast, BP_VAR_W, 1);
if ((target_ast->kind != ZEND_AST_VAR
|| target_ast->child[0]->kind != ZEND_AST_ZVAL)
&& source_ast->kind != ZEND_AST_ZNODE
&& source_node.op_type != IS_CV) {
/* Both LHS and RHS expressions may modify the same data structure,
* and the modification during RHS evaluation may dangle the pointer
* to the result of the LHS evaluation.
* Use MAKE_REF instruction to replace direct pointer with REFERENCE.
* See: Bug #71539
*/
zend_emit_op(&source_node, ZEND_MAKE_REF, &source_node, NULL);
}
opline = zend_delayed_compile_end(offset);
if (source_node.op_type != IS_VAR && zend_is_call(source_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
}
flags = zend_is_call(source_ast) ? ZEND_RETURNS_FUNCTION : 0;
if (opline && opline->opcode == ZEND_FETCH_OBJ_W) {
opline->opcode = ZEND_ASSIGN_OBJ_REF;
opline->extended_value &= ~ZEND_FETCH_REF;
opline->extended_value |= flags;
zend_emit_op_data(&source_node);
if (result != NULL) {
*result = target_node;
}
} else if (opline && opline->opcode == ZEND_FETCH_STATIC_PROP_W) {
opline->opcode = ZEND_ASSIGN_STATIC_PROP_REF;
opline->extended_value &= ~ZEND_FETCH_REF;
opline->extended_value |= flags;
zend_emit_op_data(&source_node);
if (result != NULL) {
*result = target_node;
}
} else {
opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node);
opline->extended_value = flags;
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
static inline void zend_emit_assign_ref_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN_REF, var_ast,
zend_ast_create_znode(value_node));
zend_compile_expr(NULL, assign_ast);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_compound_assign(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *var_ast = ast->child[0];
zend_ast *expr_ast = ast->child[1];
uint32_t opcode = ast->attr;
2014-06-07 11:06:53 +00:00
znode var_node, expr_node;
zend_op *opline;
uint32_t offset, cache_slot;
2014-06-07 11:06:53 +00:00
zend_ensure_writable_variable(var_ast);
/* Treat $GLOBALS['x'] assignment like assignment to variable. */
zend_ast_kind kind = is_global_var_fetch(var_ast) ? ZEND_AST_VAR : var_ast->kind;
switch (kind) {
2014-06-07 11:06:53 +00:00
case ZEND_AST_VAR:
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
zend_delayed_compile_end(offset);
opline = zend_emit_op_tmp(result, ZEND_ASSIGN_OP, &var_node, &expr_node);
opline->extended_value = opcode;
2012-12-25 06:23:08 +00:00
return;
case ZEND_AST_STATIC_PROP:
offset = zend_delayed_compile_begin();
zend_delayed_compile_var(result, var_ast, BP_VAR_RW, 0);
zend_compile_expr(&expr_node, expr_ast);
opline = zend_delayed_compile_end(offset);
cache_slot = opline->extended_value;
opline->opcode = ZEND_ASSIGN_STATIC_PROP_OP;
opline->extended_value = opcode;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
opline = zend_emit_op_data(&expr_node);
opline->extended_value = cache_slot;
return;
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM:
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin();
zend_delayed_compile_dim(result, var_ast, BP_VAR_RW);
zend_compile_expr(&expr_node, expr_ast);
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end(offset);
opline->opcode = ZEND_ASSIGN_DIM_OP;
opline->extended_value = opcode;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
2014-06-07 11:06:53 +00:00
zend_emit_op_data(&expr_node);
2012-12-25 06:23:08 +00:00
return;
2014-06-07 11:06:53 +00:00
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
2014-12-13 22:06:14 +00:00
offset = zend_delayed_compile_begin();
zend_delayed_compile_prop(result, var_ast, BP_VAR_RW);
zend_compile_expr(&expr_node, expr_ast);
2014-12-13 22:06:14 +00:00
opline = zend_delayed_compile_end(offset);
cache_slot = opline->extended_value;
opline->opcode = ZEND_ASSIGN_OBJ_OP;
opline->extended_value = opcode;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
2014-06-07 11:06:53 +00:00
opline = zend_emit_op_data(&expr_node);
opline->extended_value = cache_slot;
2014-06-07 11:06:53 +00:00
return;
EMPTY_SWITCH_DEFAULT_CASE()
}
2012-12-25 06:23:08 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
static uint32_t zend_get_arg_num(zend_function *fn, zend_string *arg_name) {
// TODO: Caching?
if (fn->type == ZEND_USER_FUNCTION) {
for (uint32_t i = 0; i < fn->common.num_args; i++) {
zend_arg_info *arg_info = &fn->op_array.arg_info[i];
if (zend_string_equals(arg_info->name, arg_name)) {
return i + 1;
}
}
} else {
for (uint32_t i = 0; i < fn->common.num_args; i++) {
zend_internal_arg_info *arg_info = &fn->internal_function.arg_info[i];
size_t len = strlen(arg_info->name);
if (len == ZSTR_LEN(arg_name) && !memcmp(arg_info->name, ZSTR_VAL(arg_name), len)) {
return i + 1;
}
}
}
/* Either an invalid argument name, or collected into a variadic argument. */
return (uint32_t) -1;
}
uint32_t zend_compile_args(
zend_ast *ast, zend_function *fbc, bool *may_have_extra_named_args) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *args = zend_ast_get_list(ast);
uint32_t i;
bool uses_arg_unpack = 0;
uint32_t arg_count = 0; /* number of arguments not including unpacks */
2012-12-25 06:23:08 +00:00
/* Whether named arguments are used syntactically, to enforce language level limitations.
* May not actually use named argument passing. */
bool uses_named_args = 0;
/* Whether there may be any undef arguments due to the use of named arguments. */
bool may_have_undef = 0;
/* Whether there may be any extra named arguments collected into a variadic. */
*may_have_extra_named_args = 0;
2014-07-13 11:11:55 +00:00
for (i = 0; i < args->children; ++i) {
zend_ast *arg = args->child[i];
zend_string *arg_name = NULL;
uint32_t arg_num = i + 1;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-13 11:11:55 +00:00
znode arg_node;
2014-06-07 11:06:53 +00:00
zend_op *opline;
zend_uchar opcode;
2014-07-13 11:11:55 +00:00
if (arg->kind == ZEND_AST_UNPACK) {
if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking");
}
2014-06-07 11:06:53 +00:00
uses_arg_unpack = 1;
2014-07-22 18:41:45 +00:00
fbc = NULL;
2015-01-03 09:22:58 +00:00
zend_compile_expr(&arg_node, arg->child[0]);
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_SEND_UNPACK, &arg_node, NULL);
2014-06-07 11:06:53 +00:00
opline->op2.num = arg_count;
2020-02-27 13:48:43 +00:00
opline->result.var = EX_NUM_TO_VAR(arg_count - 1);
/* Unpack may contain named arguments. */
may_have_undef = 1;
if (!fbc || (fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
*may_have_extra_named_args = 1;
}
2014-06-07 11:06:53 +00:00
continue;
}
if (arg->kind == ZEND_AST_NAMED_ARG) {
if (uses_arg_unpack) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking");
}
uses_named_args = 1;
arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0]));
arg = arg->child[1];
if (fbc) {
arg_num = zend_get_arg_num(fbc, arg_name);
if (arg_num == arg_count + 1 && !may_have_undef) {
/* Using named arguments, but passing in order. */
arg_name = NULL;
arg_count++;
} else {
// TODO: We could track which arguments were passed, even if out of order.
may_have_undef = 1;
if (arg_num == (uint32_t) -1 && (fbc->common.fn_flags & ZEND_ACC_VARIADIC)) {
*may_have_extra_named_args = 1;
}
}
} else {
arg_num = (uint32_t) -1;
may_have_undef = 1;
*may_have_extra_named_args = 1;
}
} else {
if (uses_arg_unpack) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use positional argument after argument unpacking");
}
if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use positional argument after named argument");
}
arg_count++;
2014-06-07 11:06:53 +00:00
}
/* Treat passing of $GLOBALS the same as passing a call.
* This will error at runtime if the argument is by-ref. */
if (zend_is_call(arg) || is_globals_fetch(arg)) {
2019-03-06 09:42:02 +00:00
zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
/* Function call was converted into builtin instruction */
if (!fbc || ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAL_EX;
} else {
opcode = ZEND_SEND_VAL;
}
2019-03-06 09:42:02 +00:00
} else {
if (fbc && arg_num != (uint32_t) -1) {
2019-03-06 09:42:02 +00:00
if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAR_NO_REF;
} else if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAL;
} else {
2019-03-06 09:42:02 +00:00
opcode = ZEND_SEND_VAR;
2014-06-07 11:06:53 +00:00
}
2019-03-06 09:42:02 +00:00
} else {
opcode = ZEND_SEND_VAR_NO_REF_EX;
2014-06-07 11:06:53 +00:00
}
2019-03-06 09:42:02 +00:00
}
} else if (zend_is_variable(arg) && !zend_ast_is_short_circuited(arg)) {
if (fbc && arg_num != (uint32_t) -1) {
2014-06-07 11:06:53 +00:00
if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
zend_compile_var(&arg_node, arg, BP_VAR_W, 1);
2014-06-07 11:06:53 +00:00
opcode = ZEND_SEND_REF;
} else {
zend_compile_var(&arg_node, arg, BP_VAR_R, 0);
opcode = (arg_node.op_type == IS_TMP_VAR) ? ZEND_SEND_VAL : ZEND_SEND_VAR;
2014-06-07 11:06:53 +00:00
}
} else {
do {
if (arg->kind == ZEND_AST_VAR) {
CG(zend_lineno) = zend_ast_get_lineno(ast);
if (is_this_fetch(arg)) {
zend_emit_op(&arg_node, ZEND_FETCH_THIS, NULL, NULL);
opcode = ZEND_SEND_VAR_EX;
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
break;
} else if (zend_try_compile_cv(&arg_node, arg) == SUCCESS) {
opcode = ZEND_SEND_VAR_EX;
break;
}
}
opline = zend_emit_op(NULL, ZEND_CHECK_FUNC_ARG, NULL, NULL);
if (arg_name) {
opline->op2_type = IS_CONST;
zend_string_addref(arg_name);
opline->op2.constant = zend_add_literal_string(&arg_name);
opline->result.num = zend_alloc_cache_slots(2);
} else {
opline->op2.num = arg_num;
}
zend_compile_var(&arg_node, arg, BP_VAR_FUNC_ARG, 1);
opcode = ZEND_SEND_FUNC_ARG;
} while (0);
2014-06-07 11:06:53 +00:00
}
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&arg_node, arg);
if (arg_node.op_type == IS_VAR) {
/* pass ++$a or something similar */
if (fbc && arg_num != (uint32_t) -1) {
if (ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAR_NO_REF;
} else if (ARG_MAY_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAL;
} else {
opcode = ZEND_SEND_VAR;
}
} else {
opcode = ZEND_SEND_VAR_NO_REF_EX;
2014-06-07 11:06:53 +00:00
}
} else if (arg_node.op_type == IS_CV) {
if (fbc && arg_num != (uint32_t) -1) {
if (ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_REF;
} else {
opcode = ZEND_SEND_VAR;
}
} else {
opcode = ZEND_SEND_VAR_EX;
}
2014-06-07 11:06:53 +00:00
} else {
/* Delay "Only variables can be passed by reference" error to execution */
if (fbc && arg_num != (uint32_t) -1 && !ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
opcode = ZEND_SEND_VAL;
} else {
opcode = ZEND_SEND_VAL_EX;
2014-06-07 11:06:53 +00:00
}
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
opline = zend_emit_op(NULL, opcode, &arg_node, NULL);
if (arg_name) {
opline->op2_type = IS_CONST;
zend_string_addref(arg_name);
opline->op2.constant = zend_add_literal_string(&arg_name);
opline->result.num = zend_alloc_cache_slots(2);
} else {
opline->op2.opline_num = arg_num;
opline->result.var = EX_NUM_TO_VAR(arg_num - 1);
}
}
if (may_have_undef) {
zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-06-07 11:06:53 +00:00
return arg_count;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
ZEND_API zend_uchar zend_get_call_op(const zend_op *init_op, zend_function *fbc) /* {{{ */
{
2016-06-28 09:57:04 +00:00
if (fbc) {
if (fbc->type == ZEND_INTERNAL_FUNCTION && !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS)) {
2016-06-28 09:57:04 +00:00
if (init_op->opcode == ZEND_INIT_FCALL && !zend_execute_internal) {
if (!(fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED))) {
return ZEND_DO_ICALL;
} else {
return ZEND_DO_FCALL_BY_NAME;
}
}
} else if (!(CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS)){
2016-06-28 09:57:04 +00:00
if (zend_execute_ex == execute_ex && !(fbc->common.fn_flags & ZEND_ACC_ABSTRACT)) {
2016-06-04 10:59:35 +00:00
return ZEND_DO_UCALL;
}
}
} else if (zend_execute_ex == execute_ex &&
!zend_execute_internal &&
(init_op->opcode == ZEND_INIT_FCALL_BY_NAME ||
init_op->opcode == ZEND_INIT_NS_FCALL_BY_NAME)) {
return ZEND_DO_FCALL_BY_NAME;
}
return ZEND_DO_FCALL;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_call_common(znode *result, zend_ast *args_ast, zend_function *fbc) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_op *opline;
uint32_t opnum_init = get_next_op_number() - 1;
uint32_t arg_count;
bool may_have_extra_named_args;
2012-12-25 06:23:08 +00:00
arg_count = zend_compile_args(args_ast, fbc, &may_have_extra_named_args);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
zend_do_extended_fcall_begin();
opline = &CG(active_op_array)->opcodes[opnum_init];
2014-06-07 11:06:53 +00:00
opline->extended_value = arg_count;
if (opline->opcode == ZEND_INIT_FCALL) {
opline->op1.num = zend_vm_calc_used_stack(arg_count, fbc);
}
opline = zend_emit_op(result, zend_get_call_op(opline, fbc), NULL, NULL);
if (may_have_extra_named_args) {
opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
}
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_end();
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2012-12-25 06:23:08 +00:00
bool zend_compile_function_name(znode *name_node, zend_ast *name_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-28 13:16:35 +00:00
zend_string *orig_name = zend_ast_get_str(name_ast);
bool is_fully_qualified;
2012-12-25 06:23:08 +00:00
name_node->op_type = IS_CONST;
ZVAL_STR(&name_node->u.constant, zend_resolve_function_name(
2014-12-13 22:06:14 +00:00
orig_name, name_ast->attr, &is_fully_qualified));
return !is_fully_qualified && FC(current_namespace);
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline = get_next_op();
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_INIT_NS_FCALL_BY_NAME;
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal(
Z_STR(name_node->u.constant));
opline->result.num = zend_alloc_cache_slot();
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_call_common(result, args_ast, NULL);
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
const char *colon;
zend_string *str = Z_STR(name_node->u.constant);
if ((colon = zend_memrchr(ZSTR_VAL(str), ':', ZSTR_LEN(str))) != NULL && colon > ZSTR_VAL(str) && *(colon - 1) == ':') {
zend_string *class = zend_string_init(ZSTR_VAL(str), colon - ZSTR_VAL(str) - 1, 0);
zend_string *method = zend_string_init(colon + 1, ZSTR_LEN(str) - (colon - ZSTR_VAL(str)) - 1, 0);
zend_op *opline = get_next_op();
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_class_name_literal(class);
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(method);
/* 2 slots, for class and method */
opline->result.num = zend_alloc_cache_slots(2);
zval_ptr_dtor(&name_node->u.constant);
} else {
zend_op *opline = get_next_op();
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(str);
opline->result.num = zend_alloc_cache_slot();
}
2014-06-07 11:06:53 +00:00
} else {
zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_call_common(result, args_ast, NULL);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
static inline bool zend_args_contain_unpack_or_named(zend_ast_list *args) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-08-25 17:28:33 +00:00
uint32_t i;
2014-07-13 11:11:55 +00:00
for (i = 0; i < args->children; ++i) {
zend_ast *arg = args->child[i];
if (arg->kind == ZEND_AST_UNPACK || arg->kind == ZEND_AST_NAMED_ARG) {
2014-06-07 11:06:53 +00:00
return 1;
}
}
2014-06-07 11:06:53 +00:00
return 0;
}
2014-08-29 05:05:58 +00:00
/* }}} */
zend_result zend_compile_func_strlen(znode *result, zend_ast_list *args) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:11:12 +00:00
znode arg_node;
if (args->children != 1) {
2014-07-22 21:11:12 +00:00
return FAILURE;
2012-12-25 06:23:08 +00:00
}
2014-07-22 21:11:12 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&arg_node, args->child[0]);
2015-06-10 22:57:37 +00:00
if (arg_node.op_type == IS_CONST && Z_TYPE(arg_node.u.constant) == IS_STRING) {
result->op_type = IS_CONST;
ZVAL_LONG(&result->u.constant, Z_STRLEN(arg_node.u.constant));
zval_ptr_dtor_str(&arg_node.u.constant);
2015-06-10 22:57:37 +00:00
} else {
zend_emit_op_tmp(result, ZEND_STRLEN, &arg_node, NULL);
}
2014-07-22 21:11:12 +00:00
return SUCCESS;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
zend_result zend_compile_func_typecheck(znode *result, zend_ast_list *args, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:11:12 +00:00
znode arg_node;
zend_op *opline;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (args->children != 1) {
2014-07-22 21:11:12 +00:00
return FAILURE;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&arg_node, args->child[0]);
opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL);
if (type != _IS_BOOL) {
opline->extended_value = (1 << type);
} else {
opline->extended_value = (1 << IS_FALSE) | (1 << IS_TRUE);
}
2014-07-22 21:11:12 +00:00
return SUCCESS;
}
2014-08-29 05:05:58 +00:00
/* }}} */
static zend_result zend_compile_func_is_scalar(znode *result, zend_ast_list *args) /* {{{ */
{
znode arg_node;
zend_op *opline;
if (args->children != 1) {
return FAILURE;
}
zend_compile_expr(&arg_node, args->child[0]);
opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &arg_node, NULL);
opline->extended_value = (1 << IS_FALSE | 1 << IS_TRUE | 1 << IS_DOUBLE | 1 << IS_LONG | 1 << IS_STRING);
return SUCCESS;
}
zend_result zend_compile_func_cast(znode *result, zend_ast_list *args, uint32_t type) /* {{{ */
2016-09-09 13:45:46 +00:00
{
znode arg_node;
zend_op *opline;
if (args->children != 1) {
2016-09-09 13:45:46 +00:00
return FAILURE;
}
zend_compile_expr(&arg_node, args->child[0]);
if (type == _IS_BOOL) {
opline = zend_emit_op_tmp(result, ZEND_BOOL, &arg_node, NULL);
} else {
opline = zend_emit_op_tmp(result, ZEND_CAST, &arg_node, NULL);
opline->extended_value = type;
}
2016-09-09 13:45:46 +00:00
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_defined(znode *result, zend_ast_list *args) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-22 21:27:00 +00:00
zend_string *name;
zend_op *opline;
if (args->children != 1 || args->child[0]->kind != ZEND_AST_ZVAL) {
2014-07-22 21:27:00 +00:00
return FAILURE;
}
2010-05-02 18:47:27 +00:00
name = zval_get_string(zend_ast_get_zval(args->child[0]));
if (zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)) || zend_memrchr(ZSTR_VAL(name), ':', ZSTR_LEN(name))) {
zend_string_release_ex(name, 0);
2014-07-22 21:27:00 +00:00
return FAILURE;
}
2012-12-25 06:23:08 +00:00
if (zend_try_ct_eval_const(&result->u.constant, name, 0)) {
zend_string_release_ex(name, 0);
zval_ptr_dtor(&result->u.constant);
ZVAL_TRUE(&result->u.constant);
result->op_type = IS_CONST;
return SUCCESS;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(result, ZEND_DEFINED, NULL, NULL);
2014-07-22 21:27:00 +00:00
opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, name);
opline->extended_value = zend_alloc_cache_slot();
2014-07-22 21:27:00 +00:00
return SUCCESS;
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
zend_result zend_compile_func_chr(znode *result, zend_ast_list *args) /* {{{ */
{
if (args->children == 1 &&
args->child[0]->kind == ZEND_AST_ZVAL &&
Z_TYPE_P(zend_ast_get_zval(args->child[0])) == IS_LONG) {
zend_long c = Z_LVAL_P(zend_ast_get_zval(args->child[0])) & 0xff;
result->op_type = IS_CONST;
ZVAL_CHAR(&result->u.constant, c);
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
zend_result zend_compile_func_ord(znode *result, zend_ast_list *args) /* {{{ */
{
if (args->children == 1 &&
args->child[0]->kind == ZEND_AST_ZVAL &&
Z_TYPE_P(zend_ast_get_zval(args->child[0])) == IS_STRING) {
result->op_type = IS_CONST;
ZVAL_LONG(&result->u.constant, (unsigned char)Z_STRVAL_P(zend_ast_get_zval(args->child[0]))[0]);
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
/* We can only calculate the stack size for functions that have been fully compiled, otherwise
* additional CV or TMP slots may still be added. This prevents the use of INIT_FCALL for
* directly or indirectly recursive function calls. */
static bool fbc_is_finalized(zend_function *fbc) {
return !ZEND_USER_CODE(fbc->type) || (fbc->common.fn_flags & ZEND_ACC_DONE_PASS_TWO);
}
static zend_result zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t num_args) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_string *name, *lcname;
zend_function *fbc;
zend_op *opline;
if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
return FAILURE;
}
2014-07-28 13:16:35 +00:00
name = zend_ast_get_str(name_ast);
lcname = zend_string_tolower(name);
fbc = zend_hash_find_ptr(CG(function_table), lcname);
if (!fbc || !fbc_is_finalized(fbc)
|| (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS))
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename)
) {
zend_string_release_ex(lcname, 0);
return FAILURE;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, NULL);
opline->extended_value = num_args;
opline->op1.num = zend_vm_calc_used_stack(num_args, fbc);
opline->op2_type = IS_CONST;
LITERAL_STR(opline->op2, lcname);
opline->result.num = zend_alloc_cache_slot();
return SUCCESS;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_init_user_func(zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline;
znode name_node;
2014-12-13 22:06:14 +00:00
if (zend_try_compile_ct_bound_init_user_func(name_ast, num_args) == SUCCESS) {
2011-06-20 01:36:23 +00:00
return;
}
2014-12-13 22:06:14 +00:00
zend_compile_expr(&name_node, name_ast);
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_INIT_USER_CALL, NULL, &name_node);
opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, zend_string_copy(orig_func_name));
opline->extended_value = num_args;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-24 18:35:18 +00:00
/* cufa = call_user_func_array */
zend_result zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
2014-08-29 05:05:58 +00:00
{
znode arg_node;
if (args->children != 2) {
return FAILURE;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
zend_compile_init_user_func(args->child[0], 0, lcname);
if (args->child[1]->kind == ZEND_AST_CALL
&& args->child[1]->child[0]->kind == ZEND_AST_ZVAL
2017-05-30 18:48:16 +00:00
&& Z_TYPE_P(zend_ast_get_zval(args->child[1]->child[0])) == IS_STRING
&& args->child[1]->child[1]->kind == ZEND_AST_ARG_LIST) {
2017-05-30 18:48:16 +00:00
zend_string *orig_name = zend_ast_get_str(args->child[1]->child[0]);
zend_ast_list *list = zend_ast_get_list(args->child[1]->child[1]);
bool is_fully_qualified;
2017-05-30 18:48:16 +00:00
zend_string *name = zend_resolve_function_name(orig_name, args->child[1]->child[0]->attr, &is_fully_qualified);
2017-05-30 18:48:16 +00:00
if (zend_string_equals_literal_ci(name, "array_slice")
&& !zend_args_contain_unpack_or_named(list)
&& list->children == 3
&& list->child[1]->kind == ZEND_AST_ZVAL) {
zval *zv = zend_ast_get_zval(list->child[1]);
if (Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) >= 0
&& Z_LVAL_P(zv) <= 0x7fffffff) {
zend_op *opline;
znode len_node;
zend_compile_expr(&arg_node, list->child[0]);
zend_compile_expr(&len_node, list->child[2]);
opline = zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, &len_node);
opline->extended_value = Z_LVAL_P(zv);
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
zend_string_release_ex(name, 0);
return SUCCESS;
}
}
zend_string_release_ex(name, 0);
}
2014-12-13 22:06:14 +00:00
zend_compile_expr(&arg_node, args->child[1]);
zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL);
zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
2014-12-13 22:06:14 +00:00
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
return SUCCESS;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-07-24 18:35:18 +00:00
/* cuf = call_user_func */
zend_result zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-08-25 17:28:33 +00:00
uint32_t i;
2012-12-25 06:23:08 +00:00
if (args->children < 1) {
2014-07-24 18:35:18 +00:00
return FAILURE;
}
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_init_user_func(args->child[0], args->children - 1, lcname);
for (i = 1; i < args->children; ++i) {
zend_ast *arg_ast = args->child[i];
2014-07-24 18:35:18 +00:00
znode arg_node;
zend_op *opline;
2012-12-25 06:23:08 +00:00
zend_compile_expr(&arg_node, arg_ast);
2014-07-24 18:35:18 +00:00
opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL);
opline->op2.num = i;
2020-02-27 13:48:43 +00:00
opline->result.var = EX_NUM_TO_VAR(i - 1);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-12-13 22:06:14 +00:00
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
2014-07-24 18:35:18 +00:00
return SUCCESS;
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
static void zend_compile_assert(znode *result, zend_ast_list *args, zend_string *name, zend_function *fbc) /* {{{ */
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
{
if (EG(assertions) >= 0) {
znode name_node;
zend_op *opline;
uint32_t check_op_number = get_next_op_number();
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
zend_emit_op(NULL, ZEND_ASSERT_CHECK, NULL, NULL);
if (fbc && fbc_is_finalized(fbc)) {
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
name_node.op_type = IS_CONST;
ZVAL_STR_COPY(&name_node.u.constant, name);
opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
} else {
opline = zend_emit_op(NULL, ZEND_INIT_NS_FCALL_BY_NAME, NULL, NULL);
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal(name);
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
}
opline->result.num = zend_alloc_cache_slot();
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
if (args->children == 1) {
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
/* add "assert(condition) as assertion message */
zend_ast *arg = zend_ast_create_zval_from_str(
zend_ast_export("assert(", args->child[0], ")"));
if (args->child[0]->kind == ZEND_AST_NAMED_ARG) {
/* If the original argument was named, add the new argument as named as well,
* as mixing named and positional is not allowed. */
zend_ast *name = zend_ast_create_zval_from_str(
zend_string_init("description", sizeof("description") - 1, 0));
arg = zend_ast_create(ZEND_AST_NAMED_ARG, name, arg);
}
zend_ast_list_add((zend_ast *) args, arg);
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
}
zend_compile_call_common(result, (zend_ast*)args, fbc);
opline = &CG(active_op_array)->opcodes[check_op_number];
opline->op2.opline_num = get_next_op_number();
SET_NODE(opline->result, result);
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
} else {
if (!fbc) {
zend_string_release_ex(name, 0);
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
}
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
}
}
/* }}} */
static zend_result zend_compile_func_in_array(znode *result, zend_ast_list *args) /* {{{ */
{
bool strict = 0;
znode array, needly;
zend_op *opline;
if (args->children == 3) {
2017-05-25 07:26:42 +00:00
if (args->child[2]->kind == ZEND_AST_ZVAL) {
strict = zend_is_true(zend_ast_get_zval(args->child[2]));
} else if (args->child[2]->kind == ZEND_AST_CONST) {
zval value;
zend_ast *name_ast = args->child[2]->child[0];
bool is_fully_qualified;
2017-05-25 07:26:42 +00:00
zend_string *resolved_name = zend_resolve_const_name(
zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified);
if (!zend_try_ct_eval_const(&value, resolved_name, is_fully_qualified)) {
zend_string_release_ex(resolved_name, 0);
2017-05-25 07:26:42 +00:00
return FAILURE;
}
zend_string_release_ex(resolved_name, 0);
2017-05-25 07:26:42 +00:00
strict = zend_is_true(&value);
zval_ptr_dtor(&value);
} else {
return FAILURE;
}
2017-05-25 07:26:42 +00:00
} else if (args->children != 2) {
return FAILURE;
}
2017-05-25 07:26:42 +00:00
if (args->child[1]->kind != ZEND_AST_ARRAY
|| !zend_try_ct_eval_array(&array.u.constant, args->child[1])) {
return FAILURE;
}
if (zend_hash_num_elements(Z_ARRVAL(array.u.constant)) > 0) {
bool ok = 1;
zval *val, tmp;
HashTable *src = Z_ARRVAL(array.u.constant);
HashTable *dst = zend_new_array(zend_hash_num_elements(src));
ZVAL_TRUE(&tmp);
if (strict) {
ZEND_HASH_FOREACH_VAL(src, val) {
if (Z_TYPE_P(val) == IS_STRING) {
zend_hash_add(dst, Z_STR_P(val), &tmp);
} else if (Z_TYPE_P(val) == IS_LONG) {
zend_hash_index_add(dst, Z_LVAL_P(val), &tmp);
} else {
zend_array_destroy(dst);
ok = 0;
break;
}
} ZEND_HASH_FOREACH_END();
} else {
ZEND_HASH_FOREACH_VAL(src, val) {
2017-05-25 07:26:42 +00:00
if (Z_TYPE_P(val) != IS_STRING
|| is_numeric_string(Z_STRVAL_P(val), Z_STRLEN_P(val), NULL, NULL, 0)) {
zend_array_destroy(dst);
ok = 0;
break;
}
zend_hash_add(dst, Z_STR_P(val), &tmp);
} ZEND_HASH_FOREACH_END();
}
zend_array_destroy(src);
if (!ok) {
return FAILURE;
}
Z_ARRVAL(array.u.constant) = dst;
}
array.op_type = IS_CONST;
zend_compile_expr(&needly, args->child[0]);
opline = zend_emit_op_tmp(result, ZEND_IN_ARRAY, &needly, &array);
opline->extended_value = strict;
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_count(znode *result, zend_ast_list *args, zend_string *lcname) /* {{{ */
{
znode arg_node;
zend_op *opline;
if (args->children != 1) {
return FAILURE;
}
zend_compile_expr(&arg_node, args->child[0]);
opline = zend_emit_op_tmp(result, ZEND_COUNT, &arg_node, NULL);
opline->extended_value = zend_string_equals_literal(lcname, "sizeof");
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_get_class(znode *result, zend_ast_list *args) /* {{{ */
{
if (args->children == 0) {
zend_emit_op_tmp(result, ZEND_GET_CLASS, NULL, NULL);
} else {
znode arg_node;
if (args->children != 1) {
return FAILURE;
}
zend_compile_expr(&arg_node, args->child[0]);
zend_emit_op_tmp(result, ZEND_GET_CLASS, &arg_node, NULL);
}
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_get_called_class(znode *result, zend_ast_list *args) /* {{{ */
{
if (args->children != 0) {
return FAILURE;
}
2017-05-25 17:20:57 +00:00
zend_emit_op_tmp(result, ZEND_GET_CALLED_CLASS, NULL, NULL);
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_gettype(znode *result, zend_ast_list *args) /* {{{ */
{
znode arg_node;
if (args->children != 1) {
return FAILURE;
}
zend_compile_expr(&arg_node, args->child[0]);
zend_emit_op_tmp(result, ZEND_GET_TYPE, &arg_node, NULL);
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_num_args(znode *result, zend_ast_list *args) /* {{{ */
{
if (CG(active_op_array)->function_name && args->children == 0) {
zend_emit_op_tmp(result, ZEND_FUNC_NUM_ARGS, NULL, NULL);
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
zend_result zend_compile_func_get_args(znode *result, zend_ast_list *args) /* {{{ */
{
if (CG(active_op_array)->function_name && args->children == 0) {
zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, NULL, NULL);
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
zend_result zend_compile_func_array_key_exists(znode *result, zend_ast_list *args) /* {{{ */
{
znode subject, needle;
if (args->children != 2) {
return FAILURE;
}
zend_compile_expr(&needle, args->child[0]);
zend_compile_expr(&subject, args->child[1]);
zend_emit_op_tmp(result, ZEND_ARRAY_KEY_EXISTS, &needle, &subject);
return SUCCESS;
}
/* }}} */
zend_result zend_compile_func_array_slice(znode *result, zend_ast_list *args) /* {{{ */
{
if (CG(active_op_array)->function_name
&& args->children == 2
&& args->child[0]->kind == ZEND_AST_CALL
&& args->child[0]->child[0]->kind == ZEND_AST_ZVAL
2017-05-30 18:48:16 +00:00
&& Z_TYPE_P(zend_ast_get_zval(args->child[0]->child[0])) == IS_STRING
&& args->child[0]->child[1]->kind == ZEND_AST_ARG_LIST
&& args->child[1]->kind == ZEND_AST_ZVAL) {
2017-05-30 18:48:16 +00:00
zend_string *orig_name = zend_ast_get_str(args->child[0]->child[0]);
bool is_fully_qualified;
2017-05-30 18:48:16 +00:00
zend_string *name = zend_resolve_function_name(orig_name, args->child[0]->child[0]->attr, &is_fully_qualified);
zend_ast_list *list = zend_ast_get_list(args->child[0]->child[1]);
zval *zv = zend_ast_get_zval(args->child[1]);
znode first;
2017-05-30 18:48:16 +00:00
if (zend_string_equals_literal_ci(name, "func_get_args")
&& list->children == 0
&& Z_TYPE_P(zv) == IS_LONG
&& Z_LVAL_P(zv) >= 0) {
first.op_type = IS_CONST;
ZVAL_LONG(&first.u.constant, Z_LVAL_P(zv));
zend_emit_op_tmp(result, ZEND_FUNC_GET_ARGS, &first, NULL);
zend_string_release_ex(name, 0);
return SUCCESS;
}
zend_string_release_ex(name, 0);
}
return FAILURE;
}
/* }}} */
zend_result zend_try_compile_special_func(znode *result, zend_string *lcname, zend_ast_list *args, zend_function *fbc, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (CG(compiler_options) & ZEND_COMPILE_NO_BUILTINS) {
return FAILURE;
}
if (fbc->type != ZEND_INTERNAL_FUNCTION) {
/* If the function is part of disabled_functions, it may be redeclared as a userland
* function with a different implementation. Don't use the VM builtin in that case. */
return FAILURE;
}
if (zend_args_contain_unpack_or_named(args)) {
return FAILURE;
}
if (zend_string_equals_literal(lcname, "strlen")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_strlen(result, args);
} else if (zend_string_equals_literal(lcname, "is_null")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_NULL);
} else if (zend_string_equals_literal(lcname, "is_bool")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, _IS_BOOL);
} else if (zend_string_equals_literal(lcname, "is_long")
|| zend_string_equals_literal(lcname, "is_int")
|| zend_string_equals_literal(lcname, "is_integer")
) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_LONG);
} else if (zend_string_equals_literal(lcname, "is_float")
|| zend_string_equals_literal(lcname, "is_double")
) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_DOUBLE);
} else if (zend_string_equals_literal(lcname, "is_string")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_STRING);
} else if (zend_string_equals_literal(lcname, "is_array")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_ARRAY);
} else if (zend_string_equals_literal(lcname, "is_object")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_OBJECT);
} else if (zend_string_equals_literal(lcname, "is_resource")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_typecheck(result, args, IS_RESOURCE);
} else if (zend_string_equals_literal(lcname, "is_scalar")) {
return zend_compile_func_is_scalar(result, args);
2016-09-09 13:45:46 +00:00
} else if (zend_string_equals_literal(lcname, "boolval")) {
return zend_compile_func_cast(result, args, _IS_BOOL);
} else if (zend_string_equals_literal(lcname, "intval")) {
return zend_compile_func_cast(result, args, IS_LONG);
} else if (zend_string_equals_literal(lcname, "floatval")
|| zend_string_equals_literal(lcname, "doubleval")
) {
return zend_compile_func_cast(result, args, IS_DOUBLE);
} else if (zend_string_equals_literal(lcname, "strval")) {
return zend_compile_func_cast(result, args, IS_STRING);
} else if (zend_string_equals_literal(lcname, "defined")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_defined(result, args);
} else if (zend_string_equals_literal(lcname, "chr") && type == BP_VAR_R) {
return zend_compile_func_chr(result, args);
} else if (zend_string_equals_literal(lcname, "ord") && type == BP_VAR_R) {
return zend_compile_func_ord(result, args);
} else if (zend_string_equals_literal(lcname, "call_user_func_array")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_cufa(result, args, lcname);
} else if (zend_string_equals_literal(lcname, "call_user_func")) {
2014-12-13 22:06:14 +00:00
return zend_compile_func_cuf(result, args, lcname);
} else if (zend_string_equals_literal(lcname, "in_array")) {
return zend_compile_func_in_array(result, args);
} else if (zend_string_equals_literal(lcname, "count")
|| zend_string_equals_literal(lcname, "sizeof")) {
return zend_compile_func_count(result, args, lcname);
} else if (zend_string_equals_literal(lcname, "get_class")) {
return zend_compile_func_get_class(result, args);
} else if (zend_string_equals_literal(lcname, "get_called_class")) {
return zend_compile_func_get_called_class(result, args);
} else if (zend_string_equals_literal(lcname, "gettype")) {
return zend_compile_func_gettype(result, args);
} else if (zend_string_equals_literal(lcname, "func_num_args")) {
return zend_compile_func_num_args(result, args);
} else if (zend_string_equals_literal(lcname, "func_get_args")) {
return zend_compile_func_get_args(result, args);
} else if (zend_string_equals_literal(lcname, "array_slice")) {
return zend_compile_func_array_slice(result, args);
} else if (zend_string_equals_literal(lcname, "array_key_exists")) {
return zend_compile_func_array_key_exists(result, args);
2014-07-22 21:27:00 +00:00
} else {
return FAILURE;
2012-12-25 06:23:08 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *name_ast = ast->child[0];
2014-07-13 11:11:55 +00:00
zend_ast *args_ast = ast->child[1];
2014-06-07 11:06:53 +00:00
znode name_node;
if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&name_node, name_ast);
zend_compile_dynamic_call(result, &name_node, args_ast);
2014-06-07 11:06:53 +00:00
return;
}
2014-06-07 11:06:53 +00:00
{
bool runtime_resolution = zend_compile_function_name(&name_node, name_ast);
2014-07-28 20:03:16 +00:00
if (runtime_resolution) {
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
if (zend_string_equals_literal_ci(zend_ast_get_str(name_ast), "assert")) {
2015-03-04 02:55:14 +00:00
zend_compile_assert(result, zend_ast_get_list(args_ast), Z_STR(name_node.u.constant), NULL);
Improved assert() according to expectations RFC. See https://wiki.php.net/rfc/expectations Squashed commit of the following: commit 3f3651a7870738e35ec541e53b53069152135b24 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 11:56:33 2015 +0300 opcode 137 is used for ZEND_OP_DATA and con't be reused for ZEND_ASSERT_CHECK commit ca8ecabf2a5f97f9116839c33396c9a7037e4368 Merge: 24328ac 9dac923 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Mar 2 10:49:23 2015 +0300 Merge branch 'master' into assert * master: Update NEWS Fixed bug #69139 (Crash in gc_zval_possible_root on unserialize) windows only test Align entries format Align entries format for 5.6.7 Align entries format for 5.5.23 Bump header year Fixed bug #69144 (strtr not replacing with partly matching replace pairs) Fixed test? Revert mktime()/gmmktime()'s arginfo Update NEWS Fixed bug #69141 Missing arguments in reflection info for some builtin functions Add NEWS entry Remove useless date warning Fix ARG_INFO for levenshtein Fix ARG_INFO for levenshtein fix dir separator in tests Update NEWS Fixed bug #69085 (SoapClient's __call() type confusion through unserialize()). commit 24328ac03f79a0f3b19be7411bf9e173f392abda Merge: 021fd94 1cdee9a Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Feb 27 15:57:13 2015 +0300 Merge branch 'master' into assert * master: Fixed C++ support Fixed bug #69115 crash in mail Reorder Update NEWs Fixed bug #69121 (Segfault in get_current_user when script owner is not in passwd with ZTS build) Update News Fixed bug #69125 (Array numeric string as key) fix bug#68942's patch Fixed ability to build unspecialized executor Fixed bug #69124 (method name could not be used when by ref) Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). commit 021fd94ed1d692d212e6e30c6c1a9767c3f16f7f Merge: 49963eb ace1f82 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 26 11:26:03 2015 +0300 Merge branch 'master' into assert * master: (59 commits) Improved ASSIGN_DIM handler Don't inline slow path Revert a part committted by mistake Fixed compilation warnings Fixed a bug that header value is not terminated by '\0' when accessed through getenv(). better name Improve fix for #69038 Update NEWs Fixed bug #69108 ("Segmentation fault" when (de)serializing SplObjectStorage) Added specialized versions of DO_FCALL handler: DO_ICALL - for internal functions DO_UCALL - for user functions DO_FCALL_BY_NAME - plain, most probably user, funcstions (not methods) Use cache_slot offsets instead of indexes (simplify run-time instructions) Split INIT_FCALL_BY_NAME inti INIT_FCALL_BY_NAME(CONST+STRING) and INIT_DYNAMIC_CALL(CONST-STRING|TMPVAR|CV) Support list($a, $b) = $a Avoid unnecassary check Make zend_array_destroy() to free the corresponding zend_array Eliminate check on the fast path Make current() and key() receive argument by value. Use Firebird default home folder, replace Interbase with Firebird Updated NEWS updated NEWS ... Conflicts: Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h commit 49963ebf9d2bcd6d2670203dd72884f6ba6c8a4b Merge: 07b1f92 6b77959 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Feb 19 11:13:08 2015 +0300 Merge branch 'master' into assert * master: Implemented AST pretty-printer update NEWS to match the actual stuff in 5.6.6 update NEWS to match the actual stuff in 5.5.22 update NEWS(add missing entry for the enchant fix, and reorder the entries a bit) fix typo in bug# update NEWS fix email format update NEWS update 5.6.6 release date in NEWS Fix bug #69033 (Request may get env. variables from previous requests if PHP works as FastCGI) BFN fix test fix test fix test Fixed bug #65593 (Segfault when calling ob_start from output buffering callback) Updated NEWS add CVE 5.4.39 next Fix associativity to match Perl Blast off to space. Conflicts: Zend/zend_ast.c commit 07b1f92ed662f6fa9309e679b83aff328362c98b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 23:06:32 2015 +0300 fixed pretty-printer (support for "elseif") commit 5a976c8d85078502b48379996ab066e57533a0c3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 19:50:08 2015 +0300 Fixed vaeious ptetty-printer issues commit 69491e8e8e692030b0585aab485146906c0fedaf Merge: 8473157 3ddc246 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:18:32 2015 +0300 Merge branch 'master' into assert * master: Set PHP_JSON_VERSION to 1.4.0 Remove unnecessary resource checks in openssl ext JSON is now maintained commit 8473157fbb12d03fff8d5b602865a4b667522a4d Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 10:17:26 2015 +0300 Fixed typo and white spaces commit 96de5ffc8d604df9797d0141ae5ad9c15e1d6c32 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Feb 18 00:28:39 2015 +0300 Fixed assert() in namesapaces commit 5eba069c28e7b6590618707e0b21cdb2dd62a192 Merge: 4a2d9c0 d428bf2 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:55 2015 +0300 Merge branch 'master' into assert * master: (25 commits) improve debugability in TS debug builds More UPGRADING, in particular on foreach Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) for master Replace var is introduced abstain from using xmlCleanupParser fix TS build Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) update news Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Port for for bug #68552 Fix bug #68942 (Use after free vulnerability in unserialize() with DateTimeZone) Update NEWS Fixed bug #69038 (switch(SOMECONSTANT) misbehaves) - BFN Don't read the local php.ini when Generating Phar When building phar shared, you can end up loading a previous phar.so that isn't compatible with the php cli being used to generate Phar here. - Fixed bug #67827 (broken detection of system crypt sha256/sha512 support) Delete json outdated package.xml made ZEND_TSRMLS_CACHE_* macros look like function calls - Fix merge - Fixed bug #67427 (SoapServer cannot handle large messages) patch by: brandt at docoloc dot de ... commit 4a2d9c0953dccd9e78ebee9291e1213419eb9136 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue Feb 17 22:45:10 2015 +0300 Implemented AST pretty-printer to capture expression passed to assert() commit 7a059b66d51a65159801bd826346721325b89fec Merge: 9973df7 3892eba Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Feb 16 18:42:28 2015 +0300 Merge branch 'expect' of github.com:krakjoe/php-src into assert * 'expect' of github.com:krakjoe/php-src: import expect Conflicts: Zend/zend_compile.c Zend/zend_execute_API.c Zend/zend_globals.h Zend/zend_vm_def.h Zend/zend_vm_execute.h Zend/zend_vm_opcodes.c Zend/zend_vm_opcodes.h ext/opcache/Optimizer/block_pass.c ext/opcache/Optimizer/pass1_5.c ext/standard/assert.c ext/standard/tests/assert/assert_error3.phpt commit 3892eba2bf56a7699453855c995404106322718d Author: krakjoe <joe.watkins@live.co.uk> Date: Sun Feb 2 12:49:35 2014 +0000 import expect
2015-03-02 09:25:40 +00:00
} else {
zend_compile_ns_call(result, &name_node, args_ast);
}
2014-06-07 11:06:53 +00:00
return;
}
}
2014-06-07 11:06:53 +00:00
{
zval *name = &name_node.u.constant;
zend_string *lcname;
2014-06-07 11:06:53 +00:00
zend_function *fbc;
zend_op *opline;
2012-12-25 06:23:08 +00:00
lcname = zend_string_tolower(Z_STR_P(name));
fbc = zend_hash_find_ptr(CG(function_table), lcname);
/* Special assert() handling should apply independently of compiler flags. */
if (fbc && zend_string_equals_literal(lcname, "assert")) {
zend_compile_assert(result, zend_ast_get_list(args_ast), lcname, fbc);
zend_string_release(lcname);
zval_ptr_dtor(&name_node.u.constant);
return;
}
if (!fbc || !fbc_is_finalized(fbc)
|| (fbc->type == ZEND_INTERNAL_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS))
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_USER_FUNCTIONS))
|| (fbc->type == ZEND_USER_FUNCTION && (CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) && fbc->op_array.filename != CG(active_op_array)->filename)
) {
zend_string_release_ex(lcname, 0);
2014-12-13 22:06:14 +00:00
zend_compile_dynamic_call(result, &name_node, args_ast);
2014-07-22 21:11:12 +00:00
return;
2014-07-22 20:57:38 +00:00
}
2011-01-19 17:17:52 +00:00
if (zend_try_compile_special_func(result, lcname,
zend_ast_get_list(args_ast), fbc, type) == SUCCESS
) {
zend_string_release_ex(lcname, 0);
zval_ptr_dtor(&name_node.u.constant);
2014-06-07 11:06:53 +00:00
return;
}
2014-06-07 11:06:53 +00:00
zval_ptr_dtor(&name_node.u.constant);
ZVAL_NEW_STR(&name_node.u.constant, lcname);
2011-01-19 17:17:52 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, &name_node);
opline->result.num = zend_alloc_cache_slot();
2014-12-13 22:06:14 +00:00
zend_compile_call_common(result, args_ast, fbc);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *obj_ast = ast->child[0];
zend_ast *method_ast = ast->child[1];
2014-07-13 11:11:55 +00:00
zend_ast *args_ast = ast->child[2];
znode obj_node, method_node;
zend_op *opline;
zend_function *fbc = NULL;
bool nullsafe = ast->kind == ZEND_AST_NULLSAFE_METHOD_CALL;
if (is_this_fetch(obj_ast)) {
if (this_guaranteed_exists()) {
obj_node.op_type = IS_UNUSED;
} else {
zend_emit_op(&obj_node, ZEND_FETCH_THIS, NULL, NULL);
}
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
2020-08-11 13:22:14 +00:00
/* We will throw if $this doesn't exist, so there's no need to emit a JMP_NULL
* check for a nullsafe access. */
} else {
zend_short_circuiting_mark_inner(obj_ast);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&obj_node, obj_ast);
2020-08-11 13:22:14 +00:00
if (nullsafe) {
zend_emit_jmp_null(&obj_node);
}
}
2014-12-13 22:06:14 +00:00
zend_compile_expr(&method_node, method_ast);
opline = zend_emit_op(NULL, ZEND_INIT_METHOD_CALL, &obj_node, NULL);
2015-01-03 09:22:58 +00:00
if (method_node.op_type == IS_CONST) {
if (Z_TYPE(method_node.u.constant) != IS_STRING) {
2014-06-07 11:06:53 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
}
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(
2014-12-13 22:06:14 +00:00
Z_STR(method_node.u.constant));
opline->result.num = zend_alloc_cache_slots(2);
} else {
SET_NODE(opline->op2, &method_node);
}
/* Check if this calls a known method on $this */
if (opline->op1_type == IS_UNUSED && opline->op2_type == IS_CONST &&
CG(active_class_entry) && zend_is_scope_known()) {
zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op2) + 1);
fbc = zend_hash_find_ptr(&CG(active_class_entry)->function_table, lcname);
/* We only know the exact method that is being called if it is either private or final.
* Otherwise an overriding method in a child class may be called. */
if (fbc && !(fbc->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_FINAL))) {
fbc = NULL;
}
}
zend_compile_call_common(result, args_ast, fbc);
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
static bool zend_is_constructor(zend_string *name) /* {{{ */
2014-08-29 05:05:58 +00:00
{
return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2019-03-06 09:42:02 +00:00
static zend_function *zend_get_compatible_func_or_null(zend_class_entry *ce, zend_string *lcname) /* {{{ */
{
zend_function *fbc = zend_hash_find_ptr(&ce->function_table, lcname);
if (!fbc || (fbc->common.fn_flags & ZEND_ACC_PUBLIC) || ce == CG(active_class_entry)) {
return fbc;
}
if (!(fbc->common.fn_flags & ZEND_ACC_PRIVATE)
&& (fbc->common.scope->ce_flags & ZEND_ACC_LINKED)
&& (!CG(active_class_entry) || (CG(active_class_entry)->ce_flags & ZEND_ACC_LINKED))
&& zend_check_protected(zend_get_function_root_class(fbc), CG(active_class_entry))) {
return fbc;
}
return NULL;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *class_ast = ast->child[0];
zend_ast *method_ast = ast->child[1];
2014-07-13 11:11:55 +00:00
zend_ast *args_ast = ast->child[2];
znode class_node, method_node;
2014-06-07 11:06:53 +00:00
zend_op *opline;
zend_function *fbc = NULL;
zend_short_circuiting_mark_inner(class_ast);
zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&method_node, method_ast);
2014-06-07 11:06:53 +00:00
if (method_node.op_type == IS_CONST) {
zval *name = &method_node.u.constant;
if (Z_TYPE_P(name) != IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Method name must be a string");
}
if (zend_is_constructor(Z_STR_P(name))) {
zval_ptr_dtor(name);
method_node.op_type = IS_UNUSED;
}
}
opline = get_next_op();
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_INIT_STATIC_METHOD_CALL;
2014-12-13 22:06:14 +00:00
zend_set_class_name_op1(opline, &class_node);
2014-06-07 11:06:53 +00:00
if (method_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_func_name_literal(
2014-12-13 22:06:14 +00:00
Z_STR(method_node.u.constant));
opline->result.num = zend_alloc_cache_slots(2);
} else {
2014-06-07 11:06:53 +00:00
if (opline->op1_type == IS_CONST) {
opline->result.num = zend_alloc_cache_slot();
}
2014-06-07 11:06:53 +00:00
SET_NODE(opline->op2, &method_node);
}
2014-06-07 11:06:53 +00:00
/* Check if we already know which method we're calling */
if (opline->op2_type == IS_CONST) {
zend_class_entry *ce = NULL;
if (opline->op1_type == IS_CONST) {
zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op1) + 1);
ce = zend_hash_find_ptr(CG(class_table), lcname);
if (!ce && CG(active_class_entry)
&& zend_string_equals_ci(CG(active_class_entry)->name, lcname)) {
ce = CG(active_class_entry);
}
} else if (opline->op1_type == IS_UNUSED
&& (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
&& zend_is_scope_known()) {
ce = CG(active_class_entry);
}
if (ce) {
zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op2) + 1);
2019-03-06 09:42:02 +00:00
fbc = zend_get_compatible_func_or_null(ce, lcname);
}
}
zend_compile_call_common(result, args_ast, fbc);
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel);
void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *class_ast = ast->child[0];
2014-07-13 11:11:55 +00:00
zend_ast *args_ast = ast->child[1];
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
znode class_node, ctor_result;
zend_op *opline;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (class_ast->kind == ZEND_AST_CLASS) {
/* anon class declaration */
zend_compile_class_decl(&class_node, class_ast, 0);
2015-04-26 13:17:53 +00:00
} else {
zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(result, ZEND_NEW, NULL, NULL);
if (class_node.op_type == IS_CONST) {
opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_class_name_literal(
Z_STR(class_node.u.constant));
opline->op2.num = zend_alloc_cache_slot();
} else {
SET_NODE(opline->op1, &class_node);
}
2014-12-13 22:06:14 +00:00
zend_compile_call_common(&ctor_result, args_ast, NULL);
zend_do_free(&ctor_result);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_clone(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *obj_ast = ast->child[0];
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
znode obj_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&obj_node, obj_ast);
zend_emit_op_tmp(result, ZEND_CLONE, &obj_node, NULL);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_global_var(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *var_ast = ast->child[0];
2014-07-22 18:24:47 +00:00
zend_ast *name_ast = var_ast->child[0];
2014-06-07 11:06:53 +00:00
2014-07-22 18:24:47 +00:00
znode name_node, result;
2014-06-07 11:06:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&name_node, name_ast);
2014-07-22 18:24:47 +00:00
if (name_node.op_type == IS_CONST) {
2014-11-10 15:41:55 +00:00
convert_to_string(&name_node.u.constant);
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
// TODO(GLOBALS) Forbid "global $GLOBALS"?
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (is_this_fetch(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as global variable");
} else if (zend_try_compile_cv(&result, var_ast) == SUCCESS) {
2014-12-13 22:06:14 +00:00
zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node);
opline->extended_value = zend_alloc_cache_slot();
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
} else {
/* name_ast should be evaluated only. FETCH_GLOBAL_LOCK instructs FETCH_W
* to not free the name_node operand, so it can be reused in the following
* ASSIGN_REF, which then frees it. */
zend_op *opline = zend_emit_op(&result, ZEND_FETCH_W, &name_node, NULL);
opline->extended_value = ZEND_FETCH_GLOBAL_LOCK;
2016-03-22 21:46:48 +00:00
if (name_node.op_type == IS_CONST) {
zend_string_addref(Z_STR(name_node.u.constant));
}
zend_emit_assign_ref_znode(
zend_ast_create(ZEND_AST_VAR, zend_ast_create_znode(&name_node)),
&result
);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
static void zend_compile_static_var_common(zend_string *var_name, zval *value, uint32_t mode) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline;
if (!CG(active_op_array)->static_variables) {
if (CG(active_op_array)->scope) {
CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
}
CG(active_op_array)->static_variables = zend_new_array(8);
}
value = zend_hash_update(CG(active_op_array)->static_variables, var_name, value);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (zend_string_equals_literal(var_name, "this")) {
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
}
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, NULL);
opline->op1_type = IS_CV;
opline->op1.var = lookup_cv(var_name);
opline->extended_value = (uint32_t)((char*)value - (char*)CG(active_op_array)->static_variables->arData) | mode;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_static_var(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-18 10:30:39 +00:00
zend_ast *var_ast = ast->child[0];
zend_ast **value_ast_ptr = &ast->child[1];
2014-07-18 10:30:39 +00:00
zval value_zv;
if (*value_ast_ptr) {
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
} else {
2014-07-18 10:30:39 +00:00
ZVAL_NULL(&value_zv);
}
2014-07-18 10:30:39 +00:00
zend_compile_static_var_common(zend_ast_get_str(var_ast), &value_zv, ZEND_BIND_REF);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_unset(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-07 11:06:53 +00:00
zend_ast *var_ast = ast->child[0];
znode var_node;
zend_op *opline;
zend_ensure_writable_variable(var_ast);
if (is_global_var_fetch(var_ast)) {
if (!var_ast->child[1]) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for unsetting");
}
zend_compile_expr(&var_node, var_ast->child[1]);
if (var_node.op_type == IS_CONST) {
convert_to_string(&var_node.u.constant);
}
opline = zend_emit_op(NULL, ZEND_UNSET_VAR, &var_node, NULL);
opline->extended_value = ZEND_FETCH_GLOBAL;
return;
}
2014-06-07 11:06:53 +00:00
switch (var_ast->kind) {
case ZEND_AST_VAR:
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (is_this_fetch(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot unset $this");
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
opline = zend_emit_op(NULL, ZEND_UNSET_CV, &var_node, NULL);
2014-06-07 11:06:53 +00:00
} else {
2015-02-02 17:44:16 +00:00
opline = zend_compile_simple_var_no_cv(NULL, var_ast, BP_VAR_UNSET, 0);
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_UNSET_VAR;
}
return;
case ZEND_AST_DIM:
opline = zend_compile_dim(NULL, var_ast, BP_VAR_UNSET);
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_UNSET_DIM;
return;
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
opline = zend_compile_prop(NULL, var_ast, BP_VAR_UNSET, 0);
2014-06-07 11:06:53 +00:00
opline->opcode = ZEND_UNSET_OBJ;
return;
2014-06-19 11:57:29 +00:00
case ZEND_AST_STATIC_PROP:
opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_UNSET, 0, 0);
opline->opcode = ZEND_UNSET_STATIC_PROP;
2014-06-19 11:57:29 +00:00
return;
2014-06-07 11:06:53 +00:00
EMPTY_SWITCH_DEFAULT_CASE()
}
2014-06-07 11:06:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-07 11:06:53 +00:00
static bool zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_loop_var *base;
2015-07-10 11:30:25 +00:00
zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
if (!loop_var) {
return 1;
}
base = zend_stack_base(&CG(loop_var_stack));
for (; loop_var >= base; loop_var--) {
if (loop_var->opcode == ZEND_FAST_CALL) {
zend_op *opline = get_next_op();
opline->opcode = ZEND_FAST_CALL;
opline->result_type = IS_TMP_VAR;
opline->result.var = loop_var->var_num;
if (return_value) {
SET_NODE(opline->op2, return_value);
}
opline->op1.num = loop_var->try_catch_offset;
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
} else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) {
zend_op *opline = get_next_op();
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
opline->opcode = ZEND_DISCARD_EXCEPTION;
opline->op1_type = IS_TMP_VAR;
opline->op1.var = loop_var->var_num;
} else if (loop_var->opcode == ZEND_RETURN) {
/* Stack separator */
break;
} else if (depth <= 1) {
return 1;
} else if (loop_var->opcode == ZEND_NOP) {
/* Loop doesn't have freeable variable */
depth--;
} else {
zend_op *opline;
2016-02-11 20:11:19 +00:00
ZEND_ASSERT(loop_var->var_type & (IS_VAR|IS_TMP_VAR));
opline = get_next_op();
opline->opcode = loop_var->opcode;
opline->op1_type = loop_var->var_type;
opline->op1.var = loop_var->var_num;
opline->extended_value = ZEND_FREE_ON_RETURN;
depth--;
}
}
return (depth == 0);
}
/* }}} */
static bool zend_handle_loops_and_finally(znode *return_value) /* {{{ */
{
return zend_handle_loops_and_finally_ex(zend_stack_count(&CG(loop_var_stack)) + 1, return_value);
}
2014-08-29 05:05:58 +00:00
/* }}} */
static bool zend_has_finally_ex(zend_long depth) /* {{{ */
{
zend_loop_var *base;
zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
if (!loop_var) {
return 0;
}
base = zend_stack_base(&CG(loop_var_stack));
for (; loop_var >= base; loop_var--) {
if (loop_var->opcode == ZEND_FAST_CALL) {
return 1;
} else if (loop_var->opcode == ZEND_DISCARD_EXCEPTION) {
} else if (loop_var->opcode == ZEND_RETURN) {
/* Stack separator */
return 0;
} else if (depth <= 1) {
return 0;
} else {
depth--;
}
}
return 0;
}
/* }}} */
static bool zend_has_finally(void) /* {{{ */
{
return zend_has_finally_ex(zend_stack_count(&CG(loop_var_stack)) + 1);
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_return(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-07 19:06:02 +00:00
zend_ast *expr_ast = ast->child[0];
bool is_generator = (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0;
bool by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2014-07-07 19:06:02 +00:00
znode expr_node;
zend_op *opline;
2016-07-14 13:44:04 +00:00
if (is_generator) {
/* For generators the by-ref flag refers to yields, not returns */
by_ref = 0;
}
2014-07-07 19:06:02 +00:00
if (!expr_ast) {
expr_node.op_type = IS_CONST;
ZVAL_NULL(&expr_node.u.constant);
} else if (by_ref && zend_is_variable(expr_ast)) {
if (zend_ast_is_short_circuited(expr_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot take reference of a nullsafe chain");
}
zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
}
if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)
&& (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR))
&& zend_has_finally()) {
/* Copy return value into temporary VAR to avoid modification in finally code */
if (by_ref) {
zend_emit_op(&expr_node, ZEND_MAKE_REF, &expr_node, NULL);
} else {
zend_emit_op_tmp(&expr_node, ZEND_QM_ASSIGN, &expr_node, NULL);
}
}
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
/* Generator return types are handled separately */
if (!is_generator && (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
zend_emit_return_type_check(
expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1, 0);
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
}
zend_handle_loops_and_finally((expr_node.op_type & (IS_TMP_VAR | IS_VAR)) ? &expr_node : NULL);
2014-07-28 20:03:16 +00:00
opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
2014-12-13 22:06:14 +00:00
&expr_node, NULL);
2014-07-28 20:03:16 +00:00
2016-07-14 13:44:04 +00:00
if (by_ref && expr_ast) {
2014-07-07 19:06:02 +00:00
if (zend_is_call(expr_ast)) {
opline->extended_value = ZEND_RETURNS_FUNCTION;
} else if (!zend_is_variable(expr_ast) || zend_ast_is_short_circuited(expr_ast)) {
2014-07-07 19:06:02 +00:00
opline->extended_value = ZEND_RETURNS_VALUE;
}
}
2014-07-07 19:06:02 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_echo(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline;
2014-07-07 19:14:14 +00:00
zend_ast *expr_ast = ast->child[0];
2014-07-07 19:14:14 +00:00
znode expr_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
2002-09-24 19:32:01 +00:00
opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL);
opline->extended_value = 0;
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_throw(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-09 20:47:36 +00:00
zend_ast *expr_ast = ast->child[0];
2014-07-09 20:47:36 +00:00
znode expr_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
2003-01-28 11:34:24 +00:00
zend_op *opline = zend_emit_op(NULL, ZEND_THROW, &expr_node, NULL);
if (result) {
/* Mark this as an "expression throw" for opcache. */
opline->extended_value = ZEND_THROW_IS_EXPR;
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
}
2014-07-09 20:47:36 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_break_continue(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-09 21:05:21 +00:00
zend_ast *depth_ast = ast->child[0];
2014-07-09 21:05:21 +00:00
zend_op *opline;
zend_long depth;
ZEND_ASSERT(ast->kind == ZEND_AST_BREAK || ast->kind == ZEND_AST_CONTINUE);
2014-07-09 21:05:21 +00:00
if (depth_ast) {
zval *depth_zv;
2014-07-09 21:05:21 +00:00
if (depth_ast->kind != ZEND_AST_ZVAL) {
zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator with non-integer operand "
"is no longer supported", ast->kind == ZEND_AST_BREAK ? "break" : "continue");
2014-07-09 21:05:21 +00:00
}
depth_zv = zend_ast_get_zval(depth_ast);
if (Z_TYPE_P(depth_zv) != IS_LONG || Z_LVAL_P(depth_zv) < 1) {
zend_error_noreturn(E_COMPILE_ERROR, "'%s' operator accepts only positive integers",
ast->kind == ZEND_AST_BREAK ? "break" : "continue");
2014-07-09 21:05:21 +00:00
}
depth = Z_LVAL_P(depth_zv);
2014-07-09 21:05:21 +00:00
} else {
depth = 1;
}
if (CG(context).current_brk_cont == -1) {
zend_error_noreturn(E_COMPILE_ERROR, "'%s' not in the 'loop' or 'switch' context",
ast->kind == ZEND_AST_BREAK ? "break" : "continue");
} else {
if (!zend_handle_loops_and_finally_ex(depth, NULL)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot '%s' " ZEND_LONG_FMT " level%s",
ast->kind == ZEND_AST_BREAK ? "break" : "continue",
depth, depth == 1 ? "" : "s");
}
}
if (ast->kind == ZEND_AST_CONTINUE) {
int d, cur = CG(context).current_brk_cont;
for (d = depth - 1; d > 0; d--) {
cur = CG(context).brk_cont_array[cur].parent;
ZEND_ASSERT(cur != -1);
}
if (CG(context).brk_cont_array[cur].is_switch) {
if (depth == 1) {
if (CG(context).brk_cont_array[cur].parent == -1) {
zend_error(E_WARNING,
"\"continue\" targeting switch is equivalent to \"break\"");
} else {
zend_error(E_WARNING,
"\"continue\" targeting switch is equivalent to \"break\". " \
"Did you mean to use \"continue " ZEND_LONG_FMT "\"?",
depth + 1);
}
} else {
if (CG(context).brk_cont_array[cur].parent == -1) {
zend_error(E_WARNING,
"\"continue " ZEND_LONG_FMT "\" targeting switch is equivalent to \"break " ZEND_LONG_FMT "\"",
depth, depth);
} else {
zend_error(E_WARNING,
"\"continue " ZEND_LONG_FMT "\" targeting switch is equivalent to \"break " ZEND_LONG_FMT "\". " \
"Did you mean to use \"continue " ZEND_LONG_FMT "\"?",
depth, depth, depth + 1);
}
}
}
}
opline = zend_emit_op(NULL, ast->kind == ZEND_AST_BREAK ? ZEND_BRK : ZEND_CONT, NULL, NULL);
opline->op1.num = CG(context).current_brk_cont;
opline->op2.num = depth;
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline) /* {{{ */
{
zend_label *dest;
2015-07-10 11:30:25 +00:00
int current, remove_oplines = opline->op1.num;
zval *label;
2015-07-10 11:30:25 +00:00
uint32_t opnum = opline - op_array->opcodes;
2015-07-10 11:30:25 +00:00
label = CT_CONSTANT_EX(op_array, opline->op2.constant);
if (CG(context).labels == NULL ||
2015-07-10 11:30:25 +00:00
(dest = zend_hash_find_ptr(CG(context).labels, Z_STR_P(label))) == NULL
) {
CG(in_compilation) = 1;
CG(active_op_array) = op_array;
CG(zend_lineno) = opline->lineno;
zend_error_noreturn(E_COMPILE_ERROR, "'goto' to undefined label '%s'", Z_STRVAL_P(label));
}
zval_ptr_dtor_str(label);
ZVAL_NULL(label);
2015-07-10 11:30:25 +00:00
current = opline->extended_value;
for (; current != dest->brk_cont; current = CG(context).brk_cont_array[current].parent) {
if (current == -1) {
2015-07-10 11:30:25 +00:00
CG(in_compilation) = 1;
CG(active_op_array) = op_array;
CG(zend_lineno) = opline->lineno;
zend_error_noreturn(E_COMPILE_ERROR, "'goto' into loop or switch statement is disallowed");
}
if (CG(context).brk_cont_array[current].start >= 0) {
2015-07-10 11:30:25 +00:00
remove_oplines--;
}
2015-07-10 11:30:25 +00:00
}
for (current = 0; current < op_array->last_try_catch; ++current) {
zend_try_catch_element *elem = &op_array->try_catch_array[current];
if (elem->try_op > opnum) {
break;
}
2015-07-10 11:30:25 +00:00
if (elem->finally_op && opnum < elem->finally_op - 1
&& (dest->opline_num > elem->finally_end || dest->opline_num < elem->try_op)
) {
remove_oplines--;
}
}
opline->opcode = ZEND_JMP;
opline->op1.opline_num = dest->opline_num;
opline->extended_value = 0;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
SET_UNUSED(opline->result);
ZEND_ASSERT(remove_oplines >= 0);
while (remove_oplines--) {
opline--;
MAKE_NOP(opline);
ZEND_VM_SET_OPCODE_HANDLER(opline);
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_goto(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-09 21:11:32 +00:00
zend_ast *label_ast = ast->child[0];
znode label_node;
2015-07-10 11:30:25 +00:00
zend_op *opline;
uint32_t opnum_start = get_next_op_number();
2014-07-09 21:11:32 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&label_node, label_ast);
2015-07-10 11:30:25 +00:00
/* Label resolution and unwinding adjustments happen in pass two. */
zend_handle_loops_and_finally(NULL);
2015-07-10 11:30:25 +00:00
opline = zend_emit_op(NULL, ZEND_GOTO, NULL, &label_node);
opline->op1.num = get_next_op_number() - opnum_start - 1;
2015-07-10 11:30:25 +00:00
opline->extended_value = CG(context).current_brk_cont;
2014-07-09 21:11:32 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-09 21:11:32 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_label(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_string *label = zend_ast_get_str(ast->child[0]);
2014-07-09 21:46:22 +00:00
zend_label dest;
if (!CG(context).labels) {
ALLOC_HASHTABLE(CG(context).labels);
2015-08-12 03:15:09 +00:00
zend_hash_init(CG(context).labels, 8, NULL, label_ptr_dtor, 0);
2014-07-09 21:46:22 +00:00
}
dest.brk_cont = CG(context).current_brk_cont;
dest.opline_num = get_next_op_number();
if (!zend_hash_add_mem(CG(context).labels, label, &dest, sizeof(zend_label))) {
zend_error_noreturn(E_COMPILE_ERROR, "Label '%s' already defined", ZSTR_VAL(label));
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_while(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *cond_ast = ast->child[0];
zend_ast *stmt_ast = ast->child[1];
znode cond_node;
uint32_t opnum_start, opnum_jmp, opnum_cond;
opnum_jmp = zend_emit_jump(0);
1999-04-07 18:10:10 +00:00
zend_begin_loop(ZEND_NOP, NULL, 0);
1999-04-07 18:10:10 +00:00
opnum_start = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
1999-04-07 18:10:10 +00:00
opnum_cond = get_next_op_number();
zend_update_jump_target(opnum_jmp, opnum_cond);
zend_compile_expr(&cond_node, cond_ast);
zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start);
1999-04-07 18:10:10 +00:00
zend_end_loop(opnum_cond, NULL);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_do_while(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-10 12:46:22 +00:00
zend_ast *stmt_ast = ast->child[0];
zend_ast *cond_ast = ast->child[1];
1999-04-07 18:10:10 +00:00
2014-07-10 12:46:22 +00:00
znode cond_node;
uint32_t opnum_start, opnum_cond;
zend_begin_loop(ZEND_NOP, NULL, 0);
1999-04-07 18:10:10 +00:00
opnum_start = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
1999-04-07 18:10:10 +00:00
opnum_cond = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_compile_expr(&cond_node, cond_ast);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start);
1999-04-07 18:10:10 +00:00
zend_end_loop(opnum_cond, NULL);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_expr_list(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list;
uint32_t i;
1999-04-07 18:10:10 +00:00
2014-07-19 11:21:12 +00:00
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
1999-04-07 18:10:10 +00:00
2014-07-19 11:21:12 +00:00
if (!ast) {
return;
}
1999-04-07 18:10:10 +00:00
list = zend_ast_get_list(ast);
for (i = 0; i < list->children; ++i) {
zend_ast *expr_ast = list->child[i];
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_do_free(result);
zend_compile_expr(result, expr_ast);
2014-07-10 13:51:47 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_for(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-10 13:51:47 +00:00
zend_ast *init_ast = ast->child[0];
zend_ast *cond_ast = ast->child[1];
zend_ast *loop_ast = ast->child[2];
zend_ast *stmt_ast = ast->child[3];
1999-04-07 18:10:10 +00:00
2014-07-10 13:51:47 +00:00
znode result;
2015-01-20 03:58:40 +00:00
uint32_t opnum_start, opnum_jmp, opnum_loop;
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr_list(&result, init_ast);
zend_do_free(&result);
opnum_jmp = zend_emit_jump(0);
2014-07-10 13:51:47 +00:00
zend_begin_loop(ZEND_NOP, NULL, 0);
2014-07-10 13:51:47 +00:00
opnum_start = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
1999-04-07 18:10:10 +00:00
opnum_loop = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_compile_expr_list(&result, loop_ast);
zend_do_free(&result);
1999-04-07 18:10:10 +00:00
zend_update_jump_target_to_next(opnum_jmp);
zend_compile_expr_list(&result, cond_ast);
zend_do_extended_stmt();
2014-07-10 13:51:47 +00:00
zend_emit_cond_jump(ZEND_JMPNZ, &result, opnum_start);
2014-07-10 13:51:47 +00:00
zend_end_loop(opnum_loop, NULL);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_foreach(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-11 10:16:21 +00:00
zend_ast *expr_ast = ast->child[0];
zend_ast *value_ast = ast->child[1];
zend_ast *key_ast = ast->child[2];
zend_ast *stmt_ast = ast->child[3];
bool by_ref = value_ast->kind == ZEND_AST_REF;
bool is_variable = zend_is_variable(expr_ast) && zend_can_write_to_variable(expr_ast);
2014-07-11 10:16:21 +00:00
znode expr_node, reset_node, value_node, key_node;
1999-04-07 18:10:10 +00:00
zend_op *opline;
uint32_t opnum_reset, opnum_fetch;
1999-04-07 18:10:10 +00:00
2014-07-11 10:16:21 +00:00
if (key_ast) {
if (key_ast->kind == ZEND_AST_REF) {
zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference");
}
if (key_ast->kind == ZEND_AST_ARRAY) {
2014-07-11 10:16:21 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element");
}
}
2014-07-11 10:16:21 +00:00
if (by_ref) {
value_ast = value_ast->child[0];
}
2011-01-19 17:17:52 +00:00
if (value_ast->kind == ZEND_AST_ARRAY && zend_propagate_list_refs(value_ast)) {
by_ref = 1;
}
2014-07-11 10:16:21 +00:00
if (by_ref && is_variable) {
zend_compile_var(&expr_node, expr_ast, BP_VAR_W, 1);
2014-07-11 10:16:21 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
1999-04-07 18:10:10 +00:00
}
if (by_ref) {
2014-12-13 22:06:14 +00:00
zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W);
}
opnum_reset = get_next_op_number();
Fix "forech" statemt behaviour according to https://wiki.php.net/rfc/php7_foreach Squashed commit of the following: commit 1e41295097576dbce6c197ddb7507c07ccae3cbe Author: Dmitry Stogov <dmitry@zend.com> Date: Sat Jan 31 07:28:58 2015 +0300 Generalize HashTableIterator API to allows its usage without involvement of HashTable.nInternalPonter commit 5406f21b11e563069d64045e599693b51c444b63 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:43 2015 +0300 Reduced alghorithms complexity commit b37f1d58d2a141b6e1d980a461ccb588d4317d2e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:30 2015 +0300 Fixed test name commit fb2d079645829b12ed4e55a461034df6400bc430 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 18:08:05 2015 +0300 API cleanup commit 08302c0d6d1cab279b9f2129df03a057baddf2ff Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 14:20:46 2015 +0300 Make array_splice() to preserve foreach hash position commit cc4b7be41e2e2b9b0d7a3c8e98466b8886692e6e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 12:24:31 2015 +0300 Make internal function, operation on array passed by reference, to preserve foreach hash position commit 5aa9712b0a30303aadfe3bdd8ae1f072ca3e6ba1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 09:49:35 2015 +0300 Implement consistent behavior for foreach by value over plain object commit 4c5b385ff53ae9f0b52572e98c4db801f56603b0 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jan 30 07:56:37 2015 +0300 More careful iterators update. commit 721fc9e80d2ee8f2cd79c8c3cdceffae2c72de92 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:43:28 2015 +0300 Added new test commit 15a23b1218b3e38630d677751a975907daa2cd54 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:05:02 2015 +0300 Reimplement iteration magic with HashTableIterators (see https://wiki.php.net/rfc/php7_foreach#implementation_details) commit 10a3260b1f16b6075fd8140f673dfef4d5efea91 Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jan 29 21:04:44 2015 +0300 New test commit eef80c583762d1e98d177cdbb27e3a8a6b0c4539 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 16:52:21 2015 +0300 Fixed foreach by reference iteration over constant array commit 61e739187391661e2d541947bec25d7dcc4479f3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 14:59:54 2015 +0300 Fixed temporary variable re-allocation pass commit 92e90c09f085c22707ff4a59201f016f56e0ef8b Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 12:44:57 2015 +0300 Fixed operand destruction in case of exceptions in iterator commit dd2a36a2074bbb0cb31de00b66dcf2812d6d753f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 10:02:34 2015 +0300 Use GET_OP1_ZVAL_PTR_DEREF() (IS_TMP_VAR and IS_CONST can't be IS_REFERENCE) commit 4638f7b91407c48710007af82a68da0007c820f2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jan 28 07:43:28 2015 +0300 Change "foreach" statement behavior (this is just a PoC yet) - "foreach by value" don't relay on internal array/object pointer and doesnt perform array duplication. It just locks it incrementing reference counter. If the original array is modified by some code, the copy on write is performed and "foreach" still work with the old copy. - it makes no difference if array given to "foreach by value" is reference itself - "foreach by reference" still use internal array/object pointer and should work similar to PHP-5. (This id not completely implemented)
2015-02-12 10:57:12 +00:00
opline = zend_emit_op(&reset_node, by_ref ? ZEND_FE_RESET_RW : ZEND_FE_RESET_R, &expr_node, NULL);
1999-04-07 18:10:10 +00:00
zend_begin_loop(ZEND_FE_FREE, &reset_node, 0);
opnum_fetch = get_next_op_number();
opline = zend_emit_op(NULL, by_ref ? ZEND_FE_FETCH_RW : ZEND_FE_FETCH_R, &reset_node, NULL);
1999-04-07 18:10:10 +00:00
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (is_this_fetch(value_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
} else if (value_ast->kind == ZEND_AST_VAR &&
zend_try_compile_cv(&value_node, value_ast) == SUCCESS) {
SET_NODE(opline->op2, &value_node);
2014-07-11 10:16:21 +00:00
} else {
opline->op2_type = IS_VAR;
opline->op2.var = get_temporary_variable();
GET_NODE(&value_node, opline->op2);
if (value_ast->kind == ZEND_AST_ARRAY) {
zend_compile_list_assign(NULL, value_ast, &value_node, value_ast->attr);
} else if (by_ref) {
zend_emit_assign_ref_znode(value_ast, &value_node);
} else {
zend_emit_assign_znode(value_ast, &value_node);
}
2004-08-23 20:16:35 +00:00
}
2014-07-11 10:16:21 +00:00
if (key_ast) {
opline = &CG(active_op_array)->opcodes[opnum_fetch];
zend_make_tmp_result(&key_node, opline);
2014-12-13 22:06:14 +00:00
zend_emit_assign_znode(key_ast, &key_node);
1999-04-07 18:10:10 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
1999-04-07 18:10:10 +00:00
/* Place JMP and FE_FREE on the line where foreach starts. It would be
* better to use the end line, but this information is not available
* currently. */
CG(zend_lineno) = ast->lineno;
2014-12-13 22:06:14 +00:00
zend_emit_jump(opnum_fetch);
1999-04-07 18:10:10 +00:00
opline = &CG(active_op_array)->opcodes[opnum_reset];
opline->op2.opline_num = get_next_op_number();
2014-07-11 10:16:21 +00:00
opline = &CG(active_op_array)->opcodes[opnum_fetch];
opline->extended_value = get_next_op_number();
2014-07-11 10:16:21 +00:00
zend_end_loop(opnum_fetch, &reset_node);
2014-07-11 10:16:21 +00:00
opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_if(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
2014-11-27 09:52:31 +00:00
uint32_t *jmp_opnums = NULL;
2015-01-03 09:22:58 +00:00
if (list->children > 1) {
jmp_opnums = safe_emalloc(sizeof(uint32_t), list->children - 1, 0);
}
1999-04-07 18:10:10 +00:00
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
2014-07-10 14:38:04 +00:00
zend_ast *cond_ast = elem_ast->child[0];
zend_ast *stmt_ast = elem_ast->child[1];
2014-07-10 14:38:04 +00:00
if (cond_ast) {
znode cond_node;
uint32_t opnum_jmpz;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&cond_node, cond_ast);
opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
2014-07-10 14:38:04 +00:00
zend_compile_stmt(stmt_ast);
2014-07-10 14:38:04 +00:00
if (i != list->children - 1) {
jmp_opnums[i] = zend_emit_jump(0);
}
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_jmpz);
} else {
/* "else" can only occur as last element. */
ZEND_ASSERT(i == list->children - 1);
zend_compile_stmt(stmt_ast);
2014-07-10 14:38:04 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-07-10 14:38:04 +00:00
if (list->children > 1) {
for (i = 0; i < list->children - 1; ++i) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(jmp_opnums[i]);
}
efree(jmp_opnums);
2014-07-10 14:38:04 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2017-03-17 22:45:05 +00:00
static zend_uchar determine_switch_jumptable_type(zend_ast_list *cases) {
uint32_t i;
zend_uchar common_type = IS_UNDEF;
for (i = 0; i < cases->children; i++) {
zend_ast *case_ast = cases->child[i];
zend_ast **cond_ast = &case_ast->child[0];
zval *cond_zv;
if (!case_ast->child[0]) {
/* Skip default clause */
continue;
}
zend_eval_const_expr(cond_ast);
if ((*cond_ast)->kind != ZEND_AST_ZVAL) {
/* Non-constant case */
return IS_UNDEF;
}
cond_zv = zend_ast_get_zval(case_ast->child[0]);
if (Z_TYPE_P(cond_zv) != IS_LONG && Z_TYPE_P(cond_zv) != IS_STRING) {
/* We only optimize switched on integers and strings */
return IS_UNDEF;
}
if (common_type == IS_UNDEF) {
common_type = Z_TYPE_P(cond_zv);
} else if (common_type != Z_TYPE_P(cond_zv)) {
/* Non-uniform case types */
return IS_UNDEF;
}
if (Z_TYPE_P(cond_zv) == IS_STRING
&& is_numeric_string(Z_STRVAL_P(cond_zv), Z_STRLEN_P(cond_zv), NULL, NULL, 0)) {
/* Numeric strings cannot be compared with a simple hash lookup */
return IS_UNDEF;
}
}
return common_type;
}
static bool should_use_jumptable(zend_ast_list *cases, zend_uchar jumptable_type) {
if (CG(compiler_options) & ZEND_COMPILE_NO_JUMPTABLES) {
return 0;
}
2017-03-17 22:45:05 +00:00
/* Thresholds are chosen based on when the average switch time for equidistributed
* input becomes smaller when using the jumptable optimization. */
if (jumptable_type == IS_LONG) {
return cases->children >= 5;
} else {
ZEND_ASSERT(jumptable_type == IS_STRING);
return cases->children >= 2;
}
}
2014-12-13 22:06:14 +00:00
void zend_compile_switch(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-11 13:31:47 +00:00
zend_ast *expr_ast = ast->child[0];
zend_ast_list *cases = zend_ast_get_list(ast->child[1]);
uint32_t i;
bool has_default_case = 0;
2014-07-11 13:31:47 +00:00
znode expr_node, case_node;
zend_op *opline;
uint32_t *jmpnz_opnums, opnum_default_jmp, opnum_switch = (uint32_t)-1;
2017-03-17 22:45:05 +00:00
zend_uchar jumptable_type;
HashTable *jumptable = NULL;
2006-12-21 02:09:36 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
2003-02-10 16:11:24 +00:00
zend_begin_loop(ZEND_FREE, &expr_node, 1);
2007-09-28 19:52:53 +00:00
2014-07-11 13:31:47 +00:00
case_node.op_type = IS_TMP_VAR;
case_node.u.op.var = get_temporary_variable();
2007-09-28 19:52:53 +00:00
2017-03-17 22:45:05 +00:00
jumptable_type = determine_switch_jumptable_type(cases);
if (jumptable_type != IS_UNDEF && should_use_jumptable(cases, jumptable_type)) {
znode jumptable_op;
ALLOC_HASHTABLE(jumptable);
zend_hash_init(jumptable, cases->children, NULL, NULL, 0);
jumptable_op.op_type = IS_CONST;
ZVAL_ARR(&jumptable_op.u.constant, jumptable);
opline = zend_emit_op(NULL,
jumptable_type == IS_LONG ? ZEND_SWITCH_LONG : ZEND_SWITCH_STRING,
&expr_node, &jumptable_op);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
2017-03-17 22:45:05 +00:00
}
opnum_switch = opline - CG(active_op_array)->opcodes;
}
jmpnz_opnums = safe_emalloc(sizeof(uint32_t), cases->children, 0);
for (i = 0; i < cases->children; ++i) {
zend_ast *case_ast = cases->child[i];
2014-07-11 13:31:47 +00:00
zend_ast *cond_ast = case_ast->child[0];
znode cond_node;
2014-07-11 13:31:47 +00:00
if (!cond_ast) {
if (has_default_case) {
CG(zend_lineno) = case_ast->lineno;
zend_error_noreturn(E_COMPILE_ERROR,
"Switch statements may only contain one default clause");
}
2014-07-11 13:31:47 +00:00
has_default_case = 1;
continue;
}
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&cond_node, cond_ast);
1999-04-07 18:10:10 +00:00
if (expr_node.op_type == IS_CONST
&& Z_TYPE(expr_node.u.constant) == IS_FALSE) {
jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
} else if (expr_node.op_type == IS_CONST
&& Z_TYPE(expr_node.u.constant) == IS_TRUE) {
jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, 0);
} else {
opline = zend_emit_op(NULL,
(expr_node.op_type & (IS_VAR|IS_TMP_VAR)) ? ZEND_CASE : ZEND_IS_EQUAL,
&expr_node, &cond_node);
SET_NODE(opline->result, &case_node);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
2014-07-11 13:31:47 +00:00
jmpnz_opnums[i] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0);
}
}
2014-12-13 22:06:14 +00:00
opnum_default_jmp = zend_emit_jump(0);
for (i = 0; i < cases->children; ++i) {
zend_ast *case_ast = cases->child[i];
2014-07-11 13:31:47 +00:00
zend_ast *cond_ast = case_ast->child[0];
zend_ast *stmt_ast = case_ast->child[1];
2014-07-11 13:31:47 +00:00
if (cond_ast) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(jmpnz_opnums[i]);
2017-03-17 22:45:05 +00:00
if (jumptable) {
zval *cond_zv = zend_ast_get_zval(cond_ast);
zval jmp_target;
ZVAL_LONG(&jmp_target, get_next_op_number());
2017-03-17 22:45:05 +00:00
ZEND_ASSERT(Z_TYPE_P(cond_zv) == jumptable_type);
if (Z_TYPE_P(cond_zv) == IS_LONG) {
zend_hash_index_add(jumptable, Z_LVAL_P(cond_zv), &jmp_target);
} else {
ZEND_ASSERT(Z_TYPE_P(cond_zv) == IS_STRING);
zend_hash_add(jumptable, Z_STR_P(cond_zv), &jmp_target);
}
}
2014-07-11 13:31:47 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_default_jmp);
2017-03-17 22:45:05 +00:00
if (jumptable) {
ZEND_ASSERT(opnum_switch != (uint32_t)-1);
2017-03-17 22:45:05 +00:00
opline = &CG(active_op_array)->opcodes[opnum_switch];
opline->extended_value = get_next_op_number();
2017-03-17 22:45:05 +00:00
}
}
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
}
2014-07-11 13:31:47 +00:00
if (!has_default_case) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_default_jmp);
2017-03-17 22:45:05 +00:00
if (jumptable) {
opline = &CG(active_op_array)->opcodes[opnum_switch];
opline->extended_value = get_next_op_number();
2017-03-17 22:45:05 +00:00
}
2014-07-11 13:31:47 +00:00
}
2003-03-05 11:14:44 +00:00
zend_end_loop(get_next_op_number(), &expr_node);
2016-02-11 20:11:19 +00:00
if (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) {
opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
opline->extended_value = ZEND_FREE_SWITCH;
2014-07-11 13:31:47 +00:00
} else if (expr_node.op_type == IS_CONST) {
zval_ptr_dtor_nogc(&expr_node.u.constant);
}
2014-07-11 13:31:47 +00:00
2014-07-11 13:33:39 +00:00
efree(jmpnz_opnums);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static uint32_t count_match_conds(zend_ast_list *arms)
{
uint32_t num_conds = 0;
for (uint32_t i = 0; i < arms->children; i++) {
zend_ast *arm_ast = arms->child[i];
if (arm_ast->child[0] == NULL) {
continue;
}
zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
num_conds += conds->children;
}
return num_conds;
}
static bool can_match_use_jumptable(zend_ast_list *arms) {
for (uint32_t i = 0; i < arms->children; i++) {
zend_ast *arm_ast = arms->child[i];
if (!arm_ast->child[0]) {
/* Skip default arm */
continue;
}
zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
for (uint32_t j = 0; j < conds->children; j++) {
zend_ast **cond_ast = &conds->child[j];
zend_eval_const_expr(cond_ast);
if ((*cond_ast)->kind != ZEND_AST_ZVAL) {
return 0;
}
zval *cond_zv = zend_ast_get_zval(*cond_ast);
if (Z_TYPE_P(cond_zv) != IS_LONG && Z_TYPE_P(cond_zv) != IS_STRING) {
return 0;
}
}
}
return 1;
}
void zend_compile_match(znode *result, zend_ast *ast)
{
zend_ast *expr_ast = ast->child[0];
zend_ast_list *arms = zend_ast_get_list(ast->child[1]);
bool has_default_arm = 0;
uint32_t opnum_match = (uint32_t)-1;
znode expr_node;
zend_compile_expr(&expr_node, expr_ast);
znode case_node;
case_node.op_type = IS_TMP_VAR;
case_node.u.op.var = get_temporary_variable();
uint32_t num_conds = count_match_conds(arms);
zend_uchar can_use_jumptable = can_match_use_jumptable(arms);
bool uses_jumptable = can_use_jumptable && num_conds >= 2;
HashTable *jumptable = NULL;
uint32_t *jmpnz_opnums = NULL;
for (uint32_t i = 0; i < arms->children; ++i) {
zend_ast *arm_ast = arms->child[i];
if (!arm_ast->child[0]) {
if (has_default_arm) {
CG(zend_lineno) = arm_ast->lineno;
zend_error_noreturn(E_COMPILE_ERROR,
"Match expressions may only contain one default arm");
}
has_default_arm = 1;
}
}
if (uses_jumptable) {
znode jumptable_op;
ALLOC_HASHTABLE(jumptable);
zend_hash_init(jumptable, num_conds, NULL, NULL, 0);
jumptable_op.op_type = IS_CONST;
ZVAL_ARR(&jumptable_op.u.constant, jumptable);
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH, &expr_node, &jumptable_op);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
opnum_match = opline - CG(active_op_array)->opcodes;
} else {
jmpnz_opnums = safe_emalloc(sizeof(uint32_t), num_conds, 0);
uint32_t cond_count = 0;
for (uint32_t i = 0; i < arms->children; ++i) {
zend_ast *arm_ast = arms->child[i];
if (!arm_ast->child[0]) {
continue;
}
zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
for (uint32_t j = 0; j < conds->children; j++) {
zend_ast *cond_ast = conds->child[j];
znode cond_node;
zend_compile_expr(&cond_node, cond_ast);
uint32_t opcode = (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) ? ZEND_CASE_STRICT : ZEND_IS_IDENTICAL;
zend_op *opline = zend_emit_op(NULL, opcode, &expr_node, &cond_node);
SET_NODE(opline->result, &case_node);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
jmpnz_opnums[cond_count] = zend_emit_cond_jump(ZEND_JMPNZ, &case_node, 0);
cond_count++;
}
}
}
uint32_t opnum_default_jmp = 0;
if (!uses_jumptable) {
opnum_default_jmp = zend_emit_jump(0);
}
bool is_first_case = 1;
uint32_t cond_count = 0;
uint32_t *jmp_end_opnums = safe_emalloc(sizeof(uint32_t), arms->children, 0);
// The generated default arm is emitted first to avoid live range issues where the tmpvar
// for the arm result is freed even though it has not been initialized yet.
if (!has_default_arm) {
if (!uses_jumptable) {
zend_update_jump_target_to_next(opnum_default_jmp);
}
if (jumptable) {
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
opline->extended_value = get_next_op_number();
}
zend_op *opline = zend_emit_op(NULL, ZEND_MATCH_ERROR, &expr_node, NULL);
if (opline->op1_type == IS_CONST) {
Z_TRY_ADDREF_P(CT_CONSTANT(opline->op1));
}
}
for (uint32_t i = 0; i < arms->children; ++i) {
zend_ast *arm_ast = arms->child[i];
zend_ast *body_ast = arm_ast->child[1];
if (arm_ast->child[0] != NULL) {
zend_ast_list *conds = zend_ast_get_list(arm_ast->child[0]);
for (uint32_t j = 0; j < conds->children; j++) {
zend_ast *cond_ast = conds->child[j];
if (jmpnz_opnums != NULL) {
zend_update_jump_target_to_next(jmpnz_opnums[cond_count]);
}
if (jumptable) {
zval *cond_zv = zend_ast_get_zval(cond_ast);
zval jmp_target;
ZVAL_LONG(&jmp_target, get_next_op_number());
if (Z_TYPE_P(cond_zv) == IS_LONG) {
zend_hash_index_add(jumptable, Z_LVAL_P(cond_zv), &jmp_target);
} else {
ZEND_ASSERT(Z_TYPE_P(cond_zv) == IS_STRING);
zend_hash_add(jumptable, Z_STR_P(cond_zv), &jmp_target);
}
}
cond_count++;
}
} else {
if (!uses_jumptable) {
zend_update_jump_target_to_next(opnum_default_jmp);
}
if (jumptable) {
ZEND_ASSERT(opnum_match != (uint32_t)-1);
zend_op *opline = &CG(active_op_array)->opcodes[opnum_match];
opline->extended_value = get_next_op_number();
}
}
znode body_node;
zend_compile_expr(&body_node, body_ast);
if (is_first_case) {
zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &body_node, NULL);
is_first_case = 0;
} else {
zend_op *opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &body_node, NULL);
SET_NODE(opline_qm_assign->result, result);
}
jmp_end_opnums[i] = zend_emit_jump(0);
}
// Initialize result in case there is no arm
if (arms->children == 0) {
result->op_type = IS_CONST;
ZVAL_NULL(&result->u.constant);
}
for (uint32_t i = 0; i < arms->children; ++i) {
zend_update_jump_target_to_next(jmp_end_opnums[i]);
}
if (expr_node.op_type & (IS_VAR|IS_TMP_VAR)) {
zend_op *opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL);
opline->extended_value = ZEND_FREE_SWITCH;
} else if (expr_node.op_type == IS_CONST) {
zval_ptr_dtor_nogc(&expr_node.u.constant);
}
if (jmpnz_opnums != NULL) {
efree(jmpnz_opnums);
}
efree(jmp_end_opnums);
}
2014-12-13 22:06:14 +00:00
void zend_compile_try(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *try_ast = ast->child[0];
zend_ast_list *catches = zend_ast_get_list(ast->child[1]);
zend_ast *finally_ast = ast->child[2];
uint32_t i, j;
zend_op *opline;
2015-07-10 21:29:07 +00:00
uint32_t try_catch_offset;
uint32_t *jmp_opnums = safe_emalloc(sizeof(uint32_t), catches->children, 0);
uint32_t orig_fast_call_var = CG(context).fast_call_var;
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
uint32_t orig_try_catch_offset = CG(context).try_catch_offset;
if (catches->children == 0 && !finally_ast) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use try without catch or finally");
}
2015-07-10 21:29:07 +00:00
/* label: try { } must not be equal to try { label: } */
if (CG(context).labels) {
2015-07-11 10:59:09 +00:00
zend_label *label;
ZEND_HASH_REVERSE_FOREACH_PTR(CG(context).labels, label) {
if (label->opline_num == get_next_op_number()) {
zend_emit_op(NULL, ZEND_NOP, NULL, NULL);
2015-07-10 21:29:07 +00:00
}
2015-07-11 10:59:09 +00:00
break;
} ZEND_HASH_FOREACH_END();
2015-07-10 21:29:07 +00:00
}
try_catch_offset = zend_add_try_element(get_next_op_number());
2015-07-10 21:29:07 +00:00
2015-07-10 11:30:25 +00:00
if (finally_ast) {
zend_loop_var fast_call;
if (!(CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_HAS_FINALLY_BLOCK;
}
CG(context).fast_call_var = get_temporary_variable();
2015-07-10 11:30:25 +00:00
/* Push FAST_CALL on unwind stack */
fast_call.opcode = ZEND_FAST_CALL;
fast_call.var_type = IS_TMP_VAR;
fast_call.var_num = CG(context).fast_call_var;
fast_call.try_catch_offset = try_catch_offset;
2015-07-10 11:30:25 +00:00
zend_stack_push(&CG(loop_var_stack), &fast_call);
}
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
CG(context).try_catch_offset = try_catch_offset;
2014-12-13 22:06:14 +00:00
zend_compile_stmt(try_ast);
if (catches->children != 0) {
2014-12-13 22:06:14 +00:00
jmp_opnums[0] = zend_emit_jump(0);
}
for (i = 0; i < catches->children; ++i) {
zend_ast *catch_ast = catches->child[i];
zend_ast_list *classes = zend_ast_get_list(catch_ast->child[0]);
zend_ast *var_ast = catch_ast->child[1];
zend_ast *stmt_ast = catch_ast->child[2];
zend_string *var_name = var_ast ? zval_make_interned_string(zend_ast_get_zval(var_ast)) : NULL;
bool is_last_catch = (i + 1 == catches->children);
uint32_t *jmp_multicatch = safe_emalloc(sizeof(uint32_t), classes->children - 1, 0);
uint32_t opnum_catch = (uint32_t)-1;
CG(zend_lineno) = catch_ast->lineno;
for (j = 0; j < classes->children; j++) {
zend_ast *class_ast = classes->child[j];
bool is_last_class = (j + 1 == classes->children);
if (!zend_is_const_default_class_ref(class_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Bad class name in the catch statement");
}
opnum_catch = get_next_op_number();
if (i == 0 && j == 0) {
CG(active_op_array)->try_catch_array[try_catch_offset].catch_op = opnum_catch;
}
opline = get_next_op();
opline->opcode = ZEND_CATCH;
opline->op1_type = IS_CONST;
opline->op1.constant = zend_add_class_name_literal(
zend_resolve_class_name_ast(class_ast));
opline->extended_value = zend_alloc_cache_slot();
if (var_name && zend_string_equals_literal(var_name, "this")) {
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
}
opline->result_type = var_name ? IS_CV : IS_UNUSED;
opline->result.var = var_name ? lookup_cv(var_name) : -1;
if (is_last_catch && is_last_class) {
opline->extended_value |= ZEND_LAST_CATCH;
}
if (!is_last_class) {
jmp_multicatch[j] = zend_emit_jump(0);
opline = &CG(active_op_array)->opcodes[opnum_catch];
opline->op2.opline_num = get_next_op_number();
}
}
for (j = 0; j < classes->children - 1; j++) {
zend_update_jump_target_to_next(jmp_multicatch[j]);
}
efree(jmp_multicatch);
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
2014-07-12 17:08:09 +00:00
if (!is_last_catch) {
2014-12-13 22:06:14 +00:00
jmp_opnums[i + 1] = zend_emit_jump(0);
2004-02-27 09:14:55 +00:00
}
ZEND_ASSERT(opnum_catch != (uint32_t)-1 && "Should have at least one class");
opline = &CG(active_op_array)->opcodes[opnum_catch];
if (!is_last_catch) {
opline->op2.opline_num = get_next_op_number();
}
}
for (i = 0; i < catches->children; ++i) {
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(jmp_opnums[i]);
}
if (finally_ast) {
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
zend_loop_var discard_exception;
uint32_t opnum_jmp = get_next_op_number() + 1;
2015-07-10 11:30:25 +00:00
/* Pop FAST_CALL from unwind stack */
zend_stack_del_top(&CG(loop_var_stack));
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
/* Push DISCARD_EXCEPTION on unwind stack */
discard_exception.opcode = ZEND_DISCARD_EXCEPTION;
discard_exception.var_type = IS_TMP_VAR;
discard_exception.var_num = CG(context).fast_call_var;
zend_stack_push(&CG(loop_var_stack), &discard_exception);
CG(zend_lineno) = finally_ast->lineno;
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_FAST_CALL, NULL, NULL);
2015-08-04 05:35:40 +00:00
opline->op1.num = try_catch_offset;
opline->result_type = IS_TMP_VAR;
opline->result.var = CG(context).fast_call_var;
2014-12-13 22:06:14 +00:00
zend_emit_op(NULL, ZEND_JMP, NULL, NULL);
2014-12-13 22:06:14 +00:00
zend_compile_stmt(finally_ast);
CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1;
CG(active_op_array)->try_catch_array[try_catch_offset].finally_end
= get_next_op_number();
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(NULL, ZEND_FAST_RET, NULL, NULL);
opline->op1_type = IS_TMP_VAR;
opline->op1.var = CG(context).fast_call_var;
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
opline->op2.num = orig_try_catch_offset;
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_jmp);
CG(context).fast_call_var = orig_fast_call_var;
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
/* Pop DISCARD_EXCEPTION from unwind stack */
zend_stack_del_top(&CG(loop_var_stack));
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
Fixed bug #72213 (Finally leaks on nested exceptions). Squashed commit of the following: commit 8461b0407fc9eab0869d43b84e6a92ba2fe06997 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:34:42 2016 +0300 Rmoved zend_try_catch_element.parent and walk through op_array.try_catch_array backward from the current try_cacth_offset. commit 0c71e249649bed178bfbef30bb3e63c57f07af05 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:04:53 2016 +0300 Move SAVE_OPLINE() to its original place commit 111432a4df738fcd65878a42f23194dc3c4983a2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed May 25 00:01:10 2016 +0300 Separate the common part of ZEND_HANDLE_EXCEPTION and FAST_RET into zend_dispatch_try_catch_finally_helper. commit 4f21c06c2ec17819a708bc037f318784554a6ecd Author: Nikita Popov <nikic@php.net> Date: Tue May 24 14:55:27 2016 +0200 Improve finally fix commit da5c7274997b8308e682b5bf280124e3a1483086 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 10:36:08 2016 +0300 Fixed Zend/tests/try/bug70228_3.phpt and Zend/tests/try/bug70228_4.phpt commit cfcedf2fb4f4fc1f7de9f7d53a3037fed7795f19 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:59:27 2016 +0300 Added test commit 4c6aa93d43da941eb4fda15b48154bfb104bdc04 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 00:38:20 2016 +0300 Added tests commit 8a8f4704b0eca2e460d42c1f253a363b0db8e510 Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 23:27:34 2016 +0300 Fixed bug #72213 (Finally leaks on nested exceptions)
2016-05-24 22:25:12 +00:00
CG(context).try_catch_offset = orig_try_catch_offset;
efree(jmp_opnums);
}
2014-08-29 05:05:58 +00:00
/* }}} */
/* Encoding declarations must already be handled during parsing */
bool zend_handle_encoding_declaration(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *declares = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < declares->children; ++i) {
zend_ast *declare_ast = declares->child[i];
2014-07-22 14:11:19 +00:00
zend_ast *name_ast = declare_ast->child[0];
zend_ast *value_ast = declare_ast->child[1];
2014-07-28 13:16:35 +00:00
zend_string *name = zend_ast_get_str(name_ast);
2014-07-22 14:11:19 +00:00
if (zend_string_equals_literal_ci(name, "encoding")) {
if (value_ast->kind != ZEND_AST_ZVAL) {
zend_throw_exception(zend_ce_compile_error, "Encoding must be a literal", 0);
return 0;
2014-07-22 14:11:19 +00:00
}
if (CG(multibyte)) {
zend_string *encoding_name = zval_get_string(zend_ast_get_zval(value_ast));
2014-07-22 14:11:19 +00:00
const zend_encoding *new_encoding, *old_encoding;
zend_encoding_filter old_input_filter;
CG(encoding_declared) = 1;
new_encoding = zend_multibyte_fetch_encoding(ZSTR_VAL(encoding_name));
2014-07-22 14:11:19 +00:00
if (!new_encoding) {
zend_error(E_COMPILE_WARNING, "Unsupported encoding [%s]", ZSTR_VAL(encoding_name));
2014-07-22 14:11:19 +00:00
} else {
old_input_filter = LANG_SCNG(input_filter);
old_encoding = LANG_SCNG(script_encoding);
2014-12-13 22:06:14 +00:00
zend_multibyte_set_filter(new_encoding);
2014-07-22 14:11:19 +00:00
/* need to re-scan if input filter changed */
if (old_input_filter != LANG_SCNG(input_filter) ||
(old_input_filter && new_encoding != old_encoding)) {
2014-12-13 22:06:14 +00:00
zend_multibyte_yyinput_again(old_input_filter, old_encoding);
2014-07-22 14:11:19 +00:00
}
}
zend_string_release_ex(encoding_name, 0);
2014-07-22 14:11:19 +00:00
} else {
zend_error(E_COMPILE_WARNING, "declare(encoding=...) ignored because "
"Zend multibyte feature is turned off by settings");
}
}
}
return 1;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
/* Check whether this is the first statement, not counting declares. */
static zend_result zend_is_first_statement(zend_ast *ast, bool allow_nop) /* {{{ */
{
uint32_t i = 0;
zend_ast_list *file_ast = zend_ast_get_list(CG(ast));
while (i < file_ast->children) {
if (file_ast->child[i] == ast) {
return SUCCESS;
} else if (file_ast->child[i] == NULL) {
if (!allow_nop) {
return FAILURE;
}
} else if (file_ast->child[i]->kind != ZEND_AST_DECLARE) {
return FAILURE;
}
i++;
}
return FAILURE;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_declare(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *declares = zend_ast_get_list(ast->child[0]);
zend_ast *stmt_ast = ast->child[1];
zend_declarables orig_declarables = FC(declarables);
uint32_t i;
for (i = 0; i < declares->children; ++i) {
zend_ast *declare_ast = declares->child[i];
zend_ast *name_ast = declare_ast->child[0];
zend_ast **value_ast_ptr = &declare_ast->child[1];
zend_string *name = zend_ast_get_str(name_ast);
if ((*value_ast_ptr)->kind != ZEND_AST_ZVAL) {
zend_error_noreturn(E_COMPILE_ERROR, "declare(%s) value must be a literal", ZSTR_VAL(name));
}
if (zend_string_equals_literal_ci(name, "ticks")) {
zval value_zv;
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
FC(declarables).ticks = zval_get_long(&value_zv);
zval_ptr_dtor_nogc(&value_zv);
} else if (zend_string_equals_literal_ci(name, "encoding")) {
2015-03-20 08:10:29 +00:00
if (FAILURE == zend_is_first_statement(ast, /* allow_nop */ 0)) {
zend_error_noreturn(E_COMPILE_ERROR, "Encoding declaration pragma must be "
"the very first statement in the script");
}
2015-01-25 01:40:54 +00:00
} else if (zend_string_equals_literal_ci(name, "strict_types")) {
2015-01-10 03:29:41 +00:00
zval value_zv;
if (FAILURE == zend_is_first_statement(ast, /* allow_nop */ 0)) {
zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must be "
"the very first statement in the script");
}
if (ast->child[1] != NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must not "
2015-03-20 08:10:29 +00:00
"use block mode");
}
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
2015-01-10 03:29:41 +00:00
2015-01-25 01:40:54 +00:00
if (Z_TYPE(value_zv) != IS_LONG || (Z_LVAL(value_zv) != 0 && Z_LVAL(value_zv) != 1)) {
zend_error_noreturn(E_COMPILE_ERROR, "strict_types declaration must have 0 or 1 as its value");
2015-01-10 03:29:41 +00:00
}
if (Z_LVAL(value_zv) == 1) {
CG(active_op_array)->fn_flags |= ZEND_ACC_STRICT_TYPES;
}
2015-03-20 08:10:29 +00:00
2014-07-22 14:11:19 +00:00
} else {
zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name));
2014-07-22 14:11:19 +00:00
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-07-22 14:11:19 +00:00
if (stmt_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
2014-07-22 14:11:19 +00:00
FC(declarables) = orig_declarables;
}
2014-07-22 14:11:19 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_stmt_list(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
2014-12-13 22:06:14 +00:00
zend_compile_stmt(list->child[i]);
}
2003-03-05 11:14:44 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-05 11:14:44 +00:00
2015-04-23 10:31:02 +00:00
ZEND_API void zend_set_function_arg_flags(zend_function *func) /* {{{ */
{
uint32_t i, n;
func->common.arg_flags[0] = 0;
func->common.arg_flags[1] = 0;
func->common.arg_flags[2] = 0;
if (func->common.arg_info) {
n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM);
i = 0;
while (i < n) {
ZEND_SET_ARG_FLAG(func, i + 1, ZEND_ARG_SEND_MODE(&func->common.arg_info[i]));
i++;
}
if (UNEXPECTED((func->common.fn_flags & ZEND_ACC_VARIADIC) && ZEND_ARG_SEND_MODE(&func->common.arg_info[i]))) {
uint32_t pass_by_reference = ZEND_ARG_SEND_MODE(&func->common.arg_info[i]);
while (i < MAX_ARG_FLAG_NUM) {
ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference);
i++;
}
}
}
}
/* }}} */
static zend_type zend_compile_single_typename(zend_ast *ast)
2015-05-21 01:50:20 +00:00
{
ZEND_ASSERT(!(ast->attr & ZEND_TYPE_NULLABLE));
2015-05-21 01:50:20 +00:00
if (ast->kind == ZEND_AST_TYPE) {
if (ast->attr == IS_STATIC && !CG(active_class_entry) && zend_is_scope_known()) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use \"static\" when no class scope is active");
}
return (zend_type) ZEND_TYPE_INIT_CODE(ast->attr, 0, 0);
2015-05-21 01:50:20 +00:00
} else {
zend_string *class_name = zend_ast_get_str(ast);
zend_uchar type_code = zend_lookup_builtin_type_by_name(class_name);
2015-05-21 01:50:20 +00:00
if (type_code != 0) {
if ((ast->attr & ZEND_NAME_NOT_FQ) != ZEND_NAME_NOT_FQ) {
2015-11-26 15:56:08 +00:00
zend_error_noreturn(E_COMPILE_ERROR,
2018-04-08 18:19:14 +00:00
"Type declaration '%s' must be unqualified",
2015-11-26 15:56:08 +00:00
ZSTR_VAL(zend_string_tolower(class_name)));
}
return (zend_type) ZEND_TYPE_INIT_CODE(type_code, 0, 0);
2015-05-21 01:50:20 +00:00
} else {
const char *correct_name;
zend_string *orig_name = zend_ast_get_str(ast);
2015-05-21 01:50:20 +00:00
uint32_t fetch_type = zend_get_class_fetch_type_ast(ast);
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
class_name = zend_resolve_class_name_ast(ast);
zend_assert_valid_class_name(class_name);
} else {
zend_ensure_valid_class_fetch_type(fetch_type);
zend_string_addref(class_name);
}
if (ast->attr == ZEND_NAME_NOT_FQ
&& zend_is_confusable_type(orig_name, &correct_name)
&& zend_is_not_imported(orig_name)) {
const char *extra =
FC(current_namespace) ? " or import the class with \"use\"" : "";
if (correct_name) {
zend_error(E_COMPILE_WARNING,
"\"%s\" will be interpreted as a class name. Did you mean \"%s\"? "
"Write \"\\%s\"%s to suppress this warning",
ZSTR_VAL(orig_name), correct_name, ZSTR_VAL(class_name), extra);
} else {
zend_error(E_COMPILE_WARNING,
"\"%s\" is not a supported builtin type "
"and will be interpreted as a class name. "
"Write \"\\%s\"%s to suppress this warning",
ZSTR_VAL(orig_name), ZSTR_VAL(class_name), extra);
}
}
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, 0, 0);
2015-05-21 01:50:20 +00:00
}
}
}
static bool zend_type_contains_traversable(zend_type type) {
zend_type *single_type;
ZEND_TYPE_FOREACH(type, single_type) {
if (ZEND_TYPE_HAS_NAME(*single_type)
&& zend_string_equals_literal_ci(ZEND_TYPE_NAME(*single_type), "Traversable")) {
return 1;
}
} ZEND_TYPE_FOREACH_END();
return 0;
}
// TODO: Ideally we'd canonicalize "iterable" into "array|Traversable" and essentially
// treat it as a built-in type alias.
static zend_type zend_compile_typename(
zend_ast *ast, bool force_allow_null) /* {{{ */
{
bool allow_null = force_allow_null;
zend_ast_attr orig_ast_attr = ast->attr;
zend_type type = ZEND_TYPE_INIT_NONE(0);
if (ast->attr & ZEND_TYPE_NULLABLE) {
allow_null = 1;
ast->attr &= ~ZEND_TYPE_NULLABLE;
}
if (ast->kind == ZEND_AST_TYPE_UNION) {
zend_ast_list *list = zend_ast_get_list(ast);
zend_type_list *type_list;
ALLOCA_FLAG(use_heap)
type_list = do_alloca(ZEND_TYPE_LIST_SIZE(list->children), use_heap);
type_list->num_types = 0;
for (uint32_t i = 0; i < list->children; i++) {
zend_ast *type_ast = list->child[i];
zend_type single_type = zend_compile_single_typename(type_ast);
uint32_t single_type_mask = ZEND_TYPE_PURE_MASK(single_type);
if (single_type_mask == MAY_BE_ANY) {
zend_error_noreturn(E_COMPILE_ERROR, "Type mixed can only be used as a standalone type");
}
uint32_t type_mask_overlap = ZEND_TYPE_PURE_MASK(type) & single_type_mask;
if (type_mask_overlap) {
zend_type overlap_type = ZEND_TYPE_INIT_MASK(type_mask_overlap);
zend_string *overlap_type_str = zend_type_to_string(overlap_type);
zend_error_noreturn(E_COMPILE_ERROR,
"Duplicate type %s is redundant", ZSTR_VAL(overlap_type_str));
}
ZEND_TYPE_FULL_MASK(type) |= ZEND_TYPE_PURE_MASK(single_type);
ZEND_TYPE_FULL_MASK(single_type) &= ~_ZEND_TYPE_MAY_BE_MASK;
if (ZEND_TYPE_HAS_CLASS(single_type)) {
if (!ZEND_TYPE_HAS_CLASS(type)) {
/* The first class type can be stored directly as the type ptr payload. */
ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type));
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT;
} else {
if (type_list->num_types == 0) {
/* Switch from single name to name list. */
type_list->num_types = 1;
type_list->types[0] = type;
ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
ZEND_TYPE_SET_LIST(type, type_list);
}
type_list->types[type_list->num_types++] = single_type;
/* Check for trivially redundant class types */
for (size_t i = 0; i < type_list->num_types - 1; i++) {
if (zend_string_equals_ci(
ZEND_TYPE_NAME(type_list->types[i]), ZEND_TYPE_NAME(single_type))) {
zend_string *single_type_str = zend_type_to_string(single_type);
zend_error_noreturn(E_COMPILE_ERROR,
"Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
}
}
}
}
}
if (type_list->num_types) {
zend_type_list *list = zend_arena_alloc(
&CG(arena), ZEND_TYPE_LIST_SIZE(type_list->num_types));
memcpy(list, type_list, ZEND_TYPE_LIST_SIZE(type_list->num_types));
ZEND_TYPE_SET_LIST(type, list);
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_ARENA_BIT;
}
free_alloca(type_list, use_heap);
} else {
type = zend_compile_single_typename(ast);
}
if (allow_null) {
ZEND_TYPE_FULL_MASK(type) |= MAY_BE_NULL;
}
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
if ((type_mask & (MAY_BE_ARRAY|MAY_BE_ITERABLE)) == (MAY_BE_ARRAY|MAY_BE_ITERABLE)) {
zend_string *type_str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Type %s contains both iterable and array, which is redundant", ZSTR_VAL(type_str));
}
if ((type_mask & MAY_BE_ITERABLE) && zend_type_contains_traversable(type)) {
zend_string *type_str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Type %s contains both iterable and Traversable, which is redundant",
ZSTR_VAL(type_str));
}
if (type_mask == MAY_BE_ANY && (orig_ast_attr & ZEND_TYPE_NULLABLE)) {
zend_error_noreturn(E_COMPILE_ERROR, "Type mixed cannot be marked as nullable since mixed already includes null");
}
if ((type_mask & MAY_BE_OBJECT) && (ZEND_TYPE_HAS_CLASS(type) || (type_mask & MAY_BE_STATIC))) {
zend_string *type_str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Type %s contains both object and a class type, which is redundant",
ZSTR_VAL(type_str));
}
if ((type_mask & MAY_BE_VOID) && (ZEND_TYPE_HAS_CLASS(type) || type_mask != MAY_BE_VOID)) {
zend_error_noreturn(E_COMPILE_ERROR, "Void can only be used as a standalone type");
}
if ((type_mask & MAY_BE_NEVER) && (ZEND_TYPE_HAS_CLASS(type) || type_mask != MAY_BE_NEVER)) {
zend_error_noreturn(E_COMPILE_ERROR, "never can only be used as a standalone type");
}
if ((type_mask & (MAY_BE_NULL|MAY_BE_FALSE))
&& !ZEND_TYPE_HAS_CLASS(type) && !(type_mask & ~(MAY_BE_NULL|MAY_BE_FALSE))) {
if (type_mask == MAY_BE_NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Null can not be used as a standalone type");
} else {
zend_error_noreturn(E_COMPILE_ERROR, "False can not be used as a standalone type");
}
}
ast->attr = orig_ast_attr;
return type;
}
2015-05-21 01:50:20 +00:00
/* }}} */
2019-10-08 13:52:18 +00:00
/* May convert value from int to float. */
static bool zend_is_valid_default_value(zend_type type, zval *value)
{
ZEND_ASSERT(ZEND_TYPE_IS_SET(type));
if (ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE_P(value))) {
return 1;
}
if ((ZEND_TYPE_FULL_MASK(type) & MAY_BE_DOUBLE) && Z_TYPE_P(value) == IS_LONG) {
/* Integers are allowed as initializers for floating-point values. */
2019-10-08 13:52:18 +00:00
convert_to_double(value);
return 1;
}
if ((ZEND_TYPE_FULL_MASK(type) & MAY_BE_ITERABLE) && Z_TYPE_P(value) == IS_ARRAY) {
return 1;
}
return 0;
}
static void zend_compile_attributes(HashTable **attributes, zend_ast *ast, uint32_t offset, uint32_t target) /* {{{ */
{
zend_attribute *attr;
zend_internal_attribute *config;
zend_ast_list *list = zend_ast_get_list(ast);
2020-08-15 08:39:00 +00:00
uint32_t g, i, j;
ZEND_ASSERT(ast->kind == ZEND_AST_ATTRIBUTE_LIST);
2020-08-15 08:39:00 +00:00
for (g = 0; g < list->children; g++) {
zend_ast_list *group = zend_ast_get_list(list->child[g]);
2020-08-15 08:39:00 +00:00
ZEND_ASSERT(group->kind == ZEND_AST_ATTRIBUTE_GROUP);
2020-08-15 08:39:00 +00:00
for (i = 0; i < group->children; i++) {
ZEND_ASSERT(group->child[i]->kind == ZEND_AST_ATTRIBUTE);
2020-08-15 08:39:00 +00:00
zend_ast *el = group->child[i];
zend_string *name = zend_resolve_class_name_ast(el->child[0]);
zend_ast_list *args = el->child[1] ? zend_ast_get_list(el->child[1]) : NULL;
uint32_t flags = (CG(active_op_array)->fn_flags & ZEND_ACC_STRICT_TYPES)
? ZEND_ATTRIBUTE_STRICT_TYPES : 0;
attr = zend_add_attribute(
attributes, name, args ? args->children : 0, flags, offset, el->lineno);
2020-08-15 08:39:00 +00:00
zend_string_release(name);
2020-08-15 08:39:00 +00:00
/* Populate arguments */
if (args) {
ZEND_ASSERT(args->kind == ZEND_AST_ARG_LIST);
bool uses_named_args = 0;
2020-08-15 08:39:00 +00:00
for (j = 0; j < args->children; j++) {
zend_ast **arg_ast_ptr = &args->child[j];
zend_ast *arg_ast = *arg_ast_ptr;
2020-08-15 08:39:00 +00:00
if (arg_ast->kind == ZEND_AST_UNPACK) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use unpacking in attribute argument list");
}
2020-08-15 08:39:00 +00:00
if (arg_ast->kind == ZEND_AST_NAMED_ARG) {
attr->args[j].name = zend_string_copy(zend_ast_get_str(arg_ast->child[0]));
arg_ast_ptr = &arg_ast->child[1];
2020-08-15 08:39:00 +00:00
uses_named_args = 1;
for (uint32_t k = 0; k < j; k++) {
if (attr->args[k].name &&
zend_string_equals(attr->args[k].name, attr->args[j].name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate named parameter $%s",
ZSTR_VAL(attr->args[j].name));
}
}
2020-08-15 08:39:00 +00:00
} else if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use positional argument after named argument");
}
zend_const_expr_to_zval(&attr->args[j].value, arg_ast_ptr);
2020-08-15 08:39:00 +00:00
}
}
}
}
/* Validate attributes in a secondary loop (needed to detect repeated attributes). */
ZEND_HASH_FOREACH_PTR(*attributes, attr) {
if (attr->offset != offset || NULL == (config = zend_internal_attribute_get(attr->lcname))) {
continue;
}
if (!(target & (config->flags & ZEND_ATTRIBUTE_TARGET_ALL))) {
zend_string *location = zend_get_attribute_target_names(target);
zend_string *allowed = zend_get_attribute_target_names(config->flags);
zend_error_noreturn(E_ERROR, "Attribute \"%s\" cannot target %s (allowed targets: %s)",
ZSTR_VAL(attr->name), ZSTR_VAL(location), ZSTR_VAL(allowed)
);
}
if (!(config->flags & ZEND_ATTRIBUTE_IS_REPEATABLE)) {
if (zend_is_attribute_repeated(*attributes, attr)) {
zend_error_noreturn(E_ERROR, "Attribute \"%s\" must not be repeated", ZSTR_VAL(attr->name));
}
}
if (config->validator != NULL) {
config->validator(attr, target, CG(active_class_entry));
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, uint32_t fallback_return_type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
zend_op_array *op_array = CG(active_op_array);
zend_arg_info *arg_infos;
if (return_type_ast || fallback_return_type) {
/* Use op_array->arg_info[-1] for return type */
arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children + 1, 0);
arg_infos->name = NULL;
if (return_type_ast) {
arg_infos->type = zend_compile_typename(
return_type_ast, /* force_allow_null */ 0);
ZEND_TYPE_FULL_MASK(arg_infos->type) |= _ZEND_ARG_INFO_FLAGS(
(op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0, /* is_variadic */ 0, /* is_tentative */ 0);
} else {
arg_infos->type = (zend_type) ZEND_TYPE_INIT_CODE(fallback_return_type, 0, 0);
}
arg_infos++;
op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
} else {
if (list->children == 0) {
return;
}
arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0);
}
2015-01-03 09:22:58 +00:00
/* Find last required parameter number for deprecation message. */
uint32_t last_required_param = (uint32_t) -1;
for (i = 0; i < list->children; ++i) {
zend_ast *param_ast = list->child[i];
zend_ast *default_ast_ptr = param_ast->child[2];
bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
if (!default_ast_ptr && !is_variadic) {
last_required_param = i;
}
}
for (i = 0; i < list->children; ++i) {
zend_ast *param_ast = list->child[i];
zend_ast *type_ast = param_ast->child[0];
zend_ast *var_ast = param_ast->child[1];
zend_ast **default_ast_ptr = &param_ast->child[2];
zend_ast *attributes_ast = param_ast->child[3];
zend_ast *doc_comment_ast = param_ast->child[4];
zend_string *name = zval_make_interned_string(zend_ast_get_zval(var_ast));
bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
bool is_variadic = (param_ast->attr & ZEND_PARAM_VARIADIC) != 0;
uint32_t visibility =
param_ast->attr & (ZEND_ACC_PUBLIC|ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE);
znode var_node, default_node;
zend_uchar opcode;
zend_op *opline;
zend_arg_info *arg_info;
2014-12-13 22:06:14 +00:00
if (zend_is_auto_global(name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign auto-global variable %s",
ZSTR_VAL(name));
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
var_node.op_type = IS_CV;
var_node.u.op.var = lookup_cv(name);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (EX_VAR_TO_NUM(var_node.u.op.var) != i) {
zend_error_noreturn(E_COMPILE_ERROR, "Redefinition of parameter $%s",
ZSTR_VAL(name));
} else if (zend_string_equals_literal(name, "this")) {
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as parameter");
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Only the last parameter can be variadic");
}
if (is_variadic) {
opcode = ZEND_RECV_VARIADIC;
default_node.op_type = IS_UNUSED;
op_array->fn_flags |= ZEND_ACC_VARIADIC;
1999-04-07 18:10:10 +00:00
if (*default_ast_ptr) {
zend_error_noreturn(E_COMPILE_ERROR,
"Variadic parameter cannot have a default value");
}
} else if (*default_ast_ptr) {
/* we cannot substitute constants here or it will break ReflectionParameter::getDefaultValueConstantName() and ReflectionParameter::isDefaultValueConstant() */
uint32_t cops = CG(compiler_options);
CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION;
opcode = ZEND_RECV_INIT;
default_node.op_type = IS_CONST;
zend_const_expr_to_zval(&default_node.u.constant, default_ast_ptr);
CG(compiler_options) = cops;
if (last_required_param != (uint32_t) -1 && i < last_required_param) {
/* Ignore parameters of the form "Type $param = null".
* This is the PHP 5 style way of writing "?Type $param", so allow it for now. */
bool is_implicit_nullable =
type_ast && !(type_ast->attr & ZEND_TYPE_NULLABLE)
&& Z_TYPE(default_node.u.constant) == IS_NULL;
if (!is_implicit_nullable) {
zend_ast *required_param_ast = list->child[last_required_param];
zend_error(E_DEPRECATED,
"Optional parameter $%s declared before required parameter $%s "
"is implicitly treated as a required parameter",
ZSTR_VAL(name), ZSTR_VAL(zend_ast_get_str(required_param_ast->child[1])));
}
/* Regardless of whether we issue a deprecation, convert this parameter into
* a required parameter without a default value. This ensures that it cannot be
* used as an optional parameter even with named parameters. */
opcode = ZEND_RECV;
default_node.op_type = IS_UNUSED;
zval_ptr_dtor(&default_node.u.constant);
}
} else {
opcode = ZEND_RECV;
default_node.op_type = IS_UNUSED;
op_array->required_num_args = i + 1;
}
arg_info = &arg_infos[i];
arg_info->name = zend_string_copy(name);
arg_info->type = (zend_type) ZEND_TYPE_INIT_NONE(0);
if (attributes_ast) {
zend_compile_attributes(&op_array->attributes, attributes_ast, i + 1, ZEND_ATTRIBUTE_TARGET_PARAMETER);
}
if (type_ast) {
uint32_t default_type = *default_ast_ptr ? Z_TYPE(default_node.u.constant) : IS_UNDEF;
bool force_nullable = default_type == IS_NULL && !visibility;
2019-03-06 09:42:02 +00:00
op_array->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
arg_info->type = zend_compile_typename(type_ast, force_nullable);
2015-05-21 01:50:20 +00:00
if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_VOID) {
2015-10-14 18:15:32 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "void cannot be used as a parameter type");
}
if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_NEVER) {
zend_error_noreturn(E_COMPILE_ERROR, "never cannot be used as a parameter type");
}
if (default_type != IS_UNDEF && default_type != IS_CONSTANT_AST && !force_nullable
&& !zend_is_valid_default_value(arg_info->type, &default_node.u.constant)) {
zend_string *type_str = zend_type_to_string(arg_info->type);
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use %s as default value for parameter $%s of type %s",
zend_get_type_by_const(default_type),
ZSTR_VAL(name), ZSTR_VAL(type_str));
}
}
opline = zend_emit_op(NULL, opcode, NULL, &default_node);
SET_NODE(opline->result, &var_node);
opline->op1.num = i + 1;
if (type_ast) {
/* Allocate cache slot to speed-up run-time class resolution */
opline->extended_value =
zend_alloc_cache_slots(zend_type_get_num_classes(arg_info->type));
}
uint32_t arg_info_flags = _ZEND_ARG_INFO_FLAGS(is_ref, is_variadic, /* is_tentative */ 0)
| (visibility ? _ZEND_IS_PROMOTED_BIT : 0);
ZEND_TYPE_FULL_MASK(arg_info->type) |= arg_info_flags;
2019-12-20 03:46:25 +00:00
if (opcode == ZEND_RECV) {
opline->op2.num = type_ast ?
ZEND_TYPE_FULL_MASK(arg_info->type) : MAY_BE_ANY;
}
if (visibility) {
zend_op_array *op_array = CG(active_op_array);
zend_class_entry *scope = op_array->scope;
bool is_ctor =
2020-06-17 14:04:52 +00:00
scope && zend_is_constructor(op_array->function_name);
if (!is_ctor) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot declare promoted property outside a constructor");
}
if ((op_array->fn_flags & ZEND_ACC_ABSTRACT)
|| (scope->ce_flags & ZEND_ACC_INTERFACE)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot declare promoted property in an abstract constructor");
}
if (is_variadic) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot declare variadic promoted property");
}
if (zend_hash_exists(&scope->properties_info, name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::$%s",
ZSTR_VAL(scope->name), ZSTR_VAL(name));
}
if (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_CALLABLE) {
zend_string *str = zend_type_to_string(arg_info->type);
zend_error_noreturn(E_COMPILE_ERROR,
"Property %s::$%s cannot have type %s",
ZSTR_VAL(scope->name), ZSTR_VAL(name), ZSTR_VAL(str));
}
/* Recompile the type, as it has different memory management requirements. */
zend_type type = ZEND_TYPE_INIT_NONE(0);
if (type_ast) {
type = zend_compile_typename(type_ast, /* force_allow_null */ 0);
}
/* Don't give the property an explicit default value. For typed properties this means
* uninitialized, for untyped properties it means an implicit null default value. */
zval default_value;
if (ZEND_TYPE_IS_SET(type)) {
ZVAL_UNDEF(&default_value);
} else {
ZVAL_NULL(&default_value);
}
zend_string *doc_comment =
doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zend_property_info *prop = zend_declare_typed_property(
scope, name, &default_value, visibility | ZEND_ACC_PROMOTED, doc_comment, type);
if (attributes_ast) {
zend_compile_attributes(
&prop->attributes, attributes_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY);
}
}
}
2018-02-05 00:16:50 +00:00
/* These are assigned at the end to avoid uninitialized memory in case of an error */
op_array->num_args = list->children;
op_array->arg_info = arg_infos;
/* Don't count the variadic argument */
if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
op_array->num_args--;
2015-01-03 09:22:58 +00:00
}
zend_set_function_arg_flags((zend_function*)op_array);
for (i = 0; i < list->children; i++) {
zend_ast *param_ast = list->child[i];
bool is_ref = (param_ast->attr & ZEND_PARAM_REF) != 0;
uint32_t visibility =
param_ast->attr & (ZEND_ACC_PUBLIC|ZEND_ACC_PROTECTED|ZEND_ACC_PRIVATE);
if (!visibility) {
continue;
}
/* Emit $this->prop = $prop for promoted properties. */
zend_string *name = zend_ast_get_str(param_ast->child[1]);
znode name_node, value_node;
name_node.op_type = IS_CONST;
ZVAL_STR_COPY(&name_node.u.constant, name);
value_node.op_type = IS_CV;
value_node.u.op.var = lookup_cv(name);
zend_op *opline = zend_emit_op(NULL,
is_ref ? ZEND_ASSIGN_OBJ_REF : ZEND_ASSIGN_OBJ, NULL, &name_node);
opline->extended_value = zend_alloc_cache_slots(3);
zend_emit_op_data(&value_node);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
static void zend_compile_closure_binding(znode *closure, zend_op_array *op_array, zend_ast *uses_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(uses_ast);
uint32_t i;
2014-07-18 10:30:39 +00:00
if (!list->children) {
return;
}
if (!op_array->static_variables) {
op_array->static_variables = zend_new_array(8);
}
for (i = 0; i < list->children; ++i) {
zend_ast *var_name_ast = list->child[i];
zend_string *var_name = zval_make_interned_string(zend_ast_get_zval(var_name_ast));
uint32_t mode = var_name_ast->attr;
zend_op *opline;
zval *value;
2014-07-18 10:30:39 +00:00
if (zend_string_equals_literal(var_name, "this")) {
2014-07-18 10:30:39 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as lexical variable");
}
2014-07-18 10:30:39 +00:00
if (zend_is_auto_global(var_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use auto-global as lexical variable");
}
value = zend_hash_add(op_array->static_variables, var_name, &EG(uninitialized_zval));
if (!value) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use variable $%s twice", ZSTR_VAL(var_name));
}
CG(zend_lineno) = zend_ast_get_lineno(var_name_ast);
opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
opline->op2_type = IS_CV;
opline->op2.var = lookup_cv(var_name);
opline->extended_value =
(uint32_t)((char*)value - (char*)op_array->static_variables->arData) | mode;
}
}
/* }}} */
2014-07-18 10:30:39 +00:00
typedef struct {
HashTable uses;
bool varvars_used;
} closure_info;
static void find_implicit_binds_recursively(closure_info *info, zend_ast *ast) {
if (!ast) {
return;
}
if (ast->kind == ZEND_AST_VAR) {
zend_ast *name_ast = ast->child[0];
if (name_ast->kind == ZEND_AST_ZVAL && Z_TYPE_P(zend_ast_get_zval(name_ast)) == IS_STRING) {
zend_string *name = zend_ast_get_str(name_ast);
if (zend_is_auto_global(name)) {
/* These is no need to explicitly import auto-globals. */
return;
}
if (zend_string_equals_literal(name, "this")) {
/* $this does not need to be explicitly imported. */
return;
}
zend_hash_add_empty_element(&info->uses, name);
} else {
info->varvars_used = 1;
find_implicit_binds_recursively(info, name_ast);
}
} else if (zend_ast_is_list(ast)) {
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; i++) {
find_implicit_binds_recursively(info, list->child[i]);
}
} else if (ast->kind == ZEND_AST_CLOSURE) {
/* For normal closures add the use() list. */
zend_ast_decl *closure_ast = (zend_ast_decl *) ast;
zend_ast *uses_ast = closure_ast->child[1];
if (uses_ast) {
zend_ast_list *uses_list = zend_ast_get_list(uses_ast);
uint32_t i;
for (i = 0; i < uses_list->children; i++) {
zend_hash_add_empty_element(&info->uses, zend_ast_get_str(uses_list->child[i]));
}
}
} else if (ast->kind == ZEND_AST_ARROW_FUNC) {
/* For arrow functions recursively check the expression. */
zend_ast_decl *closure_ast = (zend_ast_decl *) ast;
find_implicit_binds_recursively(info, closure_ast->child[2]);
} else if (!zend_ast_is_special(ast)) {
uint32_t i, children = zend_ast_get_num_children(ast);
for (i = 0; i < children; i++) {
find_implicit_binds_recursively(info, ast->child[i]);
}
}
}
static void find_implicit_binds(closure_info *info, zend_ast *params_ast, zend_ast *stmt_ast)
{
zend_ast_list *param_list = zend_ast_get_list(params_ast);
uint32_t i;
2019-11-12 07:51:55 +00:00
zend_hash_init(&info->uses, param_list->children, NULL, NULL, 0);
find_implicit_binds_recursively(info, stmt_ast);
/* Remove variables that are parameters */
for (i = 0; i < param_list->children; i++) {
zend_ast *param_ast = param_list->child[i];
zend_hash_del(&info->uses, zend_ast_get_str(param_ast->child[1]));
}
}
static void compile_implicit_lexical_binds(
closure_info *info, znode *closure, zend_op_array *op_array)
{
zend_string *var_name;
zend_op *opline;
/* TODO We might want to use a special binding mode if varvars_used is set. */
if (zend_hash_num_elements(&info->uses) == 0) {
return;
}
if (!op_array->static_variables) {
op_array->static_variables = zend_new_array(8);
}
ZEND_HASH_FOREACH_STR_KEY(&info->uses, var_name)
zval *value = zend_hash_add(
op_array->static_variables, var_name, &EG(uninitialized_zval));
uint32_t offset = (uint32_t)((char*)value - (char*)op_array->static_variables->arData);
opline = zend_emit_op(NULL, ZEND_BIND_LEXICAL, closure, NULL);
opline->op2_type = IS_CV;
opline->op2.var = lookup_cv(var_name);
opline->extended_value = offset | ZEND_BIND_IMPLICIT;
ZEND_HASH_FOREACH_END();
}
static void zend_compile_closure_uses(zend_ast *ast) /* {{{ */
{
zend_op_array *op_array = CG(active_op_array);
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
uint32_t mode = ZEND_BIND_EXPLICIT;
zend_ast *var_ast = list->child[i];
zend_string *var_name = zend_ast_get_str(var_ast);
zval zv;
ZVAL_NULL(&zv);
{
int i;
for (i = 0; i < op_array->last_var; i++) {
if (zend_string_equals(op_array->vars[i], var_name)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use lexical variable $%s as a parameter name", ZSTR_VAL(var_name));
}
}
}
CG(zend_lineno) = zend_ast_get_lineno(var_ast);
if (var_ast->attr) {
mode |= ZEND_BIND_REF;
}
zend_compile_static_var_common(var_name, &zv, mode);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
static void zend_compile_implicit_closure_uses(closure_info *info)
{
zend_string *var_name;
ZEND_HASH_FOREACH_STR_KEY(&info->uses, var_name)
zval zv;
ZVAL_NULL(&zv);
zend_compile_static_var_common(var_name, &zv, ZEND_BIND_IMPLICIT);
ZEND_HASH_FOREACH_END();
}
static void add_stringable_interface(zend_class_entry *ce) {
for (uint32_t i = 0; i < ce->num_interfaces; i++) {
if (zend_string_equals_literal(ce->interface_names[i].lc_name, "stringable")) {
/* Interface already explicitly implemented */
return;
}
}
ce->num_interfaces++;
ce->interface_names =
erealloc(ce->interface_names, sizeof(zend_class_name) * ce->num_interfaces);
// TODO: Add known interned strings instead?
ce->interface_names[ce->num_interfaces - 1].name =
zend_string_init("Stringable", sizeof("Stringable") - 1, 0);
ce->interface_names[ce->num_interfaces - 1].lc_name =
zend_string_init("stringable", sizeof("stringable") - 1, 0);
}
zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name, bool has_body) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_class_entry *ce = CG(active_class_entry);
bool in_interface = (ce->ce_flags & ZEND_ACC_INTERFACE) != 0;
2019-03-06 09:42:02 +00:00
uint32_t fn_flags = op_array->fn_flags;
1999-12-26 21:21:33 +00:00
zend_string *lcname;
2003-03-05 11:14:44 +00:00
if ((fn_flags & ZEND_ACC_PRIVATE) && (fn_flags & ZEND_ACC_FINAL) && !zend_is_constructor(name)) {
zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
}
if (in_interface) {
2019-03-06 09:42:02 +00:00
if (!(fn_flags & ZEND_ACC_PUBLIC) || (fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_ABSTRACT))) {
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface method "
"%s::%s() must be omitted", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
op_array->fn_flags |= ZEND_ACC_ABSTRACT;
2003-02-11 09:48:37 +00:00
}
if (op_array->fn_flags & ZEND_ACC_ABSTRACT) {
if ((op_array->fn_flags & ZEND_ACC_PRIVATE) && !(ce->ce_flags & ZEND_ACC_TRAIT)) {
zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private",
in_interface ? "Interface" : "Abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
1999-04-07 18:10:10 +00:00
if (has_body) {
zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body",
in_interface ? "Interface" : "Abstract", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
} else if (!has_body) {
zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
1999-04-07 18:10:10 +00:00
op_array->scope = ce;
op_array->function_name = zend_string_copy(name);
lcname = zend_string_tolower(name);
2014-12-13 22:06:14 +00:00
lcname = zend_new_interned_string(lcname);
if (zend_hash_add_ptr(&ce->function_table, lcname, op_array) == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
zend_add_magic_method(ce, (zend_function *) op_array, lcname);
if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
add_stringable_interface(ce);
}
1999-04-07 18:10:10 +00:00
return lcname;
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static uint32_t zend_add_dynamic_func_def(zend_op_array *def) {
zend_op_array *op_array = CG(active_op_array);
uint32_t def_offset = op_array->num_dynamic_func_defs++;
op_array->dynamic_func_defs = erealloc(
op_array->dynamic_func_defs, op_array->num_dynamic_func_defs * sizeof(zend_op_array *));
op_array->dynamic_func_defs[def_offset] = def;
return def_offset;
}
static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_ast_decl *decl, bool toplevel) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_string *unqualified_name, *name, *lcname;
2014-07-21 13:22:13 +00:00
zend_op *opline;
2016-05-04 16:42:16 +00:00
unqualified_name = decl->name;
op_array->function_name = name = zend_prefix_with_ns(unqualified_name);
lcname = zend_string_tolower(name);
if (FC(imports_function)) {
zend_string *import_name =
zend_hash_find_ptr_lc(FC(imports_function), unqualified_name);
2015-02-11 08:03:48 +00:00
if (import_name && !zend_string_equals_ci(lcname, import_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare function %s "
"because the name is already in use", ZSTR_VAL(name));
2014-07-21 13:22:13 +00:00
}
}
if (zend_string_equals_literal(lcname, "__autoload")) {
zend_error_noreturn(E_COMPILE_ERROR,
"__autoload() is no longer supported, use spl_autoload_register() instead");
2014-07-21 13:22:13 +00:00
}
1999-04-07 18:10:10 +00:00
if (zend_string_equals_literal_ci(unqualified_name, "assert")) {
zend_error(E_COMPILE_ERROR,
"Defining a custom assert() function is not allowed, "
"as the function has special semantics");
}
zend_register_seen_symbol(lcname, ZEND_SYMBOL_FUNCTION);
if (toplevel) {
if (UNEXPECTED(zend_hash_add_ptr(CG(function_table), lcname, op_array) == NULL)) {
do_bind_function_error(lcname, op_array, 1);
}
zend_string_release_ex(lcname, 0);
return;
}
uint32_t func_ref = zend_add_dynamic_func_def(op_array);
2014-07-21 13:22:13 +00:00
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
opline->op2.num = func_ref;
2014-07-21 13:22:13 +00:00
} else {
opline = get_next_op();
2014-07-21 13:22:13 +00:00
opline->opcode = ZEND_DECLARE_FUNCTION;
opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, zend_string_copy(lcname));
opline->op2.num = func_ref;
2014-07-21 13:22:13 +00:00
}
zend_string_release_ex(lcname, 0);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_ast *params_ast = decl->child[0];
zend_ast *uses_ast = decl->child[1];
zend_ast *stmt_ast = decl->child[2];
zend_ast *return_type_ast = decl->child[3];
bool is_method = decl->kind == ZEND_AST_METHOD;
zend_string *method_lcname;
1999-04-07 18:10:10 +00:00
zend_class_entry *orig_class_entry = CG(active_class_entry);
zend_op_array *orig_op_array = CG(active_op_array);
zend_op_array *op_array = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
zend_oparray_context orig_oparray_context;
closure_info info;
memset(&info, 0, sizeof(closure_info));
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE);
1999-04-07 18:10:10 +00:00
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
op_array->fn_flags |= ZEND_ACC_PRELOADED;
}
Immutable clases and op_arrays. Squashed commit of the following: commit cd0c36c3f943849e5b97a8dbe2dd029fbeab3df9 Merge: 4740dabb84 ad6738e886 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:43:38 2018 +0300 Merge branch 'master' into immutable * master: Remove the "auto" encoding Fixed bug #77025 Add vtbls for EUC-TW encoding commit 4740dabb843c6d4f7f866b4a2456073c9eaf4c77 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 14:12:28 2018 +0300 Reverted back ce->iterator_funcs_ptr. Initialize ce->iterator_funcs_ptr fields in immutable classes. commit ad7a78b253be970db70c2251e66f9297d8e7f829 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:46:30 2018 +0300 Added comment commit 0276ea51875bab37be01a4dc5e5a047c5698c571 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:42:43 2018 +0300 Added type cast commit c63fc5d5f19c58498108d1698055b2b442227eb3 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:36:51 2018 +0300 Moved static class members initialization into the proper place. commit b945548e9306b1826c881918858b5e5aa3eb3002 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:21:03 2018 +0300 Removed redundand assertion commit d5a41088401814c829847db212488f8aae39bcd2 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:19:13 2018 +0300 Removed duplicate code commit 8dadca8864e66de70a24bdf1181bcf7dd8fb27d7 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 11:05:43 2018 +0300 Hide offset encoding magic in ZEND_MAP_PTR_IS_OFFSET(), ZEND_MAP_PTR_OFFSET2PTR() and ZEND_MAP_PTR_PTR2OFFSET() macros. commit 9ef07c88bd76801e2d4fbfeab3ebfd6e6a67ac5f Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:48:29 2018 +0300 typo commit a06f0f3d3aba53e766046221ee44fb9720389ecc Merge: 94099586ec 3412345ffe Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Oct 17 10:47:07 2018 +0300 Merge branch 'master' into immutable * master: Remove unused variable makefile_am_files Classify object handlers are required/optional Add support for getting SKIP_TAGSTART and SKIP_WHITE options Remove some obsolete config_vars.mk occurrences Remove bsd_converted from .gitignore Remove configuration parser and scanners ignores Remove obsolete buildconf.stamp from .gitignore [ci skip] Add magicdata.patch exception to .gitignore Remove outdated ext/spl/examples items from .gitignore Remove unused test.inc in ext/iconv/tests commit 94099586ec599117581ca01c15b1f6c5f749e23a Author: Dmitry Stogov <dmitry@zend.com> Date: Mon Oct 15 23:34:01 2018 +0300 Immutable clases and op_arrays
2018-10-17 12:52:50 +00:00
ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void *)));
ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL);
op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES);
op_array->fn_flags |= decl->flags;
op_array->line_start = decl->start_lineno;
op_array->line_end = decl->end_lineno;
if (decl->doc_comment) {
op_array->doc_comment = zend_string_copy(decl->doc_comment);
2014-07-18 13:23:16 +00:00
}
if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) {
op_array->fn_flags |= ZEND_ACC_CLOSURE;
}
if (is_method) {
bool has_body = stmt_ast != NULL;
method_lcname = zend_begin_method_decl(op_array, decl->name, has_body);
} else {
zend_begin_func_decl(result, op_array, decl, toplevel);
if (decl->kind == ZEND_AST_ARROW_FUNC) {
find_implicit_binds(&info, params_ast, stmt_ast);
compile_implicit_lexical_binds(&info, result, op_array);
} else if (uses_ast) {
zend_compile_closure_binding(result, op_array, uses_ast);
}
}
CG(active_op_array) = op_array;
if (decl->child[4]) {
int target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
if (is_method) {
target = ZEND_ATTRIBUTE_TARGET_METHOD;
}
zend_compile_attributes(&op_array->attributes, decl->child[4], 0, target);
}
/* Do not leak the class scope into free standing functions, even if they are dynamically
* defined inside a class method. This is necessary for correct handling of magic constants.
* For example __CLASS__ should always be "" inside a free standing function. */
if (decl->kind == ZEND_AST_FUNC_DECL) {
CG(active_class_entry) = NULL;
}
2018-10-19 10:22:29 +00:00
if (toplevel) {
op_array->fn_flags |= ZEND_ACC_TOP_LEVEL;
}
zend_oparray_context_begin(&orig_oparray_context);
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
{
/* Push a separator to the loop variable stack */
2015-07-10 11:30:25 +00:00
zend_loop_var dummy_var;
dummy_var.opcode = ZEND_RETURN;
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
zend_stack_push(&CG(loop_var_stack), (void *) &dummy_var);
}
zend_compile_params(params_ast, return_type_ast,
is_method && zend_string_equals_literal(method_lcname, ZEND_TOSTRING_FUNC_NAME) ? IS_STRING : 0);
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
zend_mark_function_as_generator();
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
}
if (decl->kind == ZEND_AST_ARROW_FUNC) {
zend_compile_implicit_closure_uses(&info);
zend_hash_destroy(&info.uses);
} else if (uses_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_closure_uses(uses_ast);
}
2014-12-13 22:06:14 +00:00
zend_compile_stmt(stmt_ast);
if (is_method) {
CG(zend_lineno) = decl->start_lineno;
zend_check_magic_method_implementation(
CG(active_class_entry), (zend_function *) op_array, method_lcname, E_COMPILE_ERROR);
zend_string_release_ex(method_lcname, 0);
}
/* put the implicit return on the really last line */
CG(zend_lineno) = decl->end_lineno;
zend_do_extended_stmt();
zend_emit_final_return(0);
zend_init_static_variables_map_ptr(op_array);
2014-12-13 22:06:14 +00:00
pass_two(CG(active_op_array));
zend_oparray_context_end(&orig_oparray_context);
Squashed commit of the following: commit 03cf871f1576f08b2348c141b209894a7bf17a86 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:31 2015 +0300 Revert "Fixed bug #62210 (Exceptions can leak temporary variables. As a part of the fix serious refactoring was done. op_array->brk_cont_array was removed, and replaced with more general and speed efficient op_array->T_liveliness. ZEND_GOTO opcode is always replaced by ZEND_JMP at compile time). (Bob, Dmitry, Laruence)" This reverts commit 5ee841325901a4b040cfea56292a24702fe224d9. commit 285a68227ce3d380e821a24fa389aa5239bd3fe1 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:26 2015 +0300 Revert "Tuned off dubugging of live ranges" This reverts commit 404dc93d35f7061fc4b1b41ad6cb0721b9b52bcc. commit 93d9d11157301ee2ec99afb6f5744b126d17f637 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:17 2015 +0300 Revert "Remove loop_var_stack" This reverts commit b3a4c05071c3786e27e1326fa1b4d5acad62fccd. commit ede68ebbc284aec79e3f719f2c8dbf9da6907752 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:12 2015 +0300 Revert "ZEND_SEPARATE reuses temporaries" This reverts commit 1852f538b9f8d5e7d67fe5a4f6080396d8b10034. commit 96d8995dc1f517fb01b481736273767509f76c47 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:10 2015 +0300 Revert "Add assertion in liveliness computation" This reverts commit ed14019e8c0c852480eebc6fc552d8c3d939dce1. commit 0649d7bfef152e6cc8e67b922534e9946c634d9c Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:07 2015 +0300 Revert "Fixed invalid live-range detection" This reverts commit 54f367ee2a2e4cb7c952b17915c226fdc56038ab. commit dfe8f3851f6b04595eb089323e3492115a59363e Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:04 2015 +0300 Revert "Add test guaranteeing that loop vars are only freed after potential return type exceptions" This reverts commit f5db5a558d550bf441373febebbb02f3884209d1. commit 52a94aad6f48a199358cc07f7e4f56bb73050504 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:45:01 2015 +0300 Revert "Fixed exception habdling on "return" statement." This reverts commit 17c5315bdf8f8087979aeb55f6d3a512ba197cf5. commit 6e90ad7331901711e89c2ceb2bcab5023e5cee60 Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:58 2015 +0300 Revert "Fix too early terminated temporary range with break/cont/goto" This reverts commit cc876c04b420589cb1f62b650d0c0e24975dd4af. commit 7b766e44b1970e4031f75109c302c07ead2c05cb Author: Dmitry Stogov <dmitry@zend.com> Date: Fri Jul 10 02:44:55 2015 +0300 Revert "Fixed exception catching on break/continue" This reverts commit 8c3f701eebfa92d761bb368cfa8c2d1ccf821b9d.
2015-07-10 00:31:52 +00:00
/* Pop the loop variable stack separator */
zend_stack_del_top(&CG(loop_var_stack));
2014-07-18 10:58:24 +00:00
CG(active_op_array) = orig_op_array;
CG(active_class_entry) = orig_class_entry;
2014-07-18 10:58:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t flags, zend_ast *attr_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
2014-07-19 12:54:56 +00:00
zend_class_entry *ce = CG(active_class_entry);
uint32_t i, children = list->children;
2014-07-19 12:54:56 +00:00
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
zend_error_noreturn(E_COMPILE_ERROR, "Interfaces may not include properties");
}
if (ce->ce_flags & ZEND_ACC_ENUM) {
zend_error_noreturn(E_COMPILE_ERROR, "Enums may not include properties");
1999-04-07 18:10:10 +00:00
}
2014-07-19 12:54:56 +00:00
if (flags & ZEND_ACC_ABSTRACT) {
zend_error_noreturn(E_COMPILE_ERROR, "Properties cannot be declared abstract");
}
2014-07-30 17:12:48 +00:00
for (i = 0; i < children; ++i) {
zend_property_info *info;
zend_ast *prop_ast = list->child[i];
2014-07-19 12:54:56 +00:00
zend_ast *name_ast = prop_ast->child[0];
zend_ast **value_ast_ptr = &prop_ast->child[1];
2015-10-06 20:32:23 +00:00
zend_ast *doc_comment_ast = prop_ast->child[2];
zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
2015-10-06 20:32:23 +00:00
zend_string *doc_comment = NULL;
2014-07-19 12:54:56 +00:00
zval value_zv;
zend_type type = ZEND_TYPE_INIT_NONE(0);
if (type_ast) {
type = zend_compile_typename(type_ast, /* force_allow_null */ 0);
if (ZEND_TYPE_FULL_MASK(type) & (MAY_BE_VOID|MAY_BE_NEVER|MAY_BE_CALLABLE)) {
zend_string *str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Property %s::$%s cannot have type %s",
ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str));
}
}
1999-04-07 18:10:10 +00:00
2015-10-06 20:32:23 +00:00
/* Doc comment has been appended as last element in ZEND_AST_PROP_ELEM ast */
if (doc_comment_ast) {
doc_comment = zend_string_copy(zend_ast_get_str(doc_comment_ast));
}
2014-07-19 12:54:56 +00:00
if (flags & ZEND_ACC_FINAL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, "
"the final modifier is allowed only for methods and classes",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
2014-07-19 12:54:56 +00:00
}
1999-04-07 18:10:10 +00:00
2014-07-19 12:54:56 +00:00
if (zend_hash_exists(&ce->properties_info, name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::$%s",
ZSTR_VAL(ce->name), ZSTR_VAL(name));
2014-07-19 12:54:56 +00:00
}
if (*value_ast_ptr) {
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
if (ZEND_TYPE_IS_SET(type) && !Z_CONSTANT(value_zv)
&& !zend_is_valid_default_value(type, &value_zv)) {
zend_string *str = zend_type_to_string(type);
if (Z_TYPE(value_zv) == IS_NULL) {
ZEND_TYPE_FULL_MASK(type) |= MAY_BE_NULL;
zend_string *nullable_str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Default value for property of type %s may not be null. "
"Use the nullable type %s to allow null default value",
ZSTR_VAL(str), ZSTR_VAL(nullable_str));
} else {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use %s as default value for property %s::$%s of type %s",
zend_zval_type_name(&value_zv),
ZSTR_VAL(ce->name), ZSTR_VAL(name), ZSTR_VAL(str));
}
}
} else if (!ZEND_TYPE_IS_SET(type)) {
2014-07-19 12:54:56 +00:00
ZVAL_NULL(&value_zv);
} else {
ZVAL_UNDEF(&value_zv);
1999-04-07 18:10:10 +00:00
}
info = zend_declare_typed_property(ce, name, &value_zv, flags, doc_comment, type);
if (attr_ast) {
zend_compile_attributes(&info->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_PROPERTY);
}
1999-04-07 18:10:10 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
void zend_compile_prop_group(zend_ast *ast) /* {{{ */
{
zend_ast *type_ast = ast->child[0];
zend_ast *prop_ast = ast->child[1];
zend_ast *attr_ast = ast->child[2];
zend_compile_prop_decl(prop_ast, type_ast, ast->attr, attr_ast);
}
/* }}} */
2019-03-06 09:42:02 +00:00
static void zend_check_const_and_trait_alias_attr(uint32_t attr, const char* entity) /* {{{ */
{
if (attr & ZEND_ACC_STATIC) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'static' as %s modifier", entity);
} else if (attr & ZEND_ACC_ABSTRACT) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'abstract' as %s modifier", entity);
} else if (attr & ZEND_ACC_FINAL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use 'final' as %s modifier", entity);
}
}
/* }}} */
void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
2014-07-19 13:13:50 +00:00
zend_class_entry *ce = CG(active_class_entry);
uint32_t i, children = list->children;
if ((ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
zend_error_noreturn(E_COMPILE_ERROR, "Traits cannot have constants");
return;
}
for (i = 0; i < children; ++i) {
zend_class_constant *c;
zend_ast *const_ast = list->child[i];
2014-07-19 13:13:50 +00:00
zend_ast *name_ast = const_ast->child[0];
zend_ast **value_ast_ptr = &const_ast->child[1];
zend_ast *doc_comment_ast = const_ast->child[2];
zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
2014-07-19 13:13:50 +00:00
zval value_zv;
if (UNEXPECTED(flags & (ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_FINAL))) {
zend_check_const_and_trait_alias_attr(flags, "constant");
2015-05-25 20:58:30 +00:00
}
zend_const_expr_to_zval(&value_zv, value_ast_ptr);
c = zend_declare_class_constant_ex(ce, name, &value_zv, flags, doc_comment);
if (attr_ast) {
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
}
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_class_const_group(zend_ast *ast) /* {{{ */
{
zend_ast *const_ast = ast->child[0];
zend_ast *attr_ast = ast->child[1];
zend_compile_class_const_decl(const_ast, ast->attr, attr_ast);
}
/* }}} */
static void zend_compile_method_ref(zend_ast *ast, zend_trait_method_reference *method_ref) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast *class_ast = ast->child[0];
zend_ast *method_ast = ast->child[1];
1999-04-07 18:10:10 +00:00
method_ref->method_name = zend_string_copy(zend_ast_get_str(method_ast));
2014-07-19 20:39:01 +00:00
if (class_ast) {
method_ref->class_name = zend_resolve_const_class_name_reference(class_ast, "trait name");
2014-07-19 20:39:01 +00:00
} else {
method_ref->class_name = NULL;
1999-04-07 18:10:10 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast *method_ref_ast = ast->child[0];
zend_ast *insteadof_ast = ast->child[1];
zend_ast_list *insteadof_list = zend_ast_get_list(insteadof_ast);
uint32_t i;
zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence) + (insteadof_list->children - 1) * sizeof(zend_string*));
zend_compile_method_ref(method_ref_ast, &precedence->trait_method);
precedence->num_excludes = insteadof_list->children;
2015-01-03 09:22:58 +00:00
for (i = 0; i < insteadof_list->children; ++i) {
zend_ast *name_ast = insteadof_list->child[i];
precedence->exclude_class_names[i] =
zend_resolve_const_class_name_reference(name_ast, "trait name");
}
2014-07-19 20:39:01 +00:00
2014-12-13 22:06:14 +00:00
zend_add_to_list(&CG(active_class_entry)->trait_precedences, precedence);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-19 20:39:01 +00:00
zend_ast *method_ref_ast = ast->child[0];
zend_ast *alias_ast = ast->child[1];
uint32_t modifiers = ast->attr;
2014-07-19 20:39:01 +00:00
zend_trait_alias *alias;
2019-03-06 09:42:02 +00:00
zend_check_const_and_trait_alias_attr(modifiers, "method");
2014-07-19 20:39:01 +00:00
alias = emalloc(sizeof(zend_trait_alias));
zend_compile_method_ref(method_ref_ast, &alias->trait_method);
2014-07-19 20:39:01 +00:00
alias->modifiers = modifiers;
if (alias_ast) {
alias->alias = zend_string_copy(zend_ast_get_str(alias_ast));
2014-07-19 20:39:01 +00:00
} else {
alias->alias = NULL;
}
2014-12-13 22:06:14 +00:00
zend_add_to_list(&CG(active_class_entry)->trait_aliases, alias);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_use_trait(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *traits = zend_ast_get_list(ast->child[0]);
zend_ast_list *adaptations = ast->child[1] ? zend_ast_get_list(ast->child[1]) : NULL;
2014-07-19 20:39:01 +00:00
zend_class_entry *ce = CG(active_class_entry);
uint32_t i;
1999-04-07 18:10:10 +00:00
ce->trait_names = erealloc(ce->trait_names, sizeof(zend_class_name) * (ce->num_traits + traits->children));
for (i = 0; i < traits->children; ++i) {
zend_ast *trait_ast = traits->child[i];
2014-07-19 20:39:01 +00:00
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2020-01-13 11:44:16 +00:00
zend_string *name = zend_ast_get_str(trait_ast);
2014-07-19 20:39:01 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use traits inside of interfaces. "
"%s is used in %s", ZSTR_VAL(name), ZSTR_VAL(ce->name));
1999-04-07 18:10:10 +00:00
}
2014-07-19 20:39:01 +00:00
2020-01-13 11:44:16 +00:00
ce->trait_names[ce->num_traits].name =
zend_resolve_const_class_name_reference(trait_ast, "trait name");
ce->trait_names[ce->num_traits].lc_name = zend_string_tolower(ce->trait_names[ce->num_traits].name);
2014-07-19 20:39:01 +00:00
ce->num_traits++;
1999-04-07 18:10:10 +00:00
}
if (!adaptations) {
2014-07-19 20:39:01 +00:00
return;
}
for (i = 0; i < adaptations->children; ++i) {
zend_ast *adaptation_ast = adaptations->child[i];
2014-07-19 20:39:01 +00:00
switch (adaptation_ast->kind) {
case ZEND_AST_TRAIT_PRECEDENCE:
2014-12-13 22:06:14 +00:00
zend_compile_trait_precedence(adaptation_ast);
2014-07-19 20:39:01 +00:00
break;
case ZEND_AST_TRAIT_ALIAS:
2014-12-13 22:06:14 +00:00
zend_compile_trait_alias(adaptation_ast);
2014-07-19 20:39:01 +00:00
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
void zend_compile_implements(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
zend_class_entry *ce = CG(active_class_entry);
zend_class_name *interface_names;
uint32_t i;
interface_names = emalloc(sizeof(zend_class_name) * list->children);
for (i = 0; i < list->children; ++i) {
zend_ast *class_ast = list->child[i];
interface_names[i].name =
zend_resolve_const_class_name_reference(class_ast, "interface name");
interface_names[i].lc_name = zend_string_tolower(interface_names[i].name);
}
ce->num_interfaces = list->children;
ce->interface_names = interface_names;
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
static zend_string *zend_generate_anon_class_name(zend_ast_decl *decl)
{
zend_string *filename = CG(active_op_array)->filename;
uint32_t start_lineno = decl->start_lineno;
/* Use parent or first interface as prefix. */
zend_string *prefix = ZSTR_KNOWN(ZEND_STR_CLASS);
if (decl->child[0]) {
prefix = zend_resolve_const_class_name_reference(decl->child[0], "class name");
} else if (decl->child[1]) {
zend_ast_list *list = zend_ast_get_list(decl->child[1]);
prefix = zend_resolve_const_class_name_reference(list->child[0], "interface name");
}
zend_string *result = zend_strpprintf(0, "%s@anonymous%c%s:%" PRIu32 "$%" PRIx32,
ZSTR_VAL(prefix), '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
zend_string_release(prefix);
return zend_new_interned_string(result);
}
static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_backing_type_ast)
{
ZEND_ASSERT(ce->ce_flags & ZEND_ACC_ENUM);
zend_type type = zend_compile_typename(enum_backing_type_ast, 0);
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
if (ZEND_TYPE_HAS_CLASS(type) || (type_mask != MAY_BE_LONG && type_mask != MAY_BE_STRING)) {
zend_string *type_string = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
"Enum backing type must be int or string, %s given",
ZSTR_VAL(type_string));
}
if (type_mask == MAY_BE_LONG) {
ce->enum_backing_type = IS_LONG;
} else {
ZEND_ASSERT(type_mask == MAY_BE_STRING);
ce->enum_backing_type = IS_STRING;
}
zend_type_release(type, 0);
ce->backed_enum_table = emalloc(sizeof(HashTable));
zend_hash_init(ce->backed_enum_table, 0, NULL, ZVAL_PTR_DTOR, 0);
}
void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-21 14:34:45 +00:00
zend_ast_decl *decl = (zend_ast_decl *) ast;
zend_ast *extends_ast = decl->child[0];
zend_ast *implements_ast = decl->child[1];
zend_ast *stmt_ast = decl->child[2];
zend_ast *enum_backing_type_ast = decl->child[4];
2016-05-04 16:42:16 +00:00
zend_string *name, *lcname;
zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry));
2014-07-21 14:34:45 +00:00
zend_op *opline;
2015-04-26 14:03:58 +00:00
zend_class_entry *original_ce = CG(active_class_entry);
2015-04-26 13:28:55 +00:00
2015-06-13 02:56:30 +00:00
if (EXPECTED((decl->flags & ZEND_ACC_ANON_CLASS) == 0)) {
2016-05-04 16:42:16 +00:00
zend_string *unqualified_name = decl->name;
if (CG(active_class_entry)) {
zend_error_noreturn(E_COMPILE_ERROR, "Class declarations may not be nested");
}
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
2016-05-04 16:42:16 +00:00
zend_assert_valid_class_name(unqualified_name);
name = zend_prefix_with_ns(unqualified_name);
name = zend_new_interned_string(name);
lcname = zend_string_tolower(name);
Implemented Traits for PHP as proposed in the RFC [TRAITS] # RFC http://wiki.php.net/rfc/horizontalreuse#traits_-_reuse_of_behavior # Ok, here we go, I guess that will result in more discussion, which is fine # by me. But now, the patch is here, and properly archived. # # See below a list of notes to the patch, it also includes a list of # points which should be fixed # # Internals of the Traits Patch # ----------------------------- # # Open TODOs # """""""""" # # - Reflection API # - support for traits for internal classes # - currently destroy_zend_class does not handle that case # # Introduced Structures # """"""""""""""""""""" # # Data structures to encode the composition information specified in the # source: # - zend_trait_method_reference # - zend_trait_precedence # - zend_trait_alias # # Changes # """"""" # # zend_class_entry # - uses NULL terminated lists of pointers for # - trait_aliases # - trait_precedences # - do you prefer an explicit counter? # - the information is only necessary during class composition # but might be interesting for reflection # - did not want to blow up class further with not really necessary length counters # # added keywords # - trait # - insteadof # # Added opcodes # ZEND_ADD_TRAIT # - similar to ZEND_ADD_INTERFACE # - adds the trait to the list of traits of a class, no actual composition done # ZEND_BIND_TRAITS # - emitted in zend_do_end_class_declaration # - concludes the class definition and will initiate the trait composition # when the class definition is encountered during runtime # # Added Flags # ZEND_ACC_TRAIT = 0x120 # ZEND_ACC_IMPLEMENT_TRAITS = 0x400000 # ZEND_FETCH_CLASS_TRAIT = 14 # # zend_vm_execute.h # - not sure whether the handler initialization (ZEND_ADD_TRAIT_SPEC_HANDLER, # ZEND_BIND_TRAITS_SPEC_HANDLER) is correct, maybe it should be more selective # # zend_compile.c # - refactored do_inherit_method_check # split into do_inherit_method_check and do_inheritance_check_on_method # - added helper functions use a '_' as prefix and are not mentioned in the # headers # - _copy_functions # prepare hash-maps of functions which should be merged into a class # here the aliases are handled # - _merge_functions # builds a hash-table of the methods which need to be added to a class # does the conflict detection # - reused php_runkit_function_copy_ctor # - it is not identical with the original code anymore, needed to update it # think I fixed some bugs, not sure whether all have been reported back to runkit # - has to be renamed, left the name for the moment, to make its origin obvious # - here might be optimization potential # - not sure whether everything needs to be copied # - copying the literals might be broken # - added it since the literals array is freed by efree and gave problems # with doubled frees # - all immutable parts of the zend_op array should not be copied # - am not sure which parts are immutable # - and not sure how to avoid doubled frees on the same arrays on shutdown # - _merge_functions_to_class # does the final merging with the target class to handle inherited # and overridden methods # - small helper for NULL terminated lists # zend_init_list, zend_add_to_list # # zend_language_parser.y # - reused class definition for traits # - there should be something with regard to properties # - if they get explicitly defined, it might be worthwhile to # check that there are no collisions with other traits in a composition # (however, I would not introduce elaborate language features to control that # but a notice for such conflicts might be nice to the developers)
2010-04-22 22:05:56 +00:00
if (FC(imports)) {
zend_string *import_name =
zend_hash_find_ptr_lc(FC(imports), unqualified_name);
2016-05-04 16:42:16 +00:00
if (import_name && !zend_string_equals_ci(lcname, import_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare class %s "
"because the name is already in use", ZSTR_VAL(name));
}
}
zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS);
} else {
/* Find an anon class name that is not in use yet. */
name = NULL;
lcname = NULL;
do {
zend_tmp_string_release(name);
zend_tmp_string_release(lcname);
name = zend_generate_anon_class_name(decl);
lcname = zend_string_tolower(name);
} while (zend_hash_exists(CG(class_table), lcname));
2014-07-21 14:34:45 +00:00
}
lcname = zend_new_interned_string(lcname);
2014-07-21 14:34:45 +00:00
ce->type = ZEND_USER_CLASS;
2014-07-24 19:07:37 +00:00
ce->name = name;
zend_initialize_class_data(ce, 1);
2014-07-21 14:34:45 +00:00
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
ce->ce_flags |= ZEND_ACC_PRELOADED;
ZEND_MAP_PTR_NEW(ce->static_members_table);
}
2014-07-21 14:34:45 +00:00
ce->ce_flags |= decl->flags;
ce->info.user.filename = zend_string_copy(zend_get_compiled_filename());
2014-07-21 14:34:45 +00:00
ce->info.user.line_start = decl->start_lineno;
ce->info.user.line_end = decl->end_lineno;
2014-07-21 14:34:45 +00:00
if (decl->doc_comment) {
ce->info.user.doc_comment = zend_string_copy(decl->doc_comment);
1999-04-07 18:10:10 +00:00
}
2015-06-13 02:56:30 +00:00
if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) {
/* Serialization is not supported for anonymous classes */
ce->serialize = zend_class_serialize_deny;
ce->unserialize = zend_class_unserialize_deny;
}
2014-07-21 14:34:45 +00:00
if (extends_ast) {
ce->parent_name =
zend_resolve_const_class_name_reference(extends_ast, "class name");
2008-01-23 17:55:55 +00:00
}
2014-07-21 14:34:45 +00:00
CG(active_class_entry) = ce;
if (decl->child[3]) {
zend_compile_attributes(&ce->attributes, decl->child[3], 0, ZEND_ATTRIBUTE_TARGET_CLASS);
}
if (implements_ast) {
zend_compile_implements(implements_ast);
}
if (ce->ce_flags & ZEND_ACC_ENUM) {
if (enum_backing_type_ast != NULL) {
zend_compile_enum_backing_type(ce, enum_backing_type_ast);
}
zend_enum_add_interfaces(ce);
zend_enum_register_props(ce);
}
zend_compile_stmt(stmt_ast);
2014-07-21 14:34:45 +00:00
/* Reset lineno for final opcodes and errors */
CG(zend_lineno) = ast->lineno;
2018-08-27 13:40:25 +00:00
if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
zend_verify_abstract_class(ce);
}
1999-04-07 18:10:10 +00:00
2015-04-26 14:03:58 +00:00
CG(active_class_entry) = original_ce;
2018-10-17 13:12:46 +00:00
if (toplevel) {
ce->ce_flags |= ZEND_ACC_TOP_LEVEL;
}
/* We currently don't early-bind classes that implement interfaces or use traits */
if (!ce->num_interfaces && !ce->num_traits
&& !(CG(compiler_options) & ZEND_COMPILE_WITHOUT_EXECUTION)) {
if (toplevel) {
if (extends_ast) {
zend_class_entry *parent_ce = zend_lookup_class_ex(
ce->parent_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
if (parent_ce
&& ((parent_ce->type != ZEND_INTERNAL_CLASS) || !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES))
&& ((parent_ce->type != ZEND_USER_CLASS) || !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES) || (parent_ce->info.user.filename == ce->info.user.filename))) {
CG(zend_lineno) = decl->end_lineno;
if (zend_try_early_bind(ce, parent_ce, lcname, NULL)) {
CG(zend_lineno) = ast->lineno;
zend_string_release(lcname);
return;
}
CG(zend_lineno) = ast->lineno;
}
} else if (EXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL)) {
zend_string_release(lcname);
zend_build_properties_info_table(ce);
ce->ce_flags |= ZEND_ACC_LINKED;
return;
}
} else if (!extends_ast) {
/* Link unbound simple class */
2019-03-06 09:42:02 +00:00
zend_build_properties_info_table(ce);
ce->ce_flags |= ZEND_ACC_LINKED;
}
}
opline = get_next_op();
if (ce->parent_name) {
/* Lowercased parent name */
zend_string *lc_parent_name = zend_string_tolower(ce->parent_name);
opline->op2_type = IS_CONST;
LITERAL_STR(opline->op2, lc_parent_name);
}
opline->op1_type = IS_CONST;
LITERAL_STR(opline->op1, lcname);
if (decl->flags & ZEND_ACC_ANON_CLASS) {
opline->opcode = ZEND_DECLARE_ANON_CLASS;
opline->extended_value = zend_alloc_cache_slot();
zend_make_var_result(result, opline);
2018-09-19 09:22:58 +00:00
if (!zend_hash_add_ptr(CG(class_table), lcname, ce)) {
/* We checked above that the class name is not used. This really shouldn't happen. */
zend_error_noreturn(E_ERROR,
"Runtime definition key collision for %s. This is a bug", ZSTR_VAL(name));
}
} else {
/* Generate RTD keys until we find one that isn't in use yet. */
zend_string *key = NULL;
do {
zend_tmp_string_release(key);
key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
} while (!zend_hash_add_ptr(CG(class_table), key, ce));
/* RTD key is placed after lcname literal in op1 */
zend_add_literal_string(&key);
opline->opcode = ZEND_DECLARE_CLASS;
if (extends_ast && toplevel
&& (CG(compiler_options) & ZEND_COMPILE_DELAYED_BINDING)
/* We currently don't early-bind classes that implement interfaces or use traits */
&& !ce->num_interfaces && !ce->num_traits
) {
CG(active_op_array)->fn_flags |= ZEND_ACC_EARLY_BINDING;
opline->opcode = ZEND_DECLARE_CLASS_DELAYED;
opline->extended_value = zend_alloc_cache_slot();
opline->result_type = IS_UNUSED;
opline->result.opline_num = -1;
}
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static void zend_compile_enum_case(zend_ast *ast)
{
zend_class_entry *enum_class = CG(active_class_entry);
if (!(enum_class->ce_flags & ZEND_ACC_ENUM)) {
zend_error_noreturn(E_COMPILE_ERROR, "Case can only be used in enums");
}
zend_string *enum_case_name = zval_make_interned_string(zend_ast_get_zval(ast->child[0]));
zend_string *enum_class_name = enum_class->name;
zval class_name_zval;
ZVAL_STR_COPY(&class_name_zval, enum_class_name);
zend_ast *class_name_ast = zend_ast_create_zval(&class_name_zval);
zval case_name_zval;
ZVAL_STR_COPY(&case_name_zval, enum_case_name);
zend_ast *case_name_ast = zend_ast_create_zval(&case_name_zval);
zend_ast *case_value_zval_ast = NULL;
zend_ast *case_value_ast = ast->child[1];
if (enum_class->enum_backing_type != IS_UNDEF && case_value_ast == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of backed enum %s must have a value",
ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name));
}
if (case_value_ast != NULL) {
zend_eval_const_expr(&ast->child[1]);
case_value_ast = ast->child[1];
if (case_value_ast->kind != ZEND_AST_ZVAL) {
zend_error_noreturn(E_COMPILE_ERROR, "Enum case value must be constant");
}
zval case_value_zv;
ZVAL_COPY(&case_value_zv, zend_ast_get_zval(case_value_ast));
if (enum_class->enum_backing_type == IS_UNDEF) {
if (Z_TYPE(case_value_zv) == IS_LONG || Z_TYPE(case_value_zv) == IS_STRING) {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value, try adding \": %s\" to the enum declaration",
ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name),
zend_zval_type_name(&case_value_zv));
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Case %s of non-backed enum %s must not have a value",
ZSTR_VAL(enum_case_name),
ZSTR_VAL(enum_class_name));
}
}
if (enum_class->enum_backing_type != Z_TYPE(case_value_zv)) {
zend_error_noreturn(E_COMPILE_ERROR, "Enum case type %s does not match enum backing type %s",
zend_get_type_by_const(Z_TYPE(case_value_zv)),
zend_get_type_by_const(enum_class->enum_backing_type));
}
case_value_zval_ast = zend_ast_create_zval(&case_value_zv);
Z_TRY_ADDREF(case_name_zval);
if (enum_class->enum_backing_type == IS_LONG) {
zend_long long_key = Z_LVAL(case_value_zv);
zval *existing_case_name = zend_hash_index_find(enum_class->backed_enum_table, long_key);
if (existing_case_name) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(enum_case_name));
}
zend_hash_index_add_new(enum_class->backed_enum_table, long_key, &case_name_zval);
} else {
ZEND_ASSERT(enum_class->enum_backing_type == IS_STRING);
zend_string *string_key = Z_STR(case_value_zv);
zval *existing_case_name = zend_hash_find(enum_class->backed_enum_table, string_key);
if (existing_case_name != NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate value in enum %s for cases %s and %s",
ZSTR_VAL(enum_class_name),
Z_STRVAL_P(existing_case_name),
ZSTR_VAL(enum_case_name));
}
zend_hash_add_new(enum_class->backed_enum_table, string_key, &case_name_zval);
}
}
zend_ast *const_enum_init_ast = zend_ast_create(ZEND_AST_CONST_ENUM_INIT, class_name_ast, case_name_ast, case_value_zval_ast);
zval value_zv;
zend_const_expr_to_zval(&value_zv, &const_enum_init_ast);
/* Doc comment has been appended as second last element in ZEND_AST_ENUM ast - attributes are conventionally last */
zend_ast *doc_comment_ast = ast->child[2];
zend_string *doc_comment = NULL;
if (doc_comment_ast) {
doc_comment = zend_string_copy(zend_ast_get_str(doc_comment_ast));
}
zend_class_constant *c = zend_declare_class_constant_ex(enum_class, enum_case_name, &value_zv, ZEND_ACC_PUBLIC, doc_comment);
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_CLASS_CONST_IS_CASE;
zend_ast_destroy(const_enum_init_ast);
zend_ast *attr_ast = ast->child[3];
if (attr_ast) {
zend_compile_attributes(&c->attributes, attr_ast, 0, ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
}
}
2014-12-13 22:06:14 +00:00
static HashTable *zend_get_import_ht(uint32_t type) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-21 21:41:11 +00:00
switch (type) {
case ZEND_SYMBOL_CLASS:
if (!FC(imports)) {
FC(imports) = emalloc(sizeof(HashTable));
zend_hash_init(FC(imports), 8, NULL, str_dtor, 0);
2014-07-21 21:41:11 +00:00
}
return FC(imports);
case ZEND_SYMBOL_FUNCTION:
if (!FC(imports_function)) {
FC(imports_function) = emalloc(sizeof(HashTable));
zend_hash_init(FC(imports_function), 8, NULL, str_dtor, 0);
2014-07-21 21:41:11 +00:00
}
return FC(imports_function);
case ZEND_SYMBOL_CONST:
if (!FC(imports_const)) {
FC(imports_const) = emalloc(sizeof(HashTable));
zend_hash_init(FC(imports_const), 8, NULL, str_dtor, 0);
2014-07-21 21:41:11 +00:00
}
return FC(imports_const);
2014-07-21 21:41:11 +00:00
EMPTY_SWITCH_DEFAULT_CASE()
}
return NULL;
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-08-29 05:05:58 +00:00
static char *zend_get_use_type_str(uint32_t type) /* {{{ */
{
2014-07-21 21:41:11 +00:00
switch (type) {
case ZEND_SYMBOL_CLASS:
2014-07-21 21:41:11 +00:00
return "";
case ZEND_SYMBOL_FUNCTION:
2014-07-21 21:41:11 +00:00
return " function";
case ZEND_SYMBOL_CONST:
2014-07-21 21:41:11 +00:00
return " const";
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-07 18:10:10 +00:00
}
return " unknown";
2014-07-21 21:41:11 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-21 21:41:11 +00:00
2014-08-29 05:05:58 +00:00
static void zend_check_already_in_use(uint32_t type, zend_string *old_name, zend_string *new_name, zend_string *check_name) /* {{{ */
{
2015-02-11 08:03:48 +00:00
if (zend_string_equals_ci(old_name, check_name)) {
2014-07-28 20:16:24 +00:00
return;
2010-12-01 13:33:49 +00:00
}
2014-07-21 21:41:11 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use%s %s as %s because the name "
"is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name));
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_use(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
zend_string *current_ns = FC(current_namespace);
uint32_t type = ast->attr;
2014-12-13 22:06:14 +00:00
HashTable *current_import = zend_get_import_ht(type);
bool case_sensitive = type == ZEND_SYMBOL_CONST;
2014-07-21 20:49:31 +00:00
for (i = 0; i < list->children; ++i) {
zend_ast *use_ast = list->child[i];
2014-07-21 20:49:31 +00:00
zend_ast *old_name_ast = use_ast->child[0];
zend_ast *new_name_ast = use_ast->child[1];
2014-07-28 13:16:35 +00:00
zend_string *old_name = zend_ast_get_str(old_name_ast);
2014-07-21 21:41:11 +00:00
zend_string *new_name, *lookup_name;
2014-07-21 20:49:31 +00:00
if (new_name_ast) {
new_name = zend_string_copy(zend_ast_get_str(new_name_ast));
2014-07-21 20:49:31 +00:00
} else {
const char *unqualified_name;
size_t unqualified_name_len;
if (zend_get_unqualified_name(old_name, &unqualified_name, &unqualified_name_len)) {
2015-01-18 14:46:32 +00:00
/* The form "use A\B" is equivalent to "use A\B as B" */
new_name = zend_string_init(unqualified_name, unqualified_name_len, 0);
2014-07-21 20:49:31 +00:00
} else {
new_name = zend_string_copy(old_name);
1999-04-07 18:10:10 +00:00
2014-07-21 20:49:31 +00:00
if (!current_ns) {
zend_error(E_WARNING, "The use statement with non-compound name '%s' "
"has no effect", ZSTR_VAL(new_name));
2014-07-21 20:49:31 +00:00
}
}
}
1999-04-07 18:10:10 +00:00
2014-07-21 21:41:11 +00:00
if (case_sensitive) {
lookup_name = zend_string_copy(new_name);
2014-07-21 21:41:11 +00:00
} else {
lookup_name = zend_string_tolower(new_name);
2014-07-21 21:41:11 +00:00
}
1999-04-07 18:10:10 +00:00
if (type == ZEND_SYMBOL_CLASS && zend_is_reserved_class_name(new_name)) {
2014-07-21 20:49:31 +00:00
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use %s as %s because '%s' "
"is a special class name", ZSTR_VAL(old_name), ZSTR_VAL(new_name), ZSTR_VAL(new_name));
}
1999-04-07 18:10:10 +00:00
2014-07-21 20:49:31 +00:00
if (current_ns) {
zend_string *ns_name = zend_string_alloc(ZSTR_LEN(current_ns) + 1 + ZSTR_LEN(new_name), 0);
zend_str_tolower_copy(ZSTR_VAL(ns_name), ZSTR_VAL(current_ns), ZSTR_LEN(current_ns));
ZSTR_VAL(ns_name)[ZSTR_LEN(current_ns)] = '\\';
2017-12-01 14:00:11 +00:00
memcpy(ZSTR_VAL(ns_name) + ZSTR_LEN(current_ns) + 1, ZSTR_VAL(lookup_name), ZSTR_LEN(lookup_name) + 1);
1999-04-07 18:10:10 +00:00
if (zend_have_seen_symbol(ns_name, type)) {
2014-07-21 21:41:11 +00:00
zend_check_already_in_use(type, old_name, new_name, ns_name);
2014-07-21 20:49:31 +00:00
}
zend_string_efree(ns_name);
2019-03-06 09:42:02 +00:00
} else if (zend_have_seen_symbol(lookup_name, type)) {
zend_check_already_in_use(type, old_name, new_name, lookup_name);
}
zend_string_addref(old_name);
old_name = zend_new_interned_string(old_name);
2014-07-21 21:41:11 +00:00
if (!zend_hash_add_ptr(current_import, lookup_name, old_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use%s %s as %s because the name "
"is already in use", zend_get_use_type_str(type), ZSTR_VAL(old_name), ZSTR_VAL(new_name));
2014-07-21 20:49:31 +00:00
}
zend_string_release_ex(lookup_name, 0);
zend_string_release_ex(new_name, 0);
}
2014-07-21 20:49:31 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_group_use(zend_ast *ast) /* {{{ */
{
2015-03-08 16:01:55 +00:00
uint32_t i;
zend_string *ns = zend_ast_get_str(ast->child[0]);
zend_ast_list *list = zend_ast_get_list(ast->child[1]);
for (i = 0; i < list->children; i++) {
2015-03-08 16:01:55 +00:00
zend_ast *inline_use, *use = list->child[i];
zval *name_zval = zend_ast_get_zval(use->child[0]);
zend_string *name = Z_STR_P(name_zval);
zend_string *compound_ns = zend_concat_names(ZSTR_VAL(ns), ZSTR_LEN(ns), ZSTR_VAL(name), ZSTR_LEN(name));
zend_string_release_ex(name, 0);
ZVAL_STR(name_zval, compound_ns);
inline_use = zend_ast_create_list(1, ZEND_AST_USE, use);
inline_use->attr = ast->attr ? ast->attr : use->attr;
zend_compile_use(inline_use);
}
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_const_decl(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
zend_ast *const_ast = list->child[i];
2014-07-22 09:55:07 +00:00
zend_ast *name_ast = const_ast->child[0];
zend_ast **value_ast_ptr = &const_ast->child[1];
2016-05-04 16:42:16 +00:00
zend_string *unqualified_name = zend_ast_get_str(name_ast);
2016-05-04 16:42:16 +00:00
zend_string *name;
2014-07-22 09:55:07 +00:00
znode name_node, value_node;
zval *value_zv = &value_node.u.constant;
value_node.op_type = IS_CONST;
zend_const_expr_to_zval(value_zv, value_ast_ptr);
2014-07-22 09:55:07 +00:00
if (zend_get_special_const(ZSTR_VAL(unqualified_name), ZSTR_LEN(unqualified_name))) {
2016-05-04 16:42:16 +00:00
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot redeclare constant '%s'", ZSTR_VAL(unqualified_name));
}
2016-05-04 16:42:16 +00:00
name = zend_prefix_with_ns(unqualified_name);
2014-12-13 22:06:14 +00:00
name = zend_new_interned_string(name);
2014-07-22 09:55:07 +00:00
2016-05-04 16:42:16 +00:00
if (FC(imports_const)) {
zend_string *import_name = zend_hash_find_ptr(FC(imports_const), unqualified_name);
if (import_name && !zend_string_equals(import_name, name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare const %s because "
"the name is already in use", ZSTR_VAL(name));
2014-07-22 09:55:07 +00:00
}
}
name_node.op_type = IS_CONST;
ZVAL_STR(&name_node.u.constant, name);
2014-12-13 22:06:14 +00:00
zend_emit_op(NULL, ZEND_DECLARE_CONST, &name_node, &value_node);
2014-07-22 09:55:07 +00:00
zend_register_seen_symbol(name, ZEND_SYMBOL_CONST);
2014-07-22 09:55:07 +00:00
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}}*/
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_namespace(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-22 10:45:44 +00:00
zend_ast *name_ast = ast->child[0];
zend_ast *stmt_ast = ast->child[1];
zend_string *name;
bool with_bracket = stmt_ast != NULL;
/* handle mixed syntax declaration or nested namespaces */
if (!FC(has_bracketed_namespaces)) {
if (FC(current_namespace)) {
/* previous namespace declarations were unbracketed */
if (with_bracket) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations "
"with unbracketed namespace declarations");
}
}
} else {
/* previous namespace declarations were bracketed */
if (!with_bracket) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot mix bracketed namespace declarations "
"with unbracketed namespace declarations");
} else if (FC(current_namespace) || FC(in_namespace)) {
zend_error_noreturn(E_COMPILE_ERROR, "Namespace declarations cannot be nested");
}
}
bool is_first_namespace = (!with_bracket && !FC(current_namespace))
|| (with_bracket && !FC(has_bracketed_namespaces));
if (is_first_namespace && FAILURE == zend_is_first_statement(ast, /* allow_nop */ 1)) {
zend_error_noreturn(E_COMPILE_ERROR, "Namespace declaration statement has to be "
"the very first statement or after any declare call in the script");
}
if (FC(current_namespace)) {
zend_string_release_ex(FC(current_namespace), 0);
2014-07-22 10:45:44 +00:00
}
2014-07-22 10:45:44 +00:00
if (name_ast) {
2014-07-28 13:16:35 +00:00
name = zend_ast_get_str(name_ast);
if (zend_string_equals_literal_ci(name, "namespace")) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as namespace name", ZSTR_VAL(name));
}
2014-07-22 10:45:44 +00:00
FC(current_namespace) = zend_string_copy(name);
} else {
FC(current_namespace) = NULL;
}
2014-12-13 22:06:14 +00:00
zend_reset_import_tables();
2005-02-11 22:26:45 +00:00
FC(in_namespace) = 1;
if (with_bracket) {
FC(has_bracketed_namespaces) = 1;
}
1999-04-07 18:10:10 +00:00
2014-07-22 10:45:44 +00:00
if (stmt_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_top_stmt(stmt_ast);
zend_end_namespace();
2014-07-22 10:45:44 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_halt_compiler(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *offset_ast = ast->child[0];
zend_long offset = Z_LVAL_P(zend_ast_get_zval(offset_ast));
zend_string *filename, *name;
const char const_name[] = "__COMPILER_HALT_OFFSET__";
if (FC(has_bracketed_namespaces) && FC(in_namespace)) {
2014-07-28 20:03:16 +00:00
zend_error_noreturn(E_COMPILE_ERROR,
"__HALT_COMPILER() can only be used from the outermost scope");
}
2014-12-13 22:06:14 +00:00
filename = zend_get_compiled_filename();
name = zend_mangle_property_name(const_name, sizeof(const_name) - 1,
ZSTR_VAL(filename), ZSTR_LEN(filename), 0);
zend_register_long_constant(ZSTR_VAL(name), ZSTR_LEN(name), offset, CONST_CS, 0);
zend_string_release_ex(name, 0);
}
2014-08-29 05:05:58 +00:00
/* }}} */
static bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op_array *op_array = CG(active_op_array);
zend_class_entry *ce = CG(active_class_entry);
switch (ast->attr) {
case T_LINE:
2014-10-12 18:54:45 +00:00
ZVAL_LONG(zv, ast->lineno);
break;
case T_FILE:
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY(zv, CG(compiled_filename));
break;
case T_DIR:
{
zend_string *filename = CG(compiled_filename);
zend_string *dirname = zend_string_init(ZSTR_VAL(filename), ZSTR_LEN(filename), 0);
#ifdef ZEND_WIN32
2017-05-16 10:49:19 +00:00
ZSTR_LEN(dirname) = php_win32_ioutil_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
#else
2017-05-16 10:49:19 +00:00
ZSTR_LEN(dirname) = zend_dirname(ZSTR_VAL(dirname), ZSTR_LEN(dirname));
#endif
if (zend_string_equals_literal(dirname, ".")) {
dirname = zend_string_extend(dirname, MAXPATHLEN, 0);
#if HAVE_GETCWD
ZEND_IGNORE_VALUE(VCWD_GETCWD(ZSTR_VAL(dirname), MAXPATHLEN));
#elif HAVE_GETWD
ZEND_IGNORE_VALUE(VCWD_GETWD(ZSTR_VAL(dirname)));
#endif
2017-05-16 10:49:19 +00:00
ZSTR_LEN(dirname) = strlen(ZSTR_VAL(dirname));
}
ZVAL_STR(zv, dirname);
break;
}
case T_FUNC_C:
if (op_array && op_array->function_name) {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY(zv, op_array->function_name);
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
case T_METHOD_C:
/* Detect whether we are directly inside a class (e.g. a class constant) and treat
* this as not being inside a function. */
if (op_array && ce && !op_array->scope && !(op_array->fn_flags & ZEND_ACC_CLOSURE)) {
op_array = NULL;
}
if (op_array && op_array->function_name) {
if (op_array->scope) {
ZVAL_NEW_STR(zv,
zend_create_member_string(op_array->scope->name, op_array->function_name));
} else {
ZVAL_STR_COPY(zv, op_array->function_name);
}
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
case T_CLASS_C:
if (ce) {
if ((ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
return 0;
} else {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY(zv, ce->name);
}
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
case T_TRAIT_C:
if (ce && (ce->ce_flags & ZEND_ACC_TRAIT) != 0) {
2014-09-19 13:32:50 +00:00
ZVAL_STR_COPY(zv, ce->name);
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
case T_NS_C:
if (FC(current_namespace)) {
ZVAL_STR_COPY(zv, FC(current_namespace));
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
EMPTY_SWITCH_DEFAULT_CASE()
}
return 1;
}
2014-08-29 05:05:58 +00:00
/* }}} */
ZEND_API bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
{
if ((opcode == ZEND_CONCAT || opcode == ZEND_FAST_CONCAT)) {
/* Array to string warning. */
return Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY;
}
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
if (!(opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_DIV
|| opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
|| opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
/* Only the numeric operations throw errors. */
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
return 0;
}
if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) {
if (opcode == ZEND_ADD && Z_TYPE_P(op1) == IS_ARRAY && Z_TYPE_P(op2) == IS_ARRAY) {
/* Adding two arrays is allowed. */
return 0;
}
/* Numeric operators throw when one of the operands is an array. */
return 1;
}
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
/* While basic arithmetic operators always produce numeric string errors,
* bitwise operators don't produce errors if both operands are strings */
if ((opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)
&& Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
return 0;
}
if (Z_TYPE_P(op1) == IS_STRING
&& !is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), NULL, NULL, 0)) {
return 1;
}
if (Z_TYPE_P(op2) == IS_STRING
&& !is_numeric_string(Z_STRVAL_P(op2), Z_STRLEN_P(op2), NULL, NULL, 0)) {
return 1;
}
if ((opcode == ZEND_MOD && zval_get_long(op2) == 0)
|| (opcode == ZEND_DIV && zval_get_double(op2) == 0.0)) {
/* Division by zero throws an error. */
return 1;
}
if ((opcode == ZEND_SL || opcode == ZEND_SR) && zval_get_long(op2) < 0) {
/* Shift by negative number throws an error. */
return 1;
}
return 0;
}
/* }}} */
static inline bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zval *op1, zval *op2) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (zend_binary_op_produces_error(opcode, op1, op2)) {
return 0;
}
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
binary_op_type fn = get_binary_op(opcode);
2014-12-13 22:06:14 +00:00
fn(result, op1, op2);
return 1;
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
ZEND_API bool zend_unary_op_produces_error(uint32_t opcode, zval *op)
2015-06-10 22:57:37 +00:00
{
if (opcode == ZEND_BW_NOT) {
return Z_TYPE_P(op) <= IS_TRUE || Z_TYPE_P(op) == IS_ARRAY;
}
return 0;
}
static inline bool zend_try_ct_eval_unary_op(zval *result, uint32_t opcode, zval *op) /* {{{ */
{
if (zend_unary_op_produces_error(opcode, op)) {
return 0;
}
2015-06-10 22:57:37 +00:00
unary_op_type fn = get_unary_op(opcode);
fn(result, op);
return 1;
2015-06-10 22:57:37 +00:00
}
/* }}} */
static inline bool zend_try_ct_eval_unary_pm(zval *result, zend_ast_kind kind, zval *op) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zval right;
ZVAL_LONG(&right, (kind == ZEND_AST_UNARY_PLUS) ? 1 : -1);
return zend_try_ct_eval_binary_op(result, ZEND_MUL, op, &right);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
static inline void zend_ct_eval_greater(zval *result, zend_ast_kind kind, zval *op1, zval *op2) /* {{{ */
2014-08-29 05:05:58 +00:00
{
binary_op_type fn = kind == ZEND_AST_GREATER
? is_smaller_function : is_smaller_or_equal_function;
2014-12-13 22:06:14 +00:00
fn(result, op2, op1);
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
static bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
zend_ast *last_elem_ast = NULL;
uint32_t i;
bool is_constant = 1;
if (ast->attr == ZEND_ARRAY_SYNTAX_LIST) {
zend_error(E_COMPILE_ERROR, "Cannot use list() as standalone expression");
}
/* First ensure that *all* child nodes are constant and by-val */
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
if (elem_ast == NULL) {
/* Report error at line of last non-empty element */
if (last_elem_ast) {
CG(zend_lineno) = zend_ast_get_lineno(last_elem_ast);
}
zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
}
if (elem_ast->kind != ZEND_AST_UNPACK) {
zend_eval_const_expr(&elem_ast->child[0]);
zend_eval_const_expr(&elem_ast->child[1]);
2019-11-12 07:51:55 +00:00
if (elem_ast->attr /* by_ref */ || elem_ast->child[0]->kind != ZEND_AST_ZVAL
|| (elem_ast->child[1] && elem_ast->child[1]->kind != ZEND_AST_ZVAL)
) {
is_constant = 0;
}
} else {
zend_eval_const_expr(&elem_ast->child[0]);
2019-11-12 07:51:55 +00:00
if (elem_ast->child[0]->kind != ZEND_AST_ZVAL) {
is_constant = 0;
}
}
last_elem_ast = elem_ast;
1999-04-07 18:10:10 +00:00
}
2015-06-15 15:41:47 +00:00
if (!is_constant) {
return 0;
}
if (!list->children) {
ZVAL_EMPTY_ARRAY(result);
return 1;
}
array_init_size(result, list->children);
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
zend_ast *value_ast = elem_ast->child[0];
zend_ast *key_ast;
zval *value = zend_ast_get_zval(value_ast);
if (elem_ast->kind == ZEND_AST_UNPACK) {
if (Z_TYPE_P(value) == IS_ARRAY) {
HashTable *ht = Z_ARRVAL_P(value);
zval *val;
zend_string *key;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) {
if (key) {
zend_hash_update(Z_ARRVAL_P(result), key, val);
} else if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), val)) {
zval_ptr_dtor(result);
return 0;
}
Z_TRY_ADDREF_P(val);
} ZEND_HASH_FOREACH_END();
2019-11-12 07:51:55 +00:00
continue;
} else {
zend_error_noreturn(E_COMPILE_ERROR, "Only arrays and Traversables can be unpacked");
}
2019-11-12 07:51:55 +00:00
}
2017-11-01 02:25:10 +00:00
Z_TRY_ADDREF_P(value);
key_ast = elem_ast->child[1];
if (key_ast) {
zval *key = zend_ast_get_zval(key_ast);
switch (Z_TYPE_P(key)) {
case IS_LONG:
zend_hash_index_update(Z_ARRVAL_P(result), Z_LVAL_P(key), value);
break;
case IS_STRING:
zend_symtable_update(Z_ARRVAL_P(result), Z_STR_P(key), value);
break;
case IS_DOUBLE:
zend_hash_index_update(Z_ARRVAL_P(result),
zend_dval_to_lval(Z_DVAL_P(key)), value);
break;
case IS_FALSE:
zend_hash_index_update(Z_ARRVAL_P(result), 0, value);
break;
case IS_TRUE:
zend_hash_index_update(Z_ARRVAL_P(result), 1, value);
break;
case IS_NULL:
zend_hash_update(Z_ARRVAL_P(result), ZSTR_EMPTY_ALLOC(), value);
break;
default:
zend_error_noreturn(E_COMPILE_ERROR, "Illegal offset type");
break;
}
2019-03-06 09:42:02 +00:00
} else if (!zend_hash_next_index_insert(Z_ARRVAL_P(result), value)) {
zval_ptr_dtor_nogc(value);
zval_ptr_dtor(result);
return 0;
}
}
return 1;
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_binary_op(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *left_ast = ast->child[0];
zend_ast *right_ast = ast->child[1];
uint32_t opcode = ast->attr;
2005-02-20 10:19:11 +00:00
znode left_node, right_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&left_node, left_ast);
zend_compile_expr(&right_node, right_ast);
if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
if (zend_try_ct_eval_binary_op(&result->u.constant, opcode,
&left_node.u.constant, &right_node.u.constant)
) {
result->op_type = IS_CONST;
zval_ptr_dtor(&left_node.u.constant);
zval_ptr_dtor(&right_node.u.constant);
return;
}
1999-04-07 18:10:10 +00:00
}
do {
if (opcode == ZEND_IS_EQUAL || opcode == ZEND_IS_NOT_EQUAL) {
if (left_node.op_type == IS_CONST) {
if (Z_TYPE(left_node.u.constant) == IS_FALSE) {
opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
zend_emit_op_tmp(result, opcode, &right_node, NULL);
break;
} else if (Z_TYPE(left_node.u.constant) == IS_TRUE) {
opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
zend_emit_op_tmp(result, opcode, &right_node, NULL);
break;
}
} else if (right_node.op_type == IS_CONST) {
if (Z_TYPE(right_node.u.constant) == IS_FALSE) {
opcode = (opcode == ZEND_IS_NOT_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
zend_emit_op_tmp(result, opcode, &left_node, NULL);
break;
} else if (Z_TYPE(right_node.u.constant) == IS_TRUE) {
opcode = (opcode == ZEND_IS_EQUAL) ? ZEND_BOOL : ZEND_BOOL_NOT;
zend_emit_op_tmp(result, opcode, &left_node, NULL);
break;
}
}
2019-11-12 10:49:55 +00:00
} else if (opcode == ZEND_IS_IDENTICAL || opcode == ZEND_IS_NOT_IDENTICAL) {
/* convert $x === null to is_null($x) (i.e. ZEND_TYPE_CHECK opcode). Do the same thing for false/true. (covers IS_NULL, IS_FALSE, and IS_TRUE) */
if (left_node.op_type == IS_CONST) {
if (Z_TYPE(left_node.u.constant) <= IS_TRUE && Z_TYPE(left_node.u.constant) >= IS_NULL) {
zend_op *opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &right_node, NULL);
opline->extended_value =
(opcode == ZEND_IS_IDENTICAL) ?
(1 << Z_TYPE(left_node.u.constant)) :
(MAY_BE_ANY - (1 << Z_TYPE(left_node.u.constant)));
return;
}
} else if (right_node.op_type == IS_CONST) {
if (Z_TYPE(right_node.u.constant) <= IS_TRUE && Z_TYPE(right_node.u.constant) >= IS_NULL) {
zend_op *opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &left_node, NULL);
opline->extended_value =
(opcode == ZEND_IS_IDENTICAL) ?
(1 << Z_TYPE(right_node.u.constant)) :
(MAY_BE_ANY - (1 << Z_TYPE(right_node.u.constant)));
return;
}
}
} else if (opcode == ZEND_CONCAT) {
/* convert constant operands to strings at compile-time */
if (left_node.op_type == IS_CONST) {
if (Z_TYPE(left_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&left_node, ZEND_CAST, &left_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&left_node.u.constant);
}
}
if (right_node.op_type == IS_CONST) {
if (Z_TYPE(right_node.u.constant) == IS_ARRAY) {
zend_emit_op_tmp(&right_node, ZEND_CAST, &right_node, NULL)->extended_value = IS_STRING;
} else {
convert_to_string(&right_node.u.constant);
}
}
if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
opcode = ZEND_FAST_CONCAT;
}
}
zend_emit_op_tmp(result, opcode, &left_node, &right_node);
} while (0);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
/* We do not use zend_compile_binary_op for this because we want to retain the left-to-right
* evaluation order. */
2014-12-13 22:06:14 +00:00
void zend_compile_greater(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *left_ast = ast->child[0];
zend_ast *right_ast = ast->child[1];
znode left_node, right_node;
1999-04-07 18:10:10 +00:00
ZEND_ASSERT(ast->kind == ZEND_AST_GREATER || ast->kind == ZEND_AST_GREATER_EQUAL);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&left_node, left_ast);
zend_compile_expr(&right_node, right_ast);
1999-04-07 18:10:10 +00:00
if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) {
result->op_type = IS_CONST;
zend_ct_eval_greater(&result->u.constant, ast->kind,
2014-12-13 22:06:14 +00:00
&left_node.u.constant, &right_node.u.constant);
zval_ptr_dtor(&left_node.u.constant);
zval_ptr_dtor(&right_node.u.constant);
return;
}
1999-04-07 18:10:10 +00:00
2014-07-28 20:03:16 +00:00
zend_emit_op_tmp(result,
ast->kind == ZEND_AST_GREATER ? ZEND_IS_SMALLER : ZEND_IS_SMALLER_OR_EQUAL,
2014-12-13 22:06:14 +00:00
&right_node, &left_node);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_unary_op(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *expr_ast = ast->child[0];
uint32_t opcode = ast->attr;
znode expr_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
2008-07-24 22:21:41 +00:00
if (expr_node.op_type == IS_CONST
&& zend_try_ct_eval_unary_op(&result->u.constant, opcode, &expr_node.u.constant)) {
2015-06-10 22:57:37 +00:00
result->op_type = IS_CONST;
zval_ptr_dtor(&expr_node.u.constant);
return;
}
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp(result, opcode, &expr_node, NULL);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_unary_pm(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *expr_ast = ast->child[0];
znode expr_node, right_node;
2014-06-26 10:43:20 +00:00
ZEND_ASSERT(ast->kind == ZEND_AST_UNARY_PLUS || ast->kind == ZEND_AST_UNARY_MINUS);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
2019-03-06 09:42:02 +00:00
if (expr_node.op_type == IS_CONST
&& zend_try_ct_eval_unary_pm(&result->u.constant, ast->kind, &expr_node.u.constant)) {
result->op_type = IS_CONST;
zval_ptr_dtor(&expr_node.u.constant);
return;
2002-07-30 22:19:50 +00:00
}
right_node.op_type = IS_CONST;
ZVAL_LONG(&right_node.u.constant, (ast->kind == ZEND_AST_UNARY_PLUS) ? 1 : -1);
zend_emit_op_tmp(result, ZEND_MUL, &expr_node, &right_node);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_short_circuiting(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *left_ast = ast->child[0];
zend_ast *right_ast = ast->child[1];
1999-04-07 18:10:10 +00:00
znode left_node, right_node;
zend_op *opline_jmpz, *opline_bool;
uint32_t opnum_jmpz;
1999-04-07 18:10:10 +00:00
ZEND_ASSERT(ast->kind == ZEND_AST_AND || ast->kind == ZEND_AST_OR);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&left_node, left_ast);
1999-04-07 18:10:10 +00:00
if (left_node.op_type == IS_CONST) {
2015-06-14 14:56:06 +00:00
if ((ast->kind == ZEND_AST_AND && !zend_is_true(&left_node.u.constant))
|| (ast->kind == ZEND_AST_OR && zend_is_true(&left_node.u.constant))) {
result->op_type = IS_CONST;
ZVAL_BOOL(&result->u.constant, zend_is_true(&left_node.u.constant));
} else {
zend_compile_expr(&right_node, right_ast);
if (right_node.op_type == IS_CONST) {
result->op_type = IS_CONST;
ZVAL_BOOL(&result->u.constant, zend_is_true(&right_node.u.constant));
zval_ptr_dtor(&right_node.u.constant);
} else {
zend_emit_op_tmp(result, ZEND_BOOL, &right_node, NULL);
}
}
zval_ptr_dtor(&left_node.u.constant);
return;
}
opnum_jmpz = get_next_op_number();
2014-07-28 20:03:16 +00:00
opline_jmpz = zend_emit_op(NULL, ast->kind == ZEND_AST_AND ? ZEND_JMPZ_EX : ZEND_JMPNZ_EX,
2014-12-13 22:06:14 +00:00
&left_node, NULL);
if (left_node.op_type == IS_TMP_VAR) {
SET_NODE(opline_jmpz->result, &left_node);
GET_NODE(result, opline_jmpz->result);
2015-06-14 14:56:06 +00:00
} else {
zend_make_tmp_result(result, opline_jmpz);
}
zend_compile_expr(&right_node, right_ast);
opline_bool = zend_emit_op(NULL, ZEND_BOOL, &right_node, NULL);
SET_NODE(opline_bool->result, result);
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_jmpz);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_post_incdec(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *var_ast = ast->child[0];
ZEND_ASSERT(ast->kind == ZEND_AST_POST_INC || ast->kind == ZEND_AST_POST_DEC);
zend_ensure_writable_variable(var_ast);
if (var_ast->kind == ZEND_AST_PROP || var_ast->kind == ZEND_AST_NULLSAFE_PROP) {
zend_op *opline = zend_compile_prop(NULL, var_ast, BP_VAR_RW, 0);
opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_OBJ : ZEND_POST_DEC_OBJ;
2014-12-13 22:06:14 +00:00
zend_make_tmp_result(result, opline);
} else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
zend_op *opline = zend_compile_static_prop(NULL, var_ast, BP_VAR_RW, 0, 0);
opline->opcode = ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC_STATIC_PROP : ZEND_POST_DEC_STATIC_PROP;
zend_make_tmp_result(result, opline);
} else {
2014-07-29 19:00:19 +00:00
znode var_node;
zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
2014-07-28 20:03:16 +00:00
zend_emit_op_tmp(result, ast->kind == ZEND_AST_POST_INC ? ZEND_POST_INC : ZEND_POST_DEC,
2014-12-13 22:06:14 +00:00
&var_node, NULL);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_pre_incdec(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *var_ast = ast->child[0];
ZEND_ASSERT(ast->kind == ZEND_AST_PRE_INC || ast->kind == ZEND_AST_PRE_DEC);
zend_ensure_writable_variable(var_ast);
if (var_ast->kind == ZEND_AST_PROP || var_ast->kind == ZEND_AST_NULLSAFE_PROP) {
zend_op *opline = zend_compile_prop(result, var_ast, BP_VAR_RW, 0);
opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_OBJ : ZEND_PRE_DEC_OBJ;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
} else if (var_ast->kind == ZEND_AST_STATIC_PROP) {
zend_op *opline = zend_compile_static_prop(result, var_ast, BP_VAR_RW, 0, 0);
opline->opcode = ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC_STATIC_PROP : ZEND_PRE_DEC_STATIC_PROP;
opline->result_type = IS_TMP_VAR;
result->op_type = IS_TMP_VAR;
} else {
2014-07-29 19:00:19 +00:00
znode var_node;
zend_compile_var(&var_node, var_ast, BP_VAR_RW, 0);
zend_emit_op_tmp(result, ast->kind == ZEND_AST_PRE_INC ? ZEND_PRE_INC : ZEND_PRE_DEC,
2014-12-13 22:06:14 +00:00
&var_node, NULL);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_cast(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *expr_ast = ast->child[0];
znode expr_node;
1999-04-07 18:10:10 +00:00
zend_op *opline;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
1999-04-07 18:10:10 +00:00
if (ast->attr == _IS_BOOL) {
opline = zend_emit_op_tmp(result, ZEND_BOOL, &expr_node, NULL);
} else if (ast->attr == IS_NULL) {
zend_error(E_COMPILE_ERROR, "The (unset) cast is no longer supported");
} else {
opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL);
opline->extended_value = ast->attr;
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *cond_ast = ast->child[0];
zend_ast *false_ast = ast->child[2];
1999-04-07 18:10:10 +00:00
znode cond_node, false_node;
2015-07-06 15:41:29 +00:00
zend_op *opline_qm_assign;
uint32_t opnum_jmp_set;
1999-04-07 18:10:10 +00:00
ZEND_ASSERT(ast->child[1] == NULL);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&cond_node, cond_ast);
1999-04-07 18:10:10 +00:00
opnum_jmp_set = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp(result, ZEND_JMP_SET, &cond_node, NULL);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&false_node, false_ast);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &false_node, NULL);
SET_NODE(opline_qm_assign->result, result);
2015-07-06 15:41:29 +00:00
zend_update_jump_target_to_next(opnum_jmp_set);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_conditional(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *cond_ast = ast->child[0];
zend_ast *true_ast = ast->child[1];
zend_ast *false_ast = ast->child[2];
znode cond_node, true_node, false_node;
2015-07-06 15:41:29 +00:00
zend_op *opline_qm_assign2;
uint32_t opnum_jmpz, opnum_jmp;
if (cond_ast->kind == ZEND_AST_CONDITIONAL
&& cond_ast->attr != ZEND_PARENTHESIZED_CONDITIONAL) {
if (cond_ast->child[1]) {
if (true_ast) {
zend_error(E_COMPILE_ERROR,
"Unparenthesized `a ? b : c ? d : e` is not supported. "
"Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)`");
} else {
zend_error(E_COMPILE_ERROR,
"Unparenthesized `a ? b : c ?: d` is not supported. "
"Use either `(a ? b : c) ?: d` or `a ? b : (c ?: d)`");
}
} else {
if (true_ast) {
zend_error(E_COMPILE_ERROR,
"Unparenthesized `a ?: b ? c : d` is not supported. "
"Use either `(a ?: b) ? c : d` or `a ?: (b ? c : d)`");
} else {
/* This case is harmless: (a ?: b) ?: c always produces the same result
* as a ?: (b ?: c). */
}
}
}
if (!true_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_shorthand_conditional(result, ast);
1999-04-07 18:10:10 +00:00
return;
}
2015-01-03 09:22:58 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&cond_node, cond_ast);
2014-12-13 22:06:14 +00:00
opnum_jmpz = zend_emit_cond_jump(ZEND_JMPZ, &cond_node, 0);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&true_node, true_ast);
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &true_node, NULL);
2014-12-13 22:06:14 +00:00
opnum_jmp = zend_emit_jump(0);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_jmpz);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&false_node, false_ast);
2015-07-06 15:41:29 +00:00
opline_qm_assign2 = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL);
SET_NODE(opline_qm_assign2->result, result);
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
zend_update_jump_target_to_next(opnum_jmp);
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
1999-04-07 18:10:10 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_coalesce(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
zend_ast *default_ast = ast->child[1];
znode expr_node, default_node;
zend_op *opline;
uint32_t opnum;
zend_compile_var(&expr_node, expr_ast, BP_VAR_IS, 0);
opnum = get_next_op_number();
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp(result, ZEND_COALESCE, &expr_node, NULL);
2014-12-13 22:06:14 +00:00
zend_compile_expr(&default_node, default_ast);
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &default_node, NULL);
SET_NODE(opline->result, result);
opline = &CG(active_op_array)->opcodes[opnum];
opline->op2.opline_num = get_next_op_number();
}
/* }}} */
static void znode_dtor(zval *zv) {
znode *node = Z_PTR_P(zv);
if (node->op_type == IS_CONST) {
zval_ptr_dtor_nogc(&node->u.constant);
}
efree(node);
}
void zend_compile_assign_coalesce(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *var_ast = ast->child[0];
zend_ast *default_ast = ast->child[1];
znode var_node_is, var_node_w, default_node, assign_node, *node;
zend_op *opline;
uint32_t coalesce_opnum;
bool need_frees = 0;
/* Remember expressions compiled during the initial BP_VAR_IS lookup,
* to avoid double-evaluation when we compile again with BP_VAR_W. */
HashTable *orig_memoized_exprs = CG(memoized_exprs);
int orig_memoize_mode = CG(memoize_mode);
zend_ensure_writable_variable(var_ast);
if (is_this_fetch(var_ast)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
}
ALLOC_HASHTABLE(CG(memoized_exprs));
zend_hash_init(CG(memoized_exprs), 0, NULL, znode_dtor, 0);
CG(memoize_mode) = ZEND_MEMOIZE_COMPILE;
zend_compile_var(&var_node_is, var_ast, BP_VAR_IS, 0);
coalesce_opnum = get_next_op_number();
zend_emit_op_tmp(result, ZEND_COALESCE, &var_node_is, NULL);
CG(memoize_mode) = ZEND_MEMOIZE_NONE;
zend_compile_expr(&default_node, default_ast);
CG(memoize_mode) = ZEND_MEMOIZE_FETCH;
zend_compile_var(&var_node_w, var_ast, BP_VAR_W, 0);
/* Reproduce some of the zend_compile_assign() opcode fixup logic here. */
opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1];
switch (var_ast->kind) {
case ZEND_AST_VAR:
zend_emit_op_tmp(&assign_node, ZEND_ASSIGN, &var_node_w, &default_node);
break;
case ZEND_AST_STATIC_PROP:
opline->opcode = ZEND_ASSIGN_STATIC_PROP;
opline->result_type = IS_TMP_VAR;
var_node_w.op_type = IS_TMP_VAR;
zend_emit_op_data(&default_node);
assign_node = var_node_w;
break;
case ZEND_AST_DIM:
opline->opcode = ZEND_ASSIGN_DIM;
opline->result_type = IS_TMP_VAR;
var_node_w.op_type = IS_TMP_VAR;
zend_emit_op_data(&default_node);
assign_node = var_node_w;
break;
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
opline->opcode = ZEND_ASSIGN_OBJ;
opline->result_type = IS_TMP_VAR;
var_node_w.op_type = IS_TMP_VAR;
zend_emit_op_data(&default_node);
assign_node = var_node_w;
break;
EMPTY_SWITCH_DEFAULT_CASE();
}
opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &assign_node, NULL);
SET_NODE(opline->result, result);
ZEND_HASH_FOREACH_PTR(CG(memoized_exprs), node) {
if (node->op_type == IS_TMP_VAR || node->op_type == IS_VAR) {
need_frees = 1;
break;
}
} ZEND_HASH_FOREACH_END();
/* Free DUPed expressions if there are any */
if (need_frees) {
uint32_t jump_opnum = zend_emit_jump(0);
zend_update_jump_target_to_next(coalesce_opnum);
ZEND_HASH_FOREACH_PTR(CG(memoized_exprs), node) {
if (node->op_type == IS_TMP_VAR || node->op_type == IS_VAR) {
zend_emit_op(NULL, ZEND_FREE, node, NULL);
}
} ZEND_HASH_FOREACH_END();
zend_update_jump_target_to_next(jump_opnum);
} else {
zend_update_jump_target_to_next(coalesce_opnum);
}
zend_hash_destroy(CG(memoized_exprs));
FREE_HASHTABLE(CG(memoized_exprs));
CG(memoized_exprs) = orig_memoized_exprs;
CG(memoize_mode) = orig_memoize_mode;
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_print(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline;
zend_ast *expr_ast = ast->child[0];
znode expr_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
opline = zend_emit_op(NULL, ZEND_ECHO, &expr_node, NULL);
opline->extended_value = 1;
result->op_type = IS_CONST;
ZVAL_LONG(&result->u.constant, 1);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_exit(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *expr_ast = ast->child[0];
2003-03-02 13:33:31 +00:00
if (expr_ast) {
znode expr_node;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&expr_node, expr_ast);
zend_emit_op(NULL, ZEND_EXIT, &expr_node, NULL);
} else {
2014-12-13 22:06:14 +00:00
zend_emit_op(NULL, ZEND_EXIT, NULL, NULL);
2003-03-02 13:33:31 +00:00
}
result->op_type = IS_CONST;
ZVAL_TRUE(&result->u.constant);
2003-03-02 13:33:31 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-03-02 13:33:31 +00:00
2015-02-20 11:59:56 +00:00
void zend_compile_yield(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *value_ast = ast->child[0];
zend_ast *key_ast = ast->child[1];
znode value_node, key_node;
znode *value_node_ptr = NULL, *key_node_ptr = NULL;
zend_op *opline;
bool returns_by_ref = (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
2015-02-20 11:59:56 +00:00
zend_mark_function_as_generator();
if (key_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&key_node, key_ast);
key_node_ptr = &key_node;
}
2014-06-16 17:11:52 +00:00
if (value_ast) {
if (returns_by_ref && zend_is_variable(value_ast)) {
zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
2014-06-16 17:11:52 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&value_node, value_ast);
2014-06-16 17:11:52 +00:00
}
value_node_ptr = &value_node;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(result, ZEND_YIELD, value_node_ptr, key_node_ptr);
if (value_ast && returns_by_ref && zend_is_call(value_ast)) {
opline->extended_value = ZEND_RETURNS_FUNCTION;
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2015-02-20 11:59:56 +00:00
void zend_compile_yield_from(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
znode expr_node;
zend_mark_function_as_generator();
if (CG(active_op_array)->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use \"yield from\" inside a by-reference generator");
}
2015-02-20 11:59:56 +00:00
zend_compile_expr(&expr_node, expr_ast);
zend_emit_op_tmp(result, ZEND_YIELD_FROM, &expr_node, NULL);
}
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *obj_ast = ast->child[0];
zend_ast *class_ast = ast->child[1];
1999-04-07 18:10:10 +00:00
znode obj_node, class_node;
zend_op *opline;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&obj_node, obj_ast);
if (obj_node.op_type == IS_CONST) {
2017-12-19 21:16:45 +00:00
zend_do_free(&obj_node);
result->op_type = IS_CONST;
ZVAL_FALSE(&result->u.constant);
return;
}
zend_compile_class_ref(&class_node, class_ast,
ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_EXCEPTION | ZEND_FETCH_CLASS_SILENT);
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(result, ZEND_INSTANCEOF, &obj_node, NULL);
if (class_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_class_name_literal(
Z_STR(class_node.u.constant));
opline->extended_value = zend_alloc_cache_slot();
} else {
SET_NODE(opline->op2, &class_node);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_include_or_eval(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *expr_ast = ast->child[0];
znode expr_node;
zend_op *opline;
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_begin();
zend_compile_expr(&expr_node, expr_ast);
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
opline = zend_emit_op(result, ZEND_INCLUDE_OR_EVAL, &expr_node, NULL);
2014-06-19 11:57:29 +00:00
opline->extended_value = ast->attr;
2014-12-13 22:06:14 +00:00
zend_do_extended_fcall_end();
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_isset_or_empty(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *var_ast = ast->child[0];
znode var_node;
zend_op *opline = NULL;
2014-06-19 11:57:29 +00:00
ZEND_ASSERT(ast->kind == ZEND_AST_ISSET || ast->kind == ZEND_AST_EMPTY);
if (!zend_is_variable(var_ast)) {
2014-06-19 11:57:29 +00:00
if (ast->kind == ZEND_AST_EMPTY) {
/* empty(expr) can be transformed to !expr */
zend_ast *not_ast = zend_ast_create_ex(ZEND_AST_UNARY_OP, ZEND_BOOL_NOT, var_ast);
2014-12-13 22:06:14 +00:00
zend_compile_expr(result, not_ast);
2014-06-19 11:57:29 +00:00
return;
} else {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use isset() on the result of an expression "
"(you can use \"null !== expression\" instead)");
}
}
if (is_globals_fetch(var_ast)) {
result->op_type = IS_CONST;
ZVAL_BOOL(&result->u.constant, ast->kind == ZEND_AST_ISSET);
return;
}
if (is_global_var_fetch(var_ast)) {
if (!var_ast->child[1]) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
}
zend_compile_expr(&var_node, var_ast->child[1]);
if (var_node.op_type == IS_CONST) {
convert_to_string(&var_node.u.constant);
}
opline = zend_emit_op_tmp(result, ZEND_ISSET_ISEMPTY_VAR, &var_node, NULL);
opline->extended_value =
ZEND_FETCH_GLOBAL | (ast->kind == ZEND_AST_EMPTY ? ZEND_ISEMPTY : 0);
return;
}
zend_short_circuiting_mark_inner(var_ast);
2014-06-19 11:57:29 +00:00
switch (var_ast->kind) {
case ZEND_AST_VAR:
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
if (is_this_fetch(var_ast)) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_THIS, NULL, NULL);
CG(active_op_array)->fn_flags |= ZEND_ACC_USES_THIS;
Implemented RFC: Fix inconsistent behavior of $this variable Squashed commit of the following: commit bdd3b6895c3ce3eacfcf7d4bf4feb8dfa61801fd Author: Dmitry Stogov <dmitry@zend.com> Date: Thu Jun 16 00:19:42 2016 +0300 Fixed GOTO VM commit 2f1d7c8b89ce821086d357cf65f629f040a85c03 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 21:01:57 2016 +0300 Removed unused variable commit cf749c42b0b1919f70b1e7d6dcbfff76899506af Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 19:06:16 2016 +0300 Protection from $this reassign through mb_parse_str() commit 59a9a6c83c66b666971e57f1173b33a422166efd Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:14:50 2016 +0300 Added type inference rule for FETCH_THIS opcode commit 73f8d14a856f14a461430b3c7534ab2ce870cbf6 Author: Dmitry Stogov <dmitry@zend.com> Date: Wed Jun 15 18:11:18 2016 +0300 Restored PHP-7 behavior of isset($this->foo). It throws exception if not in object context. Removed useless opcode handlers. commit fa0881381e8ae97e022ae5d1ec0851c952f33c82 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 31 12:25:47 2016 +0300 Changed "Notice: Undefined variable: this" into "Exception: Using $this when not in object context". commit e32cc528c0f2c97963d8ec83eff0269f1f45af18 Author: Dmitry Stogov <dmitry@zend.com> Date: Tue May 24 02:02:43 2016 +0300 Throw exception on attempt to re-assign $this through extract() and parse_str(). commit 41f1531b52113ec8a4c208aa6b9ef50f1386bb3f Author: Dmitry Stogov <dmitry@zend.com> Date: Mon May 23 22:18:36 2016 +0300 Fixed inconsistent $this behavior
2016-06-15 23:30:23 +00:00
} else if (zend_try_compile_cv(&var_node, var_ast) == SUCCESS) {
opline = zend_emit_op(result, ZEND_ISSET_ISEMPTY_CV, &var_node, NULL);
2014-06-19 11:57:29 +00:00
} else {
2015-02-02 17:44:16 +00:00
opline = zend_compile_simple_var_no_cv(result, var_ast, BP_VAR_IS, 0);
2014-06-19 11:57:29 +00:00
opline->opcode = ZEND_ISSET_ISEMPTY_VAR;
}
1999-04-07 18:10:10 +00:00
break;
2014-06-19 11:57:29 +00:00
case ZEND_AST_DIM:
opline = zend_compile_dim(result, var_ast, BP_VAR_IS);
2014-06-19 11:57:29 +00:00
opline->opcode = ZEND_ISSET_ISEMPTY_DIM_OBJ;
break;
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
opline = zend_compile_prop(result, var_ast, BP_VAR_IS, 0);
2014-06-19 11:57:29 +00:00
opline->opcode = ZEND_ISSET_ISEMPTY_PROP_OBJ;
1999-04-07 18:10:10 +00:00
break;
2014-06-19 11:57:29 +00:00
case ZEND_AST_STATIC_PROP:
opline = zend_compile_static_prop(result, var_ast, BP_VAR_IS, 0, 0);
opline->opcode = ZEND_ISSET_ISEMPTY_STATIC_PROP;
2014-06-19 11:57:29 +00:00
break;
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-07 18:10:10 +00:00
}
result->op_type = opline->result_type = IS_TMP_VAR;
if (!(ast->kind == ZEND_AST_ISSET)) {
opline->extended_value |= ZEND_ISEMPTY;
}
1999-04-07 18:10:10 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *expr_ast = ast->child[0];
znode silence_node;
2003-02-10 16:11:24 +00:00
2014-12-13 22:06:14 +00:00
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
2014-06-19 11:57:29 +00:00
if (expr_ast->kind == ZEND_AST_VAR) {
/* For @$var we need to force a FETCH instruction, otherwise the CV access will
* happen outside the silenced section. */
2015-02-02 17:44:16 +00:00
zend_compile_simple_var_no_cv(result, expr_ast, BP_VAR_R, 0 );
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(result, expr_ast);
}
zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL);
2003-02-10 16:11:24 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2003-02-10 16:11:24 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_shell_exec(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *expr_ast = ast->child[0];
2003-08-03 08:21:08 +00:00
2014-06-19 11:57:29 +00:00
zval fn_name;
2014-07-13 11:11:55 +00:00
zend_ast *name_ast, *args_ast, *call_ast;
2014-06-19 11:57:29 +00:00
ZVAL_STRING(&fn_name, "shell_exec");
name_ast = zend_ast_create_zval(&fn_name);
args_ast = zend_ast_create_list(1, ZEND_AST_ARG_LIST, expr_ast);
call_ast = zend_ast_create(ZEND_AST_CALL, name_ast, args_ast);
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(result, call_ast);
2014-06-19 11:57:29 +00:00
2014-07-25 18:24:15 +00:00
zval_ptr_dtor(&fn_name);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast_list *list = zend_ast_get_list(ast);
2014-06-19 11:57:29 +00:00
zend_op *opline;
2014-10-02 09:37:44 +00:00
uint32_t i, opnum_init = -1;
bool packed = 1;
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
if (zend_try_ct_eval_array(&result->u.constant, ast)) {
2007-09-28 19:52:53 +00:00
result->op_type = IS_CONST;
return;
2007-09-28 19:52:53 +00:00
}
2017-05-18 10:18:08 +00:00
/* Empty arrays are handled at compile-time */
ZEND_ASSERT(list->children > 0);
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
zend_ast *value_ast, *key_ast;
bool by_ref;
2016-06-14 10:17:49 +00:00
znode value_node, key_node, *key_node_ptr = NULL;
if (elem_ast == NULL) {
zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
}
value_ast = elem_ast->child[0];
if (elem_ast->kind == ZEND_AST_UNPACK) {
zend_compile_expr(&value_node, value_ast);
if (i == 0) {
opnum_init = get_next_op_number();
opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, NULL, NULL);
}
opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_UNPACK, &value_node, NULL);
SET_NODE(opline->result, result);
continue;
}
key_ast = elem_ast->child[1];
by_ref = elem_ast->attr;
2014-06-19 11:57:29 +00:00
if (key_ast) {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&key_node, key_ast);
zend_handle_numeric_op(&key_node);
2014-06-19 11:57:29 +00:00
key_node_ptr = &key_node;
}
2007-09-28 19:52:53 +00:00
2014-06-19 11:57:29 +00:00
if (by_ref) {
zend_ensure_writable_variable(value_ast);
zend_compile_var(&value_node, value_ast, BP_VAR_W, 1);
2014-06-19 11:57:29 +00:00
} else {
2014-12-13 22:06:14 +00:00
zend_compile_expr(&value_node, value_ast);
}
2014-06-19 11:57:29 +00:00
if (i == 0) {
opnum_init = get_next_op_number();
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr);
opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT;
2014-06-19 11:57:29 +00:00
} else {
2014-07-28 20:03:16 +00:00
opline = zend_emit_op(NULL, ZEND_ADD_ARRAY_ELEMENT,
2014-12-13 22:06:14 +00:00
&value_node, key_node_ptr);
2014-06-19 11:57:29 +00:00
SET_NODE(opline->result, result);
}
2014-06-19 11:57:29 +00:00
opline->extended_value |= by_ref;
if (key_ast && key_node.op_type == IS_CONST && Z_TYPE(key_node.u.constant) == IS_STRING) {
packed = 0;
}
}
2014-06-19 11:57:29 +00:00
/* Add a flag to INIT_ARRAY if we know this array cannot be packed */
if (!packed) {
2016-04-29 11:44:56 +00:00
ZEND_ASSERT(opnum_init != (uint32_t)-1);
2014-06-19 11:57:29 +00:00
opline = &CG(active_op_array)->opcodes[opnum_init];
opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
}
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_const(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *name_ast = ast->child[0];
zend_op *opline;
bool is_fully_qualified;
zend_string *orig_name = zend_ast_get_str(name_ast);
zend_string *resolved_name = zend_resolve_const_name(orig_name, name_ast->attr, &is_fully_qualified);
2014-06-19 11:57:29 +00:00
if (zend_string_equals_literal(resolved_name, "__COMPILER_HALT_OFFSET__") || (name_ast->attr != ZEND_NAME_RELATIVE && zend_string_equals_literal(orig_name, "__COMPILER_HALT_OFFSET__"))) {
zend_ast *last = CG(ast);
while (last && last->kind == ZEND_AST_STMT_LIST) {
zend_ast_list *list = zend_ast_get_list(last);
if (list->children == 0) {
break;
}
last = list->child[list->children-1];
}
if (last && last->kind == ZEND_AST_HALT_COMPILER) {
result->op_type = IS_CONST;
ZVAL_LONG(&result->u.constant, Z_LVAL_P(zend_ast_get_zval(last->child[0])));
zend_string_release_ex(resolved_name, 0);
return;
}
}
if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified)) {
result->op_type = IS_CONST;
zend_string_release_ex(resolved_name, 0);
return;
}
2014-12-13 22:06:14 +00:00
opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL);
2014-06-19 11:57:29 +00:00
opline->op2_type = IS_CONST;
if (is_fully_qualified || !FC(current_namespace)) {
2014-06-19 11:57:29 +00:00
opline->op2.constant = zend_add_const_name_literal(
resolved_name, 0);
2014-06-19 11:57:29 +00:00
} else {
opline->op1.num = IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE;
opline->op2.constant = zend_add_const_name_literal(
resolved_name, 1);
}
opline->extended_value = zend_alloc_cache_slot();
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_class_const(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-19 11:57:29 +00:00
zend_ast *class_ast = ast->child[0];
zend_ast *const_ast = ast->child[1];
2007-09-28 19:52:53 +00:00
2014-06-19 11:57:29 +00:00
znode class_node, const_node;
2015-02-13 14:33:50 +00:00
zend_op *opline;
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
class_ast = ast->child[0];
const_ast = ast->child[1];
if (class_ast->kind == ZEND_AST_ZVAL) {
zend_string *resolved_name;
resolved_name = zend_resolve_class_name_ast(class_ast);
if (const_ast->kind == ZEND_AST_ZVAL && zend_try_ct_eval_class_const(&result->u.constant, resolved_name, zend_ast_get_str(const_ast))) {
result->op_type = IS_CONST;
zend_string_release_ex(resolved_name, 0);
return;
}
zend_string_release_ex(resolved_name, 0);
}
2014-06-19 11:57:29 +00:00
zend_compile_class_ref(&class_node, class_ast, ZEND_FETCH_CLASS_EXCEPTION);
2007-09-28 19:52:53 +00:00
2014-12-13 22:06:14 +00:00
zend_compile_expr(&const_node, const_ast);
2014-06-19 11:57:29 +00:00
opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_CONSTANT, NULL, &const_node);
2014-06-19 11:57:29 +00:00
2014-12-13 22:06:14 +00:00
zend_set_class_name_op1(opline, &class_node);
2014-06-19 11:57:29 +00:00
opline->extended_value = zend_alloc_cache_slots(2);
2014-06-19 11:57:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-19 11:57:29 +00:00
void zend_compile_class_name(znode *result, zend_ast *ast) /* {{{ */
{
zend_ast *class_ast = ast->child[0];
if (zend_try_compile_const_expr_resolve_class_name(&result->u.constant, class_ast)) {
result->op_type = IS_CONST;
return;
}
if (class_ast->kind == ZEND_AST_ZVAL) {
zend_op *opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
opline->op1.num = zend_get_class_fetch_type(zend_ast_get_str(class_ast));
} else {
znode expr_node;
zend_compile_expr(&expr_node, class_ast);
if (expr_node.op_type == IS_CONST) {
/* Unlikely case that happen if class_ast is constant folded.
* Handle it here, to avoid needing a CONST specialization in the VM. */
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use \"::class\" on value of type %s",
zend_zval_type_name(&expr_node.u.constant));
}
zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, &expr_node, NULL);
}
}
/* }}} */
static zend_op *zend_compile_rope_add_ex(zend_op *opline, znode *result, uint32_t num, znode *elem_node) /* {{{ */
{
if (num == 0) {
result->op_type = IS_TMP_VAR;
result->u.op.var = -1;
opline->opcode = ZEND_ROPE_INIT;
} else {
opline->opcode = ZEND_ROPE_ADD;
SET_NODE(opline->op1, result);
}
SET_NODE(opline->op2, elem_node);
SET_NODE(opline->result, result);
opline->extended_value = num;
return opline;
}
/* }}} */
static zend_op *zend_compile_rope_add(znode *result, uint32_t num, znode *elem_node) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline = get_next_op();
2014-06-21 18:03:29 +00:00
if (num == 0) {
result->op_type = IS_TMP_VAR;
result->u.op.var = -1;
opline->opcode = ZEND_ROPE_INIT;
} else {
opline->opcode = ZEND_ROPE_ADD;
SET_NODE(opline->op1, result);
}
SET_NODE(opline->op2, elem_node);
SET_NODE(opline->result, result);
opline->extended_value = num;
return opline;
}
/* }}} */
2007-09-28 19:52:53 +00:00
static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */
{
uint32_t i, j;
uint32_t rope_init_lineno = -1;
zend_op *opline = NULL, *init_opline;
znode elem_node, last_const_node;
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t reserved_op_number = -1;
2014-06-21 18:03:29 +00:00
ZEND_ASSERT(list->children > 0);
2014-06-21 18:03:29 +00:00
j = 0;
last_const_node.op_type = IS_UNUSED;
for (i = 0; i < list->children; i++) {
zend_compile_expr(&elem_node, list->child[i]);
if (elem_node.op_type == IS_CONST) {
convert_to_string(&elem_node.u.constant);
if (Z_STRLEN(elem_node.u.constant) == 0) {
zval_ptr_dtor(&elem_node.u.constant);
} else if (last_const_node.op_type == IS_CONST) {
concat_function(&last_const_node.u.constant, &last_const_node.u.constant, &elem_node.u.constant);
zval_ptr_dtor(&elem_node.u.constant);
2014-06-21 18:03:29 +00:00
} else {
last_const_node.op_type = IS_CONST;
ZVAL_COPY_VALUE(&last_const_node.u.constant, &elem_node.u.constant);
/* Reserve place for ZEND_ROPE_ADD instruction */
reserved_op_number = get_next_op_number();
opline = get_next_op();
opline->opcode = ZEND_NOP;
}
continue;
2014-06-21 18:03:29 +00:00
} else {
if (j == 0) {
if (last_const_node.op_type == IS_CONST) {
rope_init_lineno = reserved_op_number;
} else {
rope_init_lineno = get_next_op_number();
}
}
if (last_const_node.op_type == IS_CONST) {
opline = &CG(active_op_array)->opcodes[reserved_op_number];
zend_compile_rope_add_ex(opline, result, j++, &last_const_node);
last_const_node.op_type = IS_UNUSED;
}
opline = zend_compile_rope_add(result, j++, &elem_node);
}
}
if (j == 0) {
result->op_type = IS_CONST;
if (last_const_node.op_type == IS_CONST) {
ZVAL_COPY_VALUE(&result->u.constant, &last_const_node.u.constant);
} else {
ZVAL_EMPTY_STRING(&result->u.constant);
/* empty string */
}
CG(active_op_array)->last = reserved_op_number - 1;
return;
} else if (last_const_node.op_type == IS_CONST) {
opline = &CG(active_op_array)->opcodes[reserved_op_number];
opline = zend_compile_rope_add_ex(opline, result, j++, &last_const_node);
}
init_opline = CG(active_op_array)->opcodes + rope_init_lineno;
if (j == 1) {
if (opline->op2_type == IS_CONST) {
GET_NODE(result, opline->op2);
MAKE_NOP(opline);
2014-06-21 18:03:29 +00:00
} else {
opline->opcode = ZEND_CAST;
opline->extended_value = IS_STRING;
opline->op1_type = opline->op2_type;
opline->op1 = opline->op2;
SET_UNUSED(opline->op2);
zend_make_tmp_result(result, opline);
}
} else if (j == 2) {
opline->opcode = ZEND_FAST_CONCAT;
opline->extended_value = 0;
opline->op1_type = init_opline->op2_type;
opline->op1 = init_opline->op2;
zend_make_tmp_result(result, opline);
MAKE_NOP(init_opline);
} else {
uint32_t var;
init_opline->extended_value = j;
opline->opcode = ZEND_ROPE_END;
zend_make_tmp_result(result, opline);
var = opline->op1.var = get_temporary_variable();
/* Allocates the necessary number of zval slots to keep the rope */
i = ((j * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
while (i > 1) {
get_temporary_variable();
i--;
}
/* Update all the previous opcodes to use the same variable */
while (opline != init_opline) {
opline--;
if (opline->opcode == ZEND_ROPE_ADD &&
2016-04-29 11:44:56 +00:00
opline->result.var == (uint32_t)-1) {
opline->op1.var = var;
opline->result.var = var;
} else if (opline->opcode == ZEND_ROPE_INIT &&
2016-04-29 11:44:56 +00:00
opline->result.var == (uint32_t)-1) {
opline->result.var = var;
}
}
2007-09-28 19:52:53 +00:00
}
2014-06-21 18:03:29 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-21 18:03:29 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_magic_const(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_op *opline;
2014-12-13 22:06:14 +00:00
if (zend_try_ct_eval_magic_const(&result->u.constant, ast)) {
2014-07-21 16:02:31 +00:00
result->op_type = IS_CONST;
return;
2007-09-28 19:52:53 +00:00
}
2014-07-21 16:02:31 +00:00
2014-11-27 09:52:31 +00:00
ZEND_ASSERT(ast->attr == T_CLASS_C &&
CG(active_class_entry) &&
(CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT) != 0);
2014-07-21 16:02:31 +00:00
opline = zend_emit_op_tmp(result, ZEND_FETCH_CLASS_NAME, NULL, NULL);
opline->op1.num = ZEND_FETCH_CLASS_SELF;
2014-07-16 21:10:16 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-07-16 21:10:16 +00:00
bool zend_is_allowed_in_const_expr(zend_ast_kind kind) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-28 16:03:26 +00:00
return kind == ZEND_AST_ZVAL || kind == ZEND_AST_BINARY_OP
2014-06-26 20:02:54 +00:00
|| kind == ZEND_AST_GREATER || kind == ZEND_AST_GREATER_EQUAL
|| kind == ZEND_AST_AND || kind == ZEND_AST_OR
|| kind == ZEND_AST_UNARY_OP
|| kind == ZEND_AST_UNARY_PLUS || kind == ZEND_AST_UNARY_MINUS
2014-08-16 20:08:02 +00:00
|| kind == ZEND_AST_CONDITIONAL || kind == ZEND_AST_DIM
2014-06-26 14:35:30 +00:00
|| kind == ZEND_AST_ARRAY || kind == ZEND_AST_ARRAY_ELEM
|| kind == ZEND_AST_UNPACK
|| kind == ZEND_AST_CONST || kind == ZEND_AST_CLASS_CONST
|| kind == ZEND_AST_CLASS_NAME
|| kind == ZEND_AST_MAGIC_CONST || kind == ZEND_AST_COALESCE
|| kind == ZEND_AST_CONST_ENUM_INIT;
2014-06-26 14:35:30 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-06-26 14:35:30 +00:00
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_class_const(zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-26 14:35:30 +00:00
zend_ast *ast = *ast_ptr;
zend_ast *class_ast = ast->child[0];
zend_string *class_name;
2014-06-26 14:35:30 +00:00
int fetch_type;
2014-06-28 16:03:26 +00:00
if (class_ast->kind != ZEND_AST_ZVAL) {
2014-06-26 14:35:30 +00:00
zend_error_noreturn(E_COMPILE_ERROR,
"Dynamic class names are not allowed in compile-time class constant references");
2007-09-28 19:52:53 +00:00
}
class_name = zend_ast_get_str(class_ast);
fetch_type = zend_get_class_fetch_type(class_name);
2014-06-26 14:35:30 +00:00
if (ZEND_FETCH_CLASS_STATIC == fetch_type) {
zend_error_noreturn(E_COMPILE_ERROR,
"\"static::\" is not allowed in compile-time constants");
2014-07-19 21:30:07 +00:00
}
2015-01-03 09:22:58 +00:00
2014-07-19 21:30:07 +00:00
if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) {
zend_string *tmp = zend_resolve_class_name_ast(class_ast);
zend_string_release_ex(class_name, 0);
if (tmp != class_name) {
zval *zv = zend_ast_get_zval(class_ast);
2014-06-26 14:35:30 +00:00
ZVAL_STR(zv, tmp);
}
}
ast->attr |= ZEND_FETCH_CLASS_EXCEPTION;
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_compile_const_expr_class_name(zend_ast **ast_ptr) /* {{{ */
{
zend_ast *ast = *ast_ptr;
zend_ast *class_ast = ast->child[0];
if (class_ast->kind != ZEND_AST_ZVAL) {
zend_error_noreturn(E_COMPILE_ERROR,
"(expression)::class cannot be used in constant expressions");
}
zend_string *class_name = zend_ast_get_str(class_ast);
uint32_t fetch_type = zend_get_class_fetch_type(class_name);
switch (fetch_type) {
case ZEND_FETCH_CLASS_SELF:
case ZEND_FETCH_CLASS_PARENT:
/* For the const-eval representation store the fetch type instead of the name. */
zend_string_release(class_name);
ast->child[0] = NULL;
ast->attr = fetch_type;
return;
case ZEND_FETCH_CLASS_STATIC:
zend_error_noreturn(E_COMPILE_ERROR,
"static::class cannot be used for compile-time class name resolution");
return;
EMPTY_SWITCH_DEFAULT_CASE()
}
}
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_const(zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-06-26 14:56:50 +00:00
zend_ast *ast = *ast_ptr;
zend_ast *name_ast = ast->child[0];
zend_string *orig_name = zend_ast_get_str(name_ast);
bool is_fully_qualified;
zval result;
zend_string *resolved_name;
2014-06-26 14:56:50 +00:00
resolved_name = zend_resolve_const_name(
orig_name, name_ast->attr, &is_fully_qualified);
2014-06-26 14:56:50 +00:00
if (zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) {
zend_string_release_ex(resolved_name, 0);
2014-06-26 14:56:50 +00:00
zend_ast_destroy(ast);
*ast_ptr = zend_ast_create_zval(&result);
2014-06-26 14:56:50 +00:00
return;
}
zend_ast_destroy(ast);
2019-03-28 08:31:18 +00:00
*ast_ptr = zend_ast_create_constant(resolved_name,
!is_fully_qualified && FC(current_namespace) ? IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE : 0);
2014-06-26 14:56:50 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr_magic_const(zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-21 16:21:13 +00:00
zend_ast *ast = *ast_ptr;
2013-11-09 02:37:38 +00:00
2014-07-21 16:21:13 +00:00
/* Other cases already resolved by constant folding */
ZEND_ASSERT(ast->attr == T_CLASS_C);
2013-11-09 02:37:38 +00:00
zend_ast_destroy(ast);
*ast_ptr = zend_ast_create(ZEND_AST_CONSTANT_CLASS);
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_const_expr(zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_ast *ast = *ast_ptr;
2014-06-28 16:03:26 +00:00
if (ast == NULL || ast->kind == ZEND_AST_ZVAL) {
return;
}
if (!zend_is_allowed_in_const_expr(ast->kind)) {
zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations");
}
2014-06-26 14:35:30 +00:00
switch (ast->kind) {
case ZEND_AST_CLASS_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_class_const(ast_ptr);
2014-06-26 14:35:30 +00:00
break;
case ZEND_AST_CLASS_NAME:
zend_compile_const_expr_class_name(ast_ptr);
break;
2014-06-26 14:56:50 +00:00
case ZEND_AST_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_const(ast_ptr);
2014-06-26 14:56:50 +00:00
break;
2014-07-21 16:21:13 +00:00
case ZEND_AST_MAGIC_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_const_expr_magic_const(ast_ptr);
2014-07-21 16:21:13 +00:00
break;
2014-07-30 15:29:59 +00:00
default:
2014-12-13 22:06:14 +00:00
zend_ast_apply(ast, zend_compile_const_expr);
2014-07-30 15:29:59 +00:00
break;
2014-06-26 14:35:30 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
void zend_const_expr_to_zval(zval *result, zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
zend_eval_const_expr(ast_ptr);
zend_compile_const_expr(ast_ptr);
if ((*ast_ptr)->kind != ZEND_AST_ZVAL) {
/* Replace with compiled AST zval representation. */
zval ast_zv;
ZVAL_AST(&ast_zv, zend_ast_copy(*ast_ptr));
zend_ast_destroy(*ast_ptr);
*ast_ptr = zend_ast_create_zval(&ast_zv);
2007-09-28 19:52:53 +00:00
}
ZVAL_COPY(result, zend_ast_get_zval(*ast_ptr));
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
/* Same as compile_stmt, but with early binding */
2014-12-13 22:06:14 +00:00
void zend_compile_top_stmt(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (!ast) {
return;
2007-09-28 19:52:53 +00:00
}
if (ast->kind == ZEND_AST_STMT_LIST) {
zend_ast_list *list = zend_ast_get_list(ast);
uint32_t i;
for (i = 0; i < list->children; ++i) {
2014-12-13 22:06:14 +00:00
zend_compile_top_stmt(list->child[i]);
}
return;
}
if (ast->kind == ZEND_AST_FUNC_DECL) {
CG(zend_lineno) = ast->lineno;
zend_compile_func_decl(NULL, ast, 1);
CG(zend_lineno) = ((zend_ast_decl *) ast)->end_lineno;
} else if (ast->kind == ZEND_AST_CLASS) {
CG(zend_lineno) = ast->lineno;
zend_compile_class_decl(NULL, ast, 1);
CG(zend_lineno) = ((zend_ast_decl *) ast)->end_lineno;
} else {
zend_compile_stmt(ast);
}
2014-07-22 13:50:23 +00:00
if (ast->kind != ZEND_AST_NAMESPACE && ast->kind != ZEND_AST_HALT_COMPILER) {
2014-12-13 22:06:14 +00:00
zend_verify_namespace();
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_compile_stmt(zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
if (!ast) {
return;
2007-09-28 19:52:53 +00:00
}
2014-07-12 15:10:10 +00:00
CG(zend_lineno) = ast->lineno;
if ((CG(compiler_options) & ZEND_COMPILE_EXTENDED_STMT) && !zend_is_unticked_stmt(ast)) {
zend_do_extended_stmt();
}
2014-06-07 11:06:53 +00:00
switch (ast->kind) {
case ZEND_AST_STMT_LIST:
2014-12-13 22:06:14 +00:00
zend_compile_stmt_list(ast);
2014-07-09 22:00:48 +00:00
break;
2014-06-07 11:06:53 +00:00
case ZEND_AST_GLOBAL:
2014-12-13 22:06:14 +00:00
zend_compile_global_var(ast);
2014-07-09 22:00:48 +00:00
break;
case ZEND_AST_STATIC:
2014-12-13 22:06:14 +00:00
zend_compile_static_var(ast);
break;
2014-06-07 11:06:53 +00:00
case ZEND_AST_UNSET:
2014-12-13 22:06:14 +00:00
zend_compile_unset(ast);
2014-07-09 22:00:48 +00:00
break;
2014-07-07 19:06:02 +00:00
case ZEND_AST_RETURN:
2014-12-13 22:06:14 +00:00
zend_compile_return(ast);
2014-07-09 22:00:48 +00:00
break;
case ZEND_AST_ECHO:
2014-12-13 22:06:14 +00:00
zend_compile_echo(ast);
2014-07-09 22:00:48 +00:00
break;
case ZEND_AST_BREAK:
case ZEND_AST_CONTINUE:
2014-12-13 22:06:14 +00:00
zend_compile_break_continue(ast);
2014-07-09 22:00:48 +00:00
break;
case ZEND_AST_GOTO:
2014-12-13 22:06:14 +00:00
zend_compile_goto(ast);
2014-07-09 22:00:48 +00:00
break;
2014-07-09 21:46:22 +00:00
case ZEND_AST_LABEL:
2014-12-13 22:06:14 +00:00
zend_compile_label(ast);
2014-07-09 22:00:48 +00:00
break;
case ZEND_AST_WHILE:
2014-12-13 22:06:14 +00:00
zend_compile_while(ast);
break;
2014-07-10 12:46:22 +00:00
case ZEND_AST_DO_WHILE:
2014-12-13 22:06:14 +00:00
zend_compile_do_while(ast);
2014-07-10 12:46:22 +00:00
break;
2014-07-10 13:51:47 +00:00
case ZEND_AST_FOR:
2014-12-13 22:06:14 +00:00
zend_compile_for(ast);
2014-07-10 13:51:47 +00:00
break;
2014-07-11 10:16:21 +00:00
case ZEND_AST_FOREACH:
2014-12-13 22:06:14 +00:00
zend_compile_foreach(ast);
2014-07-11 10:16:21 +00:00
break;
2014-07-10 14:38:04 +00:00
case ZEND_AST_IF:
2014-12-13 22:06:14 +00:00
zend_compile_if(ast);
2014-07-10 14:38:04 +00:00
break;
2014-07-11 13:31:47 +00:00
case ZEND_AST_SWITCH:
2014-12-13 22:06:14 +00:00
zend_compile_switch(ast);
2014-07-11 13:31:47 +00:00
break;
case ZEND_AST_TRY:
2014-12-13 22:06:14 +00:00
zend_compile_try(ast);
break;
2014-07-22 14:11:19 +00:00
case ZEND_AST_DECLARE:
2014-12-13 22:06:14 +00:00
zend_compile_declare(ast);
2014-07-22 14:11:19 +00:00
break;
case ZEND_AST_FUNC_DECL:
case ZEND_AST_METHOD:
zend_compile_func_decl(NULL, ast, 0);
break;
case ZEND_AST_ENUM_CASE:
zend_compile_enum_case(ast);
break;
case ZEND_AST_PROP_GROUP:
zend_compile_prop_group(ast);
2014-07-19 12:54:56 +00:00
break;
case ZEND_AST_CLASS_CONST_GROUP:
zend_compile_class_const_group(ast);
2014-07-19 13:13:50 +00:00
break;
2014-07-19 20:39:01 +00:00
case ZEND_AST_USE_TRAIT:
2014-12-13 22:06:14 +00:00
zend_compile_use_trait(ast);
2014-07-19 20:39:01 +00:00
break;
2014-07-21 14:34:45 +00:00
case ZEND_AST_CLASS:
zend_compile_class_decl(NULL, ast, 0);
2014-07-21 14:34:45 +00:00
break;
case ZEND_AST_GROUP_USE:
zend_compile_group_use(ast);
break;
2014-07-21 20:49:31 +00:00
case ZEND_AST_USE:
2014-12-13 22:06:14 +00:00
zend_compile_use(ast);
2014-07-21 20:49:31 +00:00
break;
2014-07-22 09:55:07 +00:00
case ZEND_AST_CONST_DECL:
2014-12-13 22:06:14 +00:00
zend_compile_const_decl(ast);
2014-07-22 09:55:07 +00:00
break;
2014-07-22 10:45:44 +00:00
case ZEND_AST_NAMESPACE:
2014-12-13 22:06:14 +00:00
zend_compile_namespace(ast);
2014-07-22 10:45:44 +00:00
break;
case ZEND_AST_HALT_COMPILER:
2014-12-13 22:06:14 +00:00
zend_compile_halt_compiler(ast);
break;
case ZEND_AST_THROW:
zend_compile_expr(NULL, ast);
break;
2014-07-09 22:04:27 +00:00
default:
{
znode result;
2014-12-13 22:06:14 +00:00
zend_compile_expr(&result, ast);
zend_do_free(&result);
2014-07-09 22:04:27 +00:00
}
}
2014-07-09 22:00:48 +00:00
if (FC(declarables).ticks && !zend_is_unticked_stmt(ast)) {
2014-12-13 22:06:14 +00:00
zend_emit_tick();
}
2007-09-28 19:52:53 +00:00
}
2014-08-29 05:05:58 +00:00
/* }}} */
2007-09-28 19:52:53 +00:00
static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
2014-08-29 05:05:58 +00:00
{
/* CG(zend_lineno) = ast->lineno; */
CG(zend_lineno) = zend_ast_get_lineno(ast);
if (CG(memoize_mode) != ZEND_MEMOIZE_NONE) {
zend_compile_memoized_expr(result, ast);
return;
}
2014-06-07 11:06:53 +00:00
switch (ast->kind) {
2014-06-28 16:03:26 +00:00
case ZEND_AST_ZVAL:
2014-06-07 11:06:53 +00:00
ZVAL_COPY(&result->u.constant, zend_ast_get_zval(ast));
result->op_type = IS_CONST;
return;
case ZEND_AST_ZNODE:
*result = *zend_ast_get_znode(ast);
return;
case ZEND_AST_VAR:
case ZEND_AST_DIM:
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_PROP:
case ZEND_AST_CALL:
case ZEND_AST_METHOD_CALL:
case ZEND_AST_NULLSAFE_METHOD_CALL:
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_CALL:
zend_compile_var(result, ast, BP_VAR_R, 0);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_ASSIGN:
2014-12-13 22:06:14 +00:00
zend_compile_assign(result, ast);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_ASSIGN_REF:
2014-12-13 22:06:14 +00:00
zend_compile_assign_ref(result, ast);
2014-06-07 11:06:53 +00:00
return;
case ZEND_AST_NEW:
2014-12-13 22:06:14 +00:00
zend_compile_new(result, ast);
return;
case ZEND_AST_CLONE:
2014-12-13 22:06:14 +00:00
zend_compile_clone(result, ast);
return;
2014-06-19 11:57:29 +00:00
case ZEND_AST_ASSIGN_OP:
2014-12-13 22:06:14 +00:00
zend_compile_compound_assign(result, ast);
2014-06-07 11:06:53 +00:00
return;
2014-06-19 11:57:29 +00:00
case ZEND_AST_BINARY_OP:
2014-12-13 22:06:14 +00:00
zend_compile_binary_op(result, ast);
return;
case ZEND_AST_GREATER:
case ZEND_AST_GREATER_EQUAL:
2014-12-13 22:06:14 +00:00
zend_compile_greater(result, ast);
return;
case ZEND_AST_UNARY_OP:
2014-12-13 22:06:14 +00:00
zend_compile_unary_op(result, ast);
return;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_PLUS:
case ZEND_AST_UNARY_MINUS:
2014-12-13 22:06:14 +00:00
zend_compile_unary_pm(result, ast);
return;
case ZEND_AST_AND:
case ZEND_AST_OR:
2014-12-13 22:06:14 +00:00
zend_compile_short_circuiting(result, ast);
return;
case ZEND_AST_POST_INC:
case ZEND_AST_POST_DEC:
2014-12-13 22:06:14 +00:00
zend_compile_post_incdec(result, ast);
return;
case ZEND_AST_PRE_INC:
case ZEND_AST_PRE_DEC:
2014-12-13 22:06:14 +00:00
zend_compile_pre_incdec(result, ast);
return;
2014-06-19 11:57:29 +00:00
case ZEND_AST_CAST:
2014-12-13 22:06:14 +00:00
zend_compile_cast(result, ast);
return;
case ZEND_AST_CONDITIONAL:
2014-12-13 22:06:14 +00:00
zend_compile_conditional(result, ast);
return;
case ZEND_AST_COALESCE:
2014-12-13 22:06:14 +00:00
zend_compile_coalesce(result, ast);
return;
case ZEND_AST_ASSIGN_COALESCE:
zend_compile_assign_coalesce(result, ast);
return;
case ZEND_AST_PRINT:
2014-12-13 22:06:14 +00:00
zend_compile_print(result, ast);
return;
case ZEND_AST_EXIT:
2014-12-13 22:06:14 +00:00
zend_compile_exit(result, ast);
return;
case ZEND_AST_YIELD:
2014-12-13 22:06:14 +00:00
zend_compile_yield(result, ast);
return;
2015-02-20 11:59:56 +00:00
case ZEND_AST_YIELD_FROM:
zend_compile_yield_from(result, ast);
return;
case ZEND_AST_INSTANCEOF:
2014-12-13 22:06:14 +00:00
zend_compile_instanceof(result, ast);
return;
case ZEND_AST_INCLUDE_OR_EVAL:
2014-12-13 22:06:14 +00:00
zend_compile_include_or_eval(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_ISSET:
case ZEND_AST_EMPTY:
2014-12-13 22:06:14 +00:00
zend_compile_isset_or_empty(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_SILENCE:
2014-12-13 22:06:14 +00:00
zend_compile_silence(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_SHELL_EXEC:
2014-12-13 22:06:14 +00:00
zend_compile_shell_exec(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_ARRAY:
2014-12-13 22:06:14 +00:00
zend_compile_array(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_const(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_CLASS_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_class_const(result, ast);
2014-06-19 11:57:29 +00:00
return;
case ZEND_AST_CLASS_NAME:
zend_compile_class_name(result, ast);
return;
2014-06-21 18:03:29 +00:00
case ZEND_AST_ENCAPS_LIST:
2014-12-13 22:06:14 +00:00
zend_compile_encaps_list(result, ast);
2014-06-21 18:03:29 +00:00
return;
2014-07-16 21:10:16 +00:00
case ZEND_AST_MAGIC_CONST:
2014-12-13 22:06:14 +00:00
zend_compile_magic_const(result, ast);
2014-07-16 21:10:16 +00:00
return;
2014-07-18 10:58:24 +00:00
case ZEND_AST_CLOSURE:
case ZEND_AST_ARROW_FUNC:
zend_compile_func_decl(result, ast, 0);
2014-07-18 10:58:24 +00:00
return;
case ZEND_AST_THROW:
zend_compile_throw(result, ast);
return;
case ZEND_AST_MATCH:
zend_compile_match(result, ast);
return;
2014-06-07 11:06:53 +00:00
default:
ZEND_ASSERT(0 /* not supported */);
2013-11-06 18:21:07 +00:00
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2013-11-06 18:21:07 +00:00
void zend_compile_expr(znode *result, zend_ast *ast)
{
uint32_t checkpoint = zend_short_circuiting_checkpoint();
zend_compile_expr_inner(result, ast);
zend_short_circuiting_commit(checkpoint, result, ast);
}
static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t type, bool by_ref)
2014-08-29 05:05:58 +00:00
{
CG(zend_lineno) = zend_ast_get_lineno(ast);
2014-06-07 11:06:53 +00:00
switch (ast->kind) {
case ZEND_AST_VAR:
return zend_compile_simple_var(result, ast, type, 0);
2014-06-07 11:06:53 +00:00
case ZEND_AST_DIM:
return zend_compile_dim(result, ast, type);
2014-06-07 11:06:53 +00:00
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
return zend_compile_prop(result, ast, type, by_ref);
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_PROP:
return zend_compile_static_prop(result, ast, type, by_ref, 0);
2014-06-07 11:06:53 +00:00
case ZEND_AST_CALL:
2014-12-13 22:06:14 +00:00
zend_compile_call(result, ast, type);
return NULL;
2014-06-07 11:06:53 +00:00
case ZEND_AST_METHOD_CALL:
case ZEND_AST_NULLSAFE_METHOD_CALL:
2014-12-13 22:06:14 +00:00
zend_compile_method_call(result, ast, type);
return NULL;
2014-06-07 11:06:53 +00:00
case ZEND_AST_STATIC_CALL:
2014-12-13 22:06:14 +00:00
zend_compile_static_call(result, ast, type);
return NULL;
case ZEND_AST_ZNODE:
*result = *zend_ast_get_znode(ast);
return NULL;
2014-06-07 11:06:53 +00:00
default:
if (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) {
2014-09-10 13:55:26 +00:00
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot use temporary expression in write context");
2014-06-19 11:57:29 +00:00
}
2014-12-13 22:06:14 +00:00
zend_compile_expr(result, ast);
return NULL;
2011-01-19 17:17:52 +00:00
}
2014-06-07 11:06:53 +00:00
}
zend_op *zend_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
{
uint32_t checkpoint = zend_short_circuiting_checkpoint();
zend_op *opcode = zend_compile_var_inner(result, ast, type, by_ref);
zend_short_circuiting_commit(checkpoint, result, ast);
return opcode;
}
zend_op *zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type, bool by_ref) /* {{{ */
2014-08-29 05:05:58 +00:00
{
switch (ast->kind) {
2015-02-02 17:44:16 +00:00
case ZEND_AST_VAR:
return zend_compile_simple_var(result, ast, type, 1);
case ZEND_AST_DIM:
return zend_delayed_compile_dim(result, ast, type);
case ZEND_AST_PROP:
case ZEND_AST_NULLSAFE_PROP:
{
zend_op *opline = zend_delayed_compile_prop(result, ast, type);
if (by_ref) {
opline->extended_value |= ZEND_FETCH_REF;
}
return opline;
}
2015-02-02 17:44:16 +00:00
case ZEND_AST_STATIC_PROP:
return zend_compile_static_prop(result, ast, type, by_ref, 1);
default:
return zend_compile_var(result, ast, type, 0);
}
}
2014-08-29 05:05:58 +00:00
/* }}} */
2014-12-13 22:06:14 +00:00
void zend_eval_const_expr(zend_ast **ast_ptr) /* {{{ */
2014-08-29 05:05:58 +00:00
{
2014-07-21 16:02:31 +00:00
zend_ast *ast = *ast_ptr;
zval result;
2014-07-30 15:29:59 +00:00
if (!ast) {
return;
}
switch (ast->kind) {
case ZEND_AST_BINARY_OP:
2014-12-13 22:06:14 +00:00
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
return;
}
if (!zend_try_ct_eval_binary_op(&result, ast->attr,
zend_ast_get_zval(ast->child[0]), zend_ast_get_zval(ast->child[1]))
) {
return;
}
break;
2014-06-26 10:43:20 +00:00
case ZEND_AST_GREATER:
case ZEND_AST_GREATER_EQUAL:
2014-12-13 22:06:14 +00:00
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
return;
}
zend_ct_eval_greater(&result, ast->kind,
2014-12-13 22:06:14 +00:00
zend_ast_get_zval(ast->child[0]), zend_ast_get_zval(ast->child[1]));
2014-06-26 10:43:20 +00:00
break;
case ZEND_AST_AND:
case ZEND_AST_OR:
{
bool child0_is_true, child1_is_true;
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
if (ast->child[0]->kind != ZEND_AST_ZVAL) {
return;
}
child0_is_true = zend_is_true(zend_ast_get_zval(ast->child[0]));
if (child0_is_true == (ast->kind == ZEND_AST_OR)) {
ZVAL_BOOL(&result, ast->kind == ZEND_AST_OR);
break;
}
if (ast->child[1]->kind != ZEND_AST_ZVAL) {
return;
}
child1_is_true = zend_is_true(zend_ast_get_zval(ast->child[1]));
if (ast->kind == ZEND_AST_OR) {
ZVAL_BOOL(&result, child0_is_true || child1_is_true);
} else {
ZVAL_BOOL(&result, child0_is_true && child1_is_true);
}
break;
}
case ZEND_AST_UNARY_OP:
zend_eval_const_expr(&ast->child[0]);
if (ast->child[0]->kind != ZEND_AST_ZVAL) {
return;
}
if (!zend_try_ct_eval_unary_op(&result, ast->attr, zend_ast_get_zval(ast->child[0]))) {
return;
}
break;
2014-06-26 10:43:20 +00:00
case ZEND_AST_UNARY_PLUS:
case ZEND_AST_UNARY_MINUS:
2014-12-13 22:06:14 +00:00
zend_eval_const_expr(&ast->child[0]);
if (ast->child[0]->kind != ZEND_AST_ZVAL) {
return;
}
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 00:44:27 +00:00
if (!zend_try_ct_eval_unary_pm(&result, ast->kind, zend_ast_get_zval(ast->child[0]))) {
return;
}
break;
case ZEND_AST_COALESCE:
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if (ast->child[0]->kind == ZEND_AST_DIM) {
ast->child[0]->attr |= ZEND_DIM_IS;
}
zend_eval_const_expr(&ast->child[0]);
if (ast->child[0]->kind != ZEND_AST_ZVAL) {
/* ensure everything was compile-time evaluated at least once */
zend_eval_const_expr(&ast->child[1]);
return;
}
if (Z_TYPE_P(zend_ast_get_zval(ast->child[0])) == IS_NULL) {
zend_eval_const_expr(&ast->child[1]);
*ast_ptr = ast->child[1];
ast->child[1] = NULL;
zend_ast_destroy(ast);
} else {
*ast_ptr = ast->child[0];
ast->child[0] = NULL;
zend_ast_destroy(ast);
}
return;
case ZEND_AST_CONDITIONAL:
{
zend_ast **child, *child_ast;
zend_eval_const_expr(&ast->child[0]);
if (ast->child[0]->kind != ZEND_AST_ZVAL) {
/* ensure everything was compile-time evaluated at least once */
if (ast->child[1]) {
zend_eval_const_expr(&ast->child[1]);
}
zend_eval_const_expr(&ast->child[2]);
return;
}
child = &ast->child[2 - zend_is_true(zend_ast_get_zval(ast->child[0]))];
if (*child == NULL) {
child--;
}
child_ast = *child;
*child = NULL;
zend_ast_destroy(ast);
*ast_ptr = child_ast;
zend_eval_const_expr(ast_ptr);
return;
}
case ZEND_AST_DIM:
{
/* constant expression should be always read context ... */
zval *container, *dim;
if (ast->child[1] == NULL) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
}
if (ast->attr & ZEND_DIM_ALTERNATIVE_SYNTAX) {
ast->attr &= ~ZEND_DIM_ALTERNATIVE_SYNTAX; /* remove flag to avoid duplicate warning */
zend_error(E_COMPILE_ERROR, "Array and string offset access syntax with curly braces is no longer supported");
}
/* Set isset fetch indicator here, opcache disallows runtime altering of the AST */
if ((ast->attr & ZEND_DIM_IS) && ast->child[0]->kind == ZEND_AST_DIM) {
ast->child[0]->attr |= ZEND_DIM_IS;
}
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
if (ast->child[0]->kind != ZEND_AST_ZVAL || ast->child[1]->kind != ZEND_AST_ZVAL) {
return;
}
container = zend_ast_get_zval(ast->child[0]);
dim = zend_ast_get_zval(ast->child[1]);
if (Z_TYPE_P(container) == IS_ARRAY) {
zval *el;
if (Z_TYPE_P(dim) == IS_LONG) {
el = zend_hash_index_find(Z_ARR_P(container), Z_LVAL_P(dim));
if (el) {
ZVAL_COPY(&result, el);
} else {
return;
}
} else if (Z_TYPE_P(dim) == IS_STRING) {
el = zend_symtable_find(Z_ARR_P(container), Z_STR_P(dim));
if (el) {
ZVAL_COPY(&result, el);
} else {
return;
}
} else {
return; /* warning... handle at runtime */
}
} else if (Z_TYPE_P(container) == IS_STRING) {
zend_long offset;
zend_uchar c;
if (Z_TYPE_P(dim) == IS_LONG) {
offset = Z_LVAL_P(dim);
} else if (Z_TYPE_P(dim) != IS_STRING || is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, 1) != IS_LONG) {
return;
}
2015-09-23 20:19:05 +00:00
if (offset < 0 || (size_t)offset >= Z_STRLEN_P(container)) {
return;
}
c = (zend_uchar) Z_STRVAL_P(container)[offset];
ZVAL_CHAR(&result, c);
} else if (Z_TYPE_P(container) <= IS_FALSE) {
ZVAL_NULL(&result);
} else {
return;
}
2014-06-26 10:43:20 +00:00
break;
}
case ZEND_AST_ARRAY:
2014-12-13 22:06:14 +00:00
if (!zend_try_ct_eval_array(&result, ast)) {
return;
}
break;
2014-07-21 16:02:31 +00:00
case ZEND_AST_MAGIC_CONST:
2014-12-13 22:06:14 +00:00
if (!zend_try_ct_eval_magic_const(&result, ast)) {
return;
}
2014-07-21 16:02:31 +00:00
break;
case ZEND_AST_CONST:
{
zend_ast *name_ast = ast->child[0];
bool is_fully_qualified;
zend_string *resolved_name = zend_resolve_const_name(
2014-12-13 22:06:14 +00:00
zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified);
2014-12-13 22:06:14 +00:00
if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified)) {
zend_string_release_ex(resolved_name, 0);
return;
}
zend_string_release_ex(resolved_name, 0);
break;
}
case ZEND_AST_CLASS_CONST:
{
zend_ast *class_ast;
zend_ast *name_ast;
zend_string *resolved_name;
zend_eval_const_expr(&ast->child[0]);
zend_eval_const_expr(&ast->child[1]);
class_ast = ast->child[0];
name_ast = ast->child[1];
if (class_ast->kind != ZEND_AST_ZVAL || name_ast->kind != ZEND_AST_ZVAL) {
return;
}
resolved_name = zend_resolve_class_name_ast(class_ast);
if (!zend_try_ct_eval_class_const(&result, resolved_name, zend_ast_get_str(name_ast))) {
zend_string_release_ex(resolved_name, 0);
return;
}
zend_string_release_ex(resolved_name, 0);
break;
}
case ZEND_AST_CLASS_NAME:
{
zend_ast *class_ast = ast->child[0];
if (!zend_try_compile_const_expr_resolve_class_name(&result, class_ast)) {
return;
}
break;
}
default:
return;
}
zend_ast_destroy(ast);
*ast_ptr = zend_ast_create_zval(&result);
}
2014-08-29 05:05:58 +00:00
/* }}} */