Transparently introduce type-specialized opcode handlers.

This affects only PHP VM, and doesn't change anything else.
This commit is contained in:
Dmitry Stogov 2016-03-17 10:00:45 +03:00
parent 3f1e35756c
commit f4475a2360
7 changed files with 3055 additions and 50 deletions

View File

@ -40,6 +40,7 @@
#include "zend_vm.h"
#include "zend_dtrace.h"
#include "zend_inheritance.h"
#include "zend_type_info.h"
/* Virtual current working directory support */
#include "zend_virtual_cwd.h"
@ -2610,6 +2611,20 @@ void zend_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t
cleanup_live_vars(execute_data, op_num, catch_op_num);
}
static void zend_swap_operands(zend_op *op) /* {{{ */
{
znode_op tmp;
zend_uchar tmp_type;
tmp = op->op1;
tmp_type = op->op1_type;
op->op1 = op->op2;
op->op1_type = op->op2_type;
op->op2 = tmp;
op->op2_type = tmp_type;
}
/* }}} */
#ifdef HAVE_GCC_GLOBAL_REGS
# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"

View File

@ -25,6 +25,7 @@ BEGIN_EXTERN_C()
ZEND_API void zend_vm_use_old_executor(void);
ZEND_API void zend_vm_set_opcode_handler(zend_op* opcode);
ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* opcode, uint32_t op1_info, uint32_t op2_info, uint32_t res_info);
ZEND_API int zend_vm_call_opcode_handler(zend_execute_data *ex);
END_EXTERN_C()

View File

@ -8256,4 +8256,397 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, CONST, REF)
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_ADD_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
fast_long_add_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_ADD, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_ADD_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_SUB_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_SUB_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
fast_long_sub_function(result, op1, op2);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_SUB, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_SUB_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_MUL_LONG_NO_OVERFLOW, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_LONG(result, Z_LVAL_P(op1) * Z_LVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_MUL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
zend_long overflow;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1), Z_LVAL_P(op2), Z_LVAL_P(result), Z_DVAL_P(result), overflow);
Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_MUL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_MUL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2, *result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = EX_VAR(opline->result.var);
ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_LVAL_P(op1) == Z_LVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_DVAL_P(op1) == Z_DVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_NOT_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_LVAL_P(op1) != Z_LVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_NOT_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_NOT_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST,COMMUTATIVE))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_DVAL_P(op1) != Z_DVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_SMALLER_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_LVAL_P(op1) < Z_LVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_SMALLER_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_DVAL_P(op1) < Z_DVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG), ZEND_IS_SMALLER_OR_EQUAL_LONG, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_LVAL_P(op1) <= Z_LVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_SMALLER_OR_EQUAL, (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE), ZEND_IS_SMALLER_OR_EQUAL_DOUBLE, CONST|TMPVARCV, CONST|TMPVARCV, SPEC(SMART_BRANCH,NO_CONST_CONST))
{
USE_OPLINE
zval *op1, *op2;
int result;
op1 = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
op2 = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
result = (Z_DVAL_P(op1) <= Z_DVAL_P(op2));
ZEND_VM_SMART_BRANCH(result, 0);
ZVAL_BOOL(EX_VAR(opline->result.var), result);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_PRE_INC_LONG_NO_OVERFLOW, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
Z_LVAL_P(var_ptr)++;
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == MAY_BE_LONG), ZEND_PRE_INC_LONG, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
fast_long_increment_function(var_ptr);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_INC_LONG_OR_DOUBLE, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_long_increment_function(var_ptr);
} else {
Z_DVAL_P(var_ptr)++;
}
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG_NO_OVERFLOW, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
Z_LVAL_P(var_ptr)--;
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == MAY_BE_LONG), ZEND_PRE_DEC_LONG, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
fast_long_decrement_function(var_ptr);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_PRE_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_PRE_DEC_LONG_OR_DOUBLE, TMPVARCV, ANY, SPEC(RETVAL))
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_long_decrement_function(var_ptr);
} else {
Z_DVAL_P(var_ptr)--;
}
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG_NO_OVERFLOW, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
Z_LVAL_P(var_ptr)++;
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == MAY_BE_LONG), ZEND_POST_INC_LONG, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
fast_long_increment_function(var_ptr);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_INC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_INC_LONG_OR_DOUBLE, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_long_increment_function(var_ptr);
} else {
Z_DVAL_P(var_ptr)++;
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG_NO_OVERFLOW, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
Z_LVAL_P(var_ptr)--;
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == MAY_BE_LONG), ZEND_POST_DEC_LONG, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_LONG(EX_VAR(opline->result.var), Z_LVAL_P(var_ptr));
fast_long_decrement_function(var_ptr);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_POST_DEC, (op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE)), ZEND_POST_DEC_LONG_OR_DOUBLE, TMPVARCV, ANY)
{
USE_OPLINE
zval *var_ptr;
var_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW);
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), var_ptr);
if (EXPECTED(Z_TYPE_P(var_ptr) == IS_LONG)) {
fast_long_decrement_function(var_ptr);
} else {
Z_DVAL_P(var_ptr)--;
}
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_QM_ASSIGN, (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))), ZEND_QM_ASSIGN_NOREF, CONST|TMPVARCV, ANY)
{
USE_OPLINE
zend_free_op free_op1;
zval *value;
value = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R);
ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA);

