Implemented ability to dispatch from user handler to internal handler of another opcode.
#define ZEND_USER_OPCODE_RETURN 1 /* exit from executor (return from function) */
#define ZEND_USER_OPCODE_DISPATCH 2 /* call original opcode handler */
+#define ZEND_USER_OPCODE_DISPATCH_TO 0x100 /* call original handler of returned opcode */
+
ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, opcode_handler_t handler);
ZEND_API opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode);
ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY)
{
- switch (zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL)) {
+ int ret = zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL);
+
+ switch (ret) {
case ZEND_USER_OPCODE_CONTINUE:
ZEND_VM_CONTINUE();
case ZEND_USER_OPCODE_RETURN:
ZEND_VM_RETURN();
case ZEND_USER_OPCODE_DISPATCH:
+ ZEND_VM_DISPATCH(EX(opline)->opcode, EX(opline));
default:
- ZEND_VM_DISPATCH(EX(opline));
+ ZEND_VM_DISPATCH(ret & 0xff, EX(opline));
}
}
#define ZEND_VM_CONTINUE() return 0
#define ZEND_VM_RETURN() return 1
-#define ZEND_VM_DISPATCH(op) return zend_vm_get_opcode_handler(op->opcode, op)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC
static int ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
- switch (zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL)) {
+ int ret = zend_user_opcode_handlers[EX(opline)->opcode](ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL);
+
+ switch (ret) {
case ZEND_USER_OPCODE_CONTINUE:
ZEND_VM_CONTINUE();
case ZEND_USER_OPCODE_RETURN:
ZEND_VM_RETURN();
case ZEND_USER_OPCODE_DISPATCH:
+ ZEND_VM_DISPATCH(EX(opline)->opcode, EX(opline));
default:
- ZEND_VM_DISPATCH(EX(opline));
+ ZEND_VM_DISPATCH(ret & 0xff, EX(opline));
}
}
out($f,"\n");
out($f,"#define ZEND_VM_CONTINUE() return 0\n");
out($f,"#define ZEND_VM_RETURN() return 1\n");
- out($f,"#define ZEND_VM_DISPATCH(op) return zend_vm_get_opcode_handler(op->opcode, op)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
+ out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return zend_vm_get_opcode_handler(opcode, opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,"\n");
out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n");
out($f,"#define ZEND_VM_RETURN() return\n");
- out($f,"#define ZEND_VM_DISPATCH(op) dispatch_handler = zend_vm_get_opcode_handler(op->opcode, op); goto zend_vm_dispatch;\n\n");
+ out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n\n");
out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL &execute_data TSRMLS_CC\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,"\n");
out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n");
out($f,"#define ZEND_VM_RETURN() return\n");
- out($f,"#define ZEND_VM_DISPATCH(op) goto *(void**)(zend_vm_get_opcode_handler(op->opcode, op));\n\n");
+ out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n\n");
out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL &execute_data TSRMLS_CC\n");
break;
}