}
+#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
+# undef ZEND_VM_TAIL_CALL
+# undef ZEND_VM_CONTINUE
+# undef ZEND_VM_RETURN
+
+# define ZEND_VM_TAIL_CALL(call) call; ZEND_VM_CONTINUE()
+# define ZEND_VM_CONTINUE() HYBRID_NEXT()
+# define ZEND_VM_RETURN() goto HYBRID_HALT_LABEL
+#endif
+
+
ZEND_API void execute_ex(zend_execute_data *ex)
{
DCL_OPLINE
#endif
#endif
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
+zend_leave_helper_SPEC_LABEL:
+{
+ zend_execute_data *old_execute_data;
+ uint32_t call_info = EX_CALL_INFO();
+
+ if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED)) == 0)) {
+ i_free_compiled_variables(execute_data);
+
+ EG(current_execute_data) = EX(prev_execute_data);
+ if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+ zend_object *object = Z_OBJ(execute_data->This);
+#if 0
+ if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+#else
+ if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+#endif
+ GC_DELREF(object);
+ zend_object_store_ctor_failed(object);
+ }
+ OBJ_RELEASE(object);
+ } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ }
+ EG(vm_stack_top) = (zval*)execute_data;
+ execute_data = EX(prev_execute_data);
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_rethrow_exception(execute_data);
+ HANDLE_EXCEPTION_LEAVE();
+ }
+
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else if (EXPECTED((call_info & (ZEND_CALL_CODE|ZEND_CALL_TOP)) == 0)) {
+ i_free_compiled_variables(execute_data);
+
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_clean_and_cache_symbol_table(EX(symbol_table));
+ }
+ EG(current_execute_data) = EX(prev_execute_data);
+ if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
+ zend_object *object = Z_OBJ(execute_data->This);
+#if 0
+ if (UNEXPECTED(EG(exception) != NULL) && (EX(opline)->op1.num & ZEND_CALL_CTOR)) {
+#else
+ if (UNEXPECTED(EG(exception) != NULL) && (call_info & ZEND_CALL_CTOR)) {
+#endif
+ GC_DELREF(object);
+ zend_object_store_ctor_failed(object);
+ }
+ OBJ_RELEASE(object);
+ } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ }
+
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+ old_execute_data = execute_data;
+ execute_data = EX(prev_execute_data);
+ zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_rethrow_exception(execute_data);
+ HANDLE_EXCEPTION_LEAVE();
+ }
+
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) {
+ zend_detach_symbol_table(execute_data);
+ destroy_op_array(&EX(func)->op_array);
+ efree_size(EX(func), sizeof(zend_op_array));
+ old_execute_data = execute_data;
+ execute_data = EG(current_execute_data) = EX(prev_execute_data);
+ zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
+
+ zend_attach_symbol_table(execute_data);
+ if (UNEXPECTED(EG(exception) != NULL)) {
+ zend_rethrow_exception(execute_data);
+ HANDLE_EXCEPTION_LEAVE();
+ }
+
+ LOAD_NEXT_OPLINE();
+ ZEND_VM_LEAVE();
+ } else {
+ if (EXPECTED((call_info & ZEND_CALL_CODE) == 0)) {
+ i_free_compiled_variables(execute_data);
+ if (UNEXPECTED(call_info & (ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS))) {
+ if (UNEXPECTED(call_info & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ zend_clean_and_cache_symbol_table(EX(symbol_table));
+ }
+ zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+ }
+ EG(current_execute_data) = EX(prev_execute_data);
+ if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
+ }
+ ZEND_VM_RETURN();
+ } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ {
+ zend_array *symbol_table = EX(symbol_table);
+
+ zend_detach_symbol_table(execute_data);
+ old_execute_data = EX(prev_execute_data);
+ while (old_execute_data) {
+ if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
+ if (old_execute_data->symbol_table == symbol_table) {
+ zend_attach_symbol_table(old_execute_data);
+ }
+ break;
+ }
+ old_execute_data = old_execute_data->prev_execute_data;
+ }
+ EG(current_execute_data) = EX(prev_execute_data);
+ ZEND_VM_RETURN();
+ }
+ }
+}
+
HYBRID_CASE(ZEND_JMP_SPEC):
VM_TRACE(ZEND_JMP_SPEC)
ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_RETURN_SPEC_CONST):
VM_TRACE(ZEND_RETURN_SPEC_CONST)
- ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
+{
+ USE_OPLINE
+ zval *retval_ptr;
+ zval *return_value;
+ zend_free_op free_op1;
+
+ retval_ptr = RT_CONSTANT(opline, opline->op1);
+ return_value = EX(return_value);
+ if (IS_CONST == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) {
+ SAVE_OPLINE();
+ retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R);
+ if (return_value) {
+ ZVAL_NULL(return_value);
+ }
+ } else if (!return_value) {
+ if (IS_CONST & (IS_VAR|IS_TMP_VAR)) {
+ if (Z_REFCOUNTED_P(free_op1) && !Z_DELREF_P(free_op1)) {
+ SAVE_OPLINE();
+ zval_dtor_func(Z_COUNTED_P(free_op1));
+ }
+ }
+ } else {
+ if ((IS_CONST & (IS_CONST|IS_TMP_VAR))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (IS_CONST == IS_CONST) {
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(return_value))) {
+ Z_ADDREF_P(return_value);
+ }
+ }
+ } else if (IS_CONST == IS_CV) {
+ if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) {
+ ZVAL_NULL(retval_ptr);
+ } else {
+ Z_ADDREF_P(return_value);
+ }
+ } else {
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY(return_value, retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ } else /* if (IS_CONST == IS_VAR) */ {
+ if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
+ zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (UNEXPECTED(GC_DELREF(ref) == 0)) {
+ efree_size(ref, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ Z_ADDREF_P(retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ }
+ }
+ goto zend_leave_helper_SPEC_LABEL;
+}
+
HYBRID_CASE(ZEND_RETURN_BY_REF_SPEC_CONST):
VM_TRACE(ZEND_RETURN_BY_REF_SPEC_CONST)
ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_RETURN_SPEC_TMP):
VM_TRACE(ZEND_RETURN_SPEC_TMP)
- ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
+{
+ USE_OPLINE
+ zval *retval_ptr;
+ zval *return_value;
+ zend_free_op free_op1;
+
+ retval_ptr = _get_zval_ptr_tmp(opline->op1.var, &free_op1 EXECUTE_DATA_CC);
+ return_value = EX(return_value);
+ if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) {
+ SAVE_OPLINE();
+ retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R);
+ if (return_value) {
+ ZVAL_NULL(return_value);
+ }
+ } else if (!return_value) {
+ if (IS_TMP_VAR & (IS_VAR|IS_TMP_VAR)) {
+ if (Z_REFCOUNTED_P(free_op1) && !Z_DELREF_P(free_op1)) {
+ SAVE_OPLINE();
+ zval_dtor_func(Z_COUNTED_P(free_op1));
+ }
+ }
+ } else {
+ if ((IS_TMP_VAR & (IS_CONST|IS_TMP_VAR))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (IS_TMP_VAR == IS_CONST) {
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(return_value))) {
+ Z_ADDREF_P(return_value);
+ }
+ }
+ } else if (IS_TMP_VAR == IS_CV) {
+ if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) {
+ ZVAL_NULL(retval_ptr);
+ } else {
+ Z_ADDREF_P(return_value);
+ }
+ } else {
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY(return_value, retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ } else /* if (IS_TMP_VAR == IS_VAR) */ {
+ if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
+ zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (UNEXPECTED(GC_DELREF(ref) == 0)) {
+ efree_size(ref, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ Z_ADDREF_P(retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ }
+ }
+ goto zend_leave_helper_SPEC_LABEL;
+}
+
HYBRID_CASE(ZEND_RETURN_BY_REF_SPEC_TMP):
VM_TRACE(ZEND_RETURN_BY_REF_SPEC_TMP)
ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_RETURN_SPEC_VAR):
VM_TRACE(ZEND_RETURN_SPEC_VAR)
- ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
+{
+ USE_OPLINE
+ zval *retval_ptr;
+ zval *return_value;
+ zend_free_op free_op1;
+
+ retval_ptr = _get_zval_ptr_var(opline->op1.var, &free_op1 EXECUTE_DATA_CC);
+ return_value = EX(return_value);
+ if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) {
+ SAVE_OPLINE();
+ retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R);
+ if (return_value) {
+ ZVAL_NULL(return_value);
+ }
+ } else if (!return_value) {
+ if (IS_VAR & (IS_VAR|IS_TMP_VAR)) {
+ if (Z_REFCOUNTED_P(free_op1) && !Z_DELREF_P(free_op1)) {
+ SAVE_OPLINE();
+ zval_dtor_func(Z_COUNTED_P(free_op1));
+ }
+ }
+ } else {
+ if ((IS_VAR & (IS_CONST|IS_TMP_VAR))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (IS_VAR == IS_CONST) {
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(return_value))) {
+ Z_ADDREF_P(return_value);
+ }
+ }
+ } else if (IS_VAR == IS_CV) {
+ if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) {
+ ZVAL_NULL(retval_ptr);
+ } else {
+ Z_ADDREF_P(return_value);
+ }
+ } else {
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY(return_value, retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ } else /* if (IS_VAR == IS_VAR) */ {
+ if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
+ zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (UNEXPECTED(GC_DELREF(ref) == 0)) {
+ efree_size(ref, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ Z_ADDREF_P(retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ }
+ }
+ goto zend_leave_helper_SPEC_LABEL;
+}
+
HYBRID_CASE(ZEND_RETURN_BY_REF_SPEC_VAR):
VM_TRACE(ZEND_RETURN_BY_REF_SPEC_VAR)
ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_RETURN_SPEC_CV):
VM_TRACE(ZEND_RETURN_SPEC_CV)
- ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
- HYBRID_BREAK();
+{
+ USE_OPLINE
+ zval *retval_ptr;
+ zval *return_value;
+ zend_free_op free_op1;
+
+ retval_ptr = _get_zval_ptr_cv_undef(opline->op1.var EXECUTE_DATA_CC);
+ return_value = EX(return_value);
+ if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(retval_ptr) == IS_UNDEF)) {
+ SAVE_OPLINE();
+ retval_ptr = GET_OP1_UNDEF_CV(retval_ptr, BP_VAR_R);
+ if (return_value) {
+ ZVAL_NULL(return_value);
+ }
+ } else if (!return_value) {
+ if (IS_CV & (IS_VAR|IS_TMP_VAR)) {
+ if (Z_REFCOUNTED_P(free_op1) && !Z_DELREF_P(free_op1)) {
+ SAVE_OPLINE();
+ zval_dtor_func(Z_COUNTED_P(free_op1));
+ }
+ }
+ } else {
+ if ((IS_CV & (IS_CONST|IS_TMP_VAR))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (IS_CV == IS_CONST) {
+ if (UNEXPECTED(Z_OPT_REFCOUNTED_P(return_value))) {
+ Z_ADDREF_P(return_value);
+ }
+ }
+ } else if (IS_CV == IS_CV) {
+ if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ if (EXPECTED(!Z_OPT_ISREF_P(retval_ptr))) {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) {
+ ZVAL_NULL(retval_ptr);
+ } else {
+ Z_ADDREF_P(return_value);
+ }
+ } else {
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY(return_value, retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ } else /* if (IS_CV == IS_VAR) */ {
+ if (UNEXPECTED(Z_ISREF_P(retval_ptr))) {
+ zend_refcounted *ref = Z_COUNTED_P(retval_ptr);
+
+ retval_ptr = Z_REFVAL_P(retval_ptr);
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ if (UNEXPECTED(GC_DELREF(ref) == 0)) {
+ efree_size(ref, sizeof(zend_reference));
+ } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) {
+ Z_ADDREF_P(retval_ptr);
+ }
+ } else {
+ ZVAL_COPY_VALUE(return_value, retval_ptr);
+ }
+ }
+ }
+ goto zend_leave_helper_SPEC_LABEL;
+}
+
HYBRID_CASE(ZEND_RETURN_BY_REF_SPEC_CV):
VM_TRACE(ZEND_RETURN_BY_REF_SPEC_CV)
ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
++$line_no;
}
+function is_hot_helper($name) {
+ global $helpers;
+
+ if (isset($helpers[$name]["hot"])) {
+ return $helpers[$name]["hot"];
+ } else {
+ return false;
+ }
+}
+
// Returns name of specialized helper
function helper_name($name, $spec, $op1, $op2, $extra_spec) {
global $prefix, $helpers;
}
// Updating code according to selected threading model
switch($kind) {
+ case ZEND_VM_KIND_HYBRID:
+ $code = preg_replace_callback(
+ array(
+ "/EXECUTE_DATA(?=[^_])/m",
+ "/ZEND_VM_DISPATCH_TO_HANDLER\(\s*([A-Z_]*)\s*\)/m",
+ "/ZEND_VM_DISPATCH_TO_HELPER\(\s*([A-Za-z_]*)\s*(,[^)]*)?\)/m",
+ ),
+ function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) {
+ if (strncasecmp($matches[0], "EXECUTE_DATA", strlen("EXECUTE_DATA")) == 0) {
+ return "execute_data";
+ } else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
+ global $opcodes, $opnames;
+
+ $name = $matches[1];
+ $opcode = $opcodes[$opnames[$name]];
+ if (is_hot_handler($opcode["hot"], $op1, $op2, $extra_spec)) {
+ return "goto " . opcode_name($name, $spec, $op1, $op2) . "_LABEL";
+ } else {
+ return "ZEND_VM_TAIL_CALL(" . opcode_name($name, $spec, $op1, $op2) . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
+ }
+ } else {
+ // ZEND_VM_DISPATCH_TO_HELPER
+ if (isset($matches[2])) {
+ // extra args
+ $args = substr(preg_replace("/,\s*[A-Za-z_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2);
+ return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))";
+ }
+ if (is_hot_helper($matches[1])) {
+ return "goto " . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "_LABEL";
+ }
+ return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
+ }
+ },
+ $code);
+ break;
case ZEND_VM_KIND_CALL:
$code = preg_replace_callback(
array(
}
}
+function is_inline_hybrid_handler($name, $hot, $op1, $op2, $extra_spec) {
+ return $name == "ZEND_RETURN";
+ //return $hot && is_hot_handler($hot, $op1, $op2, $extra_spec);
+}
+
// Generates opcode handler
function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $opcode, $extra_spec = null, &$switch_labels = array()) {
global $definition_file, $prefix, $opnames, $gen_order;
$spec_name = $name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2].($spec?extra_spec_name($extra_spec):"");
switch($kind) {
case ZEND_VM_KIND_HYBRID:
- $code =
- "\t\t\tHYBRID_CASE({$spec_name}):\n"
- . "\t\t\t\tVM_TRACE($spec_name)\n"
- . "\t\t\t\t{$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"
- . "\t\t\t\tHYBRID_BREAK();\n";
+ if (is_inline_hybrid_handler($name, $opcode["hot"], $op1, $op2, $extra_spec)) {
+ $out = fopen('php://memory', 'w+');
+ gen_code($out, $spec, $kind, 0, $code, $op1, $op2, $name, $extra_spec);
+ rewind($out);
+ $code =
+ "\t\t\tHYBRID_CASE({$spec_name}):\n"
+ . "\t\t\t\tVM_TRACE($spec_name)\n"
+ . stream_get_contents($out);
+ fclose($out);
+ } else {
+ $code =
+ "\t\t\tHYBRID_CASE({$spec_name}):\n"
+ . "\t\t\t\tVM_TRACE($spec_name)\n"
+ . "\t\t\t\t{$spec_name}_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"
+ . "\t\t\t\tHYBRID_BREAK();\n";
+ }
if (is_array($gen_order)) {
$gen_order[$spec_name] = $code;
} else {
}
// Generates helper
-function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, $inline, $cold, $extra_spec = null) {
+function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno, $inline, $cold = false, $hot = false, $extra_spec = null) {
global $definition_file, $prefix;
- if ($kind == ZEND_VM_KIND_HYBRID) {
+ if ($kind == ZEND_VM_KIND_HYBRID && !$hot) {
return;
}
// Generate helper's entry point according to selected threading model
switch($kind) {
+ case ZEND_VM_KIND_HYBRID:
+ out($f, $spec_name . "_LABEL:\n");
+ break;
case ZEND_VM_KIND_CALL:
if ($inline) {
$zend_attributes = " zend_always_inline";
if (isset($helpers[$num]["op1"][$op1]) &&
isset($helpers[$num]["op2"][$op2])) {
// Generate helper code
- gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $extra_spec);
+ gen_helper($f, 1, $kind, $num, $op1, $op2, $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"], $extra_spec);
}
}
} else {
} else if (isset($dsc["helper"])) {
$num = $dsc["helper"];
// Generate helper code
- gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"]);
+ gen_helper($f, 0, $kind, $num, "ANY", "ANY", $helpers[$num]["param"], $helpers[$num]["code"], $lineno, $helpers[$num]["inline"], $helpers[$num]["cold"], $helpers[$num]["hot"]);
} else {
var_dump($dsc);
die("??? $kind:$num\n");
}
if ($kind == ZEND_VM_KIND_HYBRID) {
gen_executor_code($f, $spec, ZEND_VM_KIND_CALL, $m[1]);
+ out($f,"\n");
+ out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
+ out($f,"# undef ZEND_VM_TAIL_CALL\n");
+ out($f,"# undef ZEND_VM_CONTINUE\n");
+ out($f,"# undef ZEND_VM_RETURN\n");
+// out($f,"# undef ZEND_VM_INTERRUPT\n");
+ out($f,"\n");
+ out($f,"# define ZEND_VM_TAIL_CALL(call) call; ZEND_VM_CONTINUE()\n");
+ out($f,"# define ZEND_VM_CONTINUE() HYBRID_NEXT()\n");
+ out($f,"# define ZEND_VM_RETURN() goto HYBRID_HALT_LABEL\n");
+// out($f,"# define ZEND_VM_INTERRUPT() goto zend_interrupt_helper_SPEC_LABEL\n");
+ out($f,"#endif\n\n");
}
break;
case "EXECUTOR_NAME":
$list[$lineno] = array("handler"=>$handler);
} else if (strpos($line,"ZEND_VM_HELPER(") === 0 ||
strpos($line,"ZEND_VM_INLINE_HELPER(") === 0 ||
- strpos($line,"ZEND_VM_COLD_HELPER(") === 0) {
+ strpos($line,"ZEND_VM_COLD_HELPER(") === 0 ||
+ strpos($line,"ZEND_VM_HOT_HELPER(") === 0) {
// Parsing helper's definition
if (preg_match(
- "/^ZEND_VM(_INLINE|_COLD)?_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(?:,\s*SPEC\(([A-Z_|=,]+)\)\s*)?(?:,\s*([^)]*)\s*)?\)/",
+ "/^ZEND_VM(_INLINE|_COLD|_HOT)?_HELPER\(\s*([A-Za-z_]+)\s*,\s*([A-Z_|]+)\s*,\s*([A-Z_|]+)\s*(?:,\s*SPEC\(([A-Z_|=,]+)\)\s*)?(?:,\s*([^)]*)\s*)?\)/",
$line,
$m) == 0) {
die("ERROR ($def:$lineno): Invalid ZEND_VM_HELPER definition.\n");
}
$inline = !empty($m[1]) && $m[1] === "_INLINE";
$cold = !empty($m[1]) && $m[1] === "_COLD";
+ $hot = !empty($m[1]) && $m[1] === "_HOT";
$helper = $m[2];
$op1 = parse_operand_spec($def, $lineno, $m[3], $flags1);
$op2 = parse_operand_spec($def, $lineno, $m[4], $flags2);
}
}
- $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"","inline"=>$inline,"cold"=>$cold);
+ $helpers[$helper] = array("op1"=>$op1,"op2"=>$op2,"param"=>$param,"code"=>"","inline"=>$inline,"cold"=>$cold,"hot"=>$hot);
if (!empty($m[5])) {
$helpers[$helper]["spec"] = parse_spec_rules($def, $lineno, $m[5]);