File diff suppressed because it is too large Load Diff

View File

@ -1053,6 +1053,10 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
if ($flags) {
$specs[$num] .= " | ".implode("|", $flags);
}
if ($num >= 256) {
$opcodes[$num]['spec_code'] = $specs[$num];
unset($specs[$num]);
}
$foreach_op1 = function($do) use ($dsc, $op_types) {
return function() use ($do, $dsc, $op_types) {
@ -1226,6 +1230,9 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
}
$next++;
}
if ($num >= 256) {
continue;
}
$next = $num+1;
//ugly trick for ZEND_VM_DEFINE_OP
@ -1430,11 +1437,13 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array())
foreach ($list as $lineno => $dsc) {
if (isset($dsc["handler"])) {
$num = $dsc["handler"];
// Generate handler code
gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno);
// Generate handler code
if ($num < 256) {
gen_handler($f, 0, $kind, $opcodes[$num]["op"], "ANY", "ANY", isset($opcodes[$num]["use"]), $opcodes[$num]["code"], $lineno);
}
} else if (isset($dsc["helper"])) {
$num = $dsc["helper"];
// Generate helper code
// Generate helper code
gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"]);
} else {
var_dump($dsc);
@ -1892,6 +1901,7 @@ function gen_vm($def, $skel) {
$helper = null;
$max_opcode_len = 0;
$max_opcode = 0;
$extra_num = 256;
$export = array();
foreach ($in as $line) {
++$lineno;
@ -1939,6 +1949,48 @@ function gen_vm($def, $skel) {
$handler = $code;
$helper = null;
$list[$lineno] = array("handler"=>$handler);
} else if (strpos($line,"ZEND_VM_TYPE_SPEC_HANDLER(") === 0) {
// Parsing opcode handler's definition
if (preg_match(
"/^ZEND_VM_TYPE_SPEC_HANDLER\(\s*([A-Z_]+)\s*,\s*([^,]+),\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(,\s*([A-Z_|]+)\s*)?(,\s*SPEC\(([A-Z_|=,]+)\)\s*)?\)/",
$line,
$m) == 0) {
die("ERROR ($def:$lineno): Invalid ZEND_VM_TYPE_HANDLER_HANDLER definition.\n");
}
$orig_op = $m[1];
if (!isset($opnames[$orig_op])) {
die("ERROR ($def:$lineno): Opcode with name '$orig_op' is not defined.\n");
}
$orig_code = $opnames[$orig_op];
$condition = $m[2];
$code = $extra_num++;
$op = $m[3];
$op1 = parse_operand_spec($def, $lineno, $m[4], $flags1);
$op2 = parse_operand_spec($def, $lineno, $m[5], $flags2);
$flags = $flags1 | ($flags2 << 8);
if (!empty($m[7])) {
$flags |= parse_ext_spec($def, $lineno, $m[7]);
}
if (isset($opcodes[$code])) {
die("ERROR ($def:$lineno): Opcode with name '$code' is already defined.\n");
}
$opcodes[$orig_code]['type_spec'][$code] = $condition;
$used_extra_spec["TYPE"] = 1;
$opcodes[$code] = array("op"=>$op,"op1"=>$op1,"op2"=>$op2,"code"=>"","flags"=>$flags);
if (isset($m[9])) {
$opcodes[$code]["spec"] = parse_spec_rules($def, $lineno, $m[9]);
if (isset($opcodes[$code]["spec"]["NO_CONST_CONST"])) {
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_NO_CONST_CONST"];
}
if (isset($opcodes[$code]["spec"]["COMMUTATIVE"])) {
$opcodes[$code]["flags"] |= $vm_op_flags["ZEND_VM_COMMUTATIVE"];
}
}
$opnames[$op] = $code;
$handler = $code;
$helper = null;
$list[$lineno] = array("handler"=>$handler);
} else if (strpos($line,"ZEND_VM_HELPER(") === 0 || strpos($line,"ZEND_VM_INLINE_HELPER(") === 0) {
// Parsing helper's definition
if (preg_match(
@ -2065,7 +2117,9 @@ function gen_vm($def, $skel) {
foreach ($opcodes as $code => $dsc) {
$code = str_pad((string)$code,$code_len," ",STR_PAD_LEFT);
$op = str_pad($dsc["op"],$max_opcode_len);
fputs($f,"#define $op $code\n");
if ($code <= $max_opcode) {
fputs($f,"#define $op $code\n");
}
}
$code = str_pad((string)$max_opcode,$code_len," ",STR_PAD_LEFT);
@ -2153,10 +2207,10 @@ function gen_vm($def, $skel) {
gen_executor($f, $skl, ZEND_VM_SPEC, ZEND_VM_KIND, "execute", "zend_init_opcodes_handlers");
// Generate zend_vm_get_opcode_handler() function
out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n");
out($f, "static const void *zend_vm_get_opcode_handler_ex(uint32_t spec, const zend_op* op)\n");
out($f, "{\n");
if (!ZEND_VM_SPEC) {
out($f, "\treturn zend_opcode_handlers[opcode];\n");
out($f, "\treturn zend_opcode_handlers[spec];\n");
} else {
out($f, "\tstatic const int zend_vm_decode[] = {\n");
out($f, "\t\t_UNUSED_CODE, /* 0 */\n");
@ -2177,7 +2231,6 @@ function gen_vm($def, $skel) {
out($f, "\t\t_UNUSED_CODE, /* 15 */\n");
out($f, "\t\t_CV_CODE /* 16 = IS_CV */\n");
out($f, "\t};\n");
out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n");
out($f, "\tuint32_t offset = 0;\n");
out($f, "\tif (spec & SPEC_RULE_OP1) offset = offset * 5 + zend_vm_decode[op->op1_type];\n");
out($f, "\tif (spec & SPEC_RULE_OP2) offset = offset * 5 + zend_vm_decode[op->op2_type];\n");
@ -2203,6 +2256,14 @@ function gen_vm($def, $skel) {
out($f, "\treturn zend_opcode_handlers[(spec & SPEC_START_MASK) + offset];\n");
}
out($f, "}\n\n");
out($f, "static const void *zend_vm_get_opcode_handler(zend_uchar opcode, const zend_op* op)\n");
out($f, "{\n");
if (!ZEND_VM_SPEC) {
out($f, "\treturn zend_vm_get_opcode_handler_ex(opcode, op);\n");
} else {
out($f, "\treturn zend_vm_get_opcode_handler_ex(zend_spec_handlers[opcode], op);\n");
}
out($f, "}\n\n");
// Generate zend_vm_get_opcode_handler() function
out($f, "ZEND_API void zend_vm_set_opcode_handler(zend_op* op)\n");
@ -2210,6 +2271,55 @@ function gen_vm($def, $skel) {
out($f, "\top->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);\n");
out($f, "}\n\n");
// Generate zend_vm_set_opcode_handler_ex() function
out($f, "ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint32_t op2_info, uint32_t res_info)\n");
out($f, "{\n");
out($f, "\tzend_uchar opcode = zend_user_opcodes[op->opcode];\n");
if (!ZEND_VM_SPEC) {
out($f, "\top->handler = zend_vm_get_opcode_handler_ex(opcode, op);\n");
} else {
out($f, "\tuint32_t spec = zend_spec_handlers[opcode];\n");
if (isset($used_extra_spec["TYPE"])) {
out($f, "\tswitch (opcode) {\n");
foreach($opcodes as $code => $dsc) {
if (isset($dsc['type_spec'])) {
$orig_op = $dsc['op'];
out($f, "\t\tcase $orig_op:\n");
$first = true;
foreach($dsc['type_spec'] as $code => $condition) {
if ($first) {
out($f, "\t\t\tif ($condition) {\n");
$first = false;
} else {
out($f, "\t\t\t} else if ($condition) {\n");
}
$spec_dsc = $opcodes[$code];
if (isset($spec_dsc["spec"]["NO_CONST_CONST"])) {
out($f, "\t\t\t\tif (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {\n");
out($f, "\t\t\t\t\tbreak;\n");
out($f, "\t\t\t\t}\n");
}
out($f, "\t\t\t\tspec = ${spec_dsc['spec_code']};\n");
if (isset($spec_dsc["spec"]["COMMUTATIVE"])) {
out($f, "\t\t\t\tif (op->op1_type > op->op2_type) {\n");
out($f, "\t\t\t\t\tzend_swap_operands(op);\n");
out($f, "\t\t\t\t}\n");
}
}
if (!$first) {
out($f, "\t\t\t}\n");
}
out($f, "\t\t\tbreak;\n");
}
}
out($f, "\t\tdefault:\n");
out($f, "\t\t\tbreak;\n");
out($f, "\t}\n");
}
out($f, "\top->handler = zend_vm_get_opcode_handler_ex(spec, op);\n");
}
out($f, "}\n\n");
// Generate zend_vm_call_opcode_handler() function
if (ZEND_VM_KIND == ZEND_VM_KIND_CALL) {
out($f, "ZEND_API int zend_vm_call_opcode_handler(zend_execute_data* ex)\n");

View File

@ -24,39 +24,7 @@
#include "zend_bitset.h"
/* Bitmask for type inference (zend_ssa_var_info.type) */
#define MAY_BE_UNDEF (1 << IS_UNDEF)
#define MAY_BE_NULL (1 << IS_NULL)
#define MAY_BE_FALSE (1 << IS_FALSE)
#define MAY_BE_TRUE (1 << IS_TRUE)
#define MAY_BE_LONG (1 << IS_LONG)
#define MAY_BE_DOUBLE (1 << IS_DOUBLE)
#define MAY_BE_STRING (1 << IS_STRING)
#define MAY_BE_ARRAY (1 << IS_ARRAY)
#define MAY_BE_OBJECT (1 << IS_OBJECT)
#define MAY_BE_RESOURCE (1 << IS_RESOURCE)
#define MAY_BE_ANY (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)
#define MAY_BE_REF (1 << IS_REFERENCE) /* may be reference */
#define MAY_BE_ARRAY_SHIFT (IS_REFERENCE)
#define MAY_BE_ARRAY_OF_NULL (MAY_BE_NULL << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_FALSE (MAY_BE_FALSE << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_TRUE (MAY_BE_TRUE << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_LONG (MAY_BE_LONG << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_DOUBLE (MAY_BE_DOUBLE << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_STRING (MAY_BE_STRING << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_ARRAY (MAY_BE_ARRAY << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_OBJECT (MAY_BE_OBJECT << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_RESOURCE (MAY_BE_RESOURCE << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_ANY (MAY_BE_ANY << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_REF (MAY_BE_REF << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_KEY_LONG (1<<21)
#define MAY_BE_ARRAY_KEY_STRING (1<<22)
#define MAY_BE_ARRAY_KEY_ANY (MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_KEY_STRING)
#define MAY_BE_ERROR (1<<23)
#define MAY_BE_CLASS (1<<24)
#include "zend_type_info.h"
#define MAY_BE_IN_REG (1<<25) /* value allocated in CPU register */

View File

@ -29,6 +29,7 @@
#include "zend_cfg.h"
#include "zend_func_info.h"
#include "zend_call_graph.h"
#include "zend_inference.h"
#include "zend_dump.h"
#ifndef HAVE_DFA_PASS
@ -678,6 +679,34 @@ static void zend_redo_pass_two(zend_op_array *op_array)
}
}
#if HAVE_DFA_PASS
static void zend_redo_pass_two_ex(zend_op_array *op_array, zend_ssa *ssa)
{
zend_op *opline, *end;
opline = op_array->opcodes;
end = opline + op_array->last;
while (opline < end) {
zend_vm_set_opcode_handler_ex(opline,
opline->op1_type == IS_UNDEF ? 0 : (OP1_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY)),
opline->op2_type == IS_UNDEF ? 0 : (OP2_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY)),
(opline->opcode == ZEND_PRE_INC ||
opline->opcode == ZEND_PRE_DEC ||
opline->opcode == ZEND_POST_INC ||
opline->opcode == ZEND_POST_DEC) ?
((ssa->ops[opline - op_array->opcodes].op1_def >= 0) ? (OP1_DEF_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY)) : MAY_BE_ANY) :
(opline->result_type == IS_UNDEF ? 0 : (RES_INFO() & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY))));
if (opline->op1_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
}
if (opline->op2_type == IS_CONST) {
ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
}
opline++;
}
}
#endif
static void zend_optimize_op_array(zend_op_array *op_array,
zend_optimizer_ctx *ctx)
{
@ -810,8 +839,13 @@ int zend_optimize_script(zend_script *script, zend_long optimization_level, zend
}
for (i = 0; i < call_graph.op_arrays_count; i++) {
zend_redo_pass_two(call_graph.op_arrays[i]);
ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
func_info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
if (func_info && func_info->ssa.var_info) {
zend_redo_pass_two_ex(call_graph.op_arrays[i], &func_info->ssa);
ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
} else {
zend_redo_pass_two(call_graph.op_arrays[i]);
}
}
zend_arena_release(&ctx.arena, checkpoint);