From 86ed717f227aaf490c0e1eaa69b865ca76e7e9e8 Mon Sep 17 00:00:00 2001 From: i582 <51853996+i582@users.noreply.github.com> Date: Sat, 11 Sep 2021 20:05:06 +0300 Subject: [PATCH] allowed 'catch' without variable A 'catch' without a variable is a catch with the 'without_variable' flag set with a variable with an autogenerated name. This variable is further used as a placeholder. At the stage of code generation, if the 'without_variable' flag is set, then we simply destroy the current exception, thereby handling it. The gain in this case is in the absence of moving the current exception into a temp variable, which, according to benchmarks, however, gives an increase in speed within the margin of error for simple Exception. --- compiler/code-gen/vertex-compiler.cpp | 20 +++++++++++++++++-- compiler/gentree.cpp | 10 +++++++++- compiler/vertex-desc.json | 3 +++ .../exceptions/18_catch_without_variable.php | 16 +++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/phpt/exceptions/18_catch_without_variable.php diff --git a/compiler/code-gen/vertex-compiler.cpp b/compiler/code-gen/vertex-compiler.cpp index d87773d253..2596279aff 100644 --- a/compiler/code-gen/vertex-compiler.cpp +++ b/compiler/code-gen/vertex-compiler.cpp @@ -263,7 +263,15 @@ void compile_try(VertexAdaptor root, CodeGenerator &W) { if (!is_first_catch) { W << "else " << BEGIN << NL; } - move_exception(caught_class, catch_op->var()); + + // if 'catch' is used without a variable, then + // the current exception can simply be destroyed + if (catch_op->without_variable) { + W << "CurException.destroy();" << NL; + } else { + move_exception(caught_class, catch_op->var()); + } + W << catch_op->cmd() << NL; if (!is_first_catch) { W << END << NL; @@ -277,7 +285,15 @@ void compile_try(VertexAdaptor root, CodeGenerator &W) { } std::string e = gen_unique_name("e"); W << BEGIN; - move_exception(caught_class, catch_op->var()); + + // if 'catch' is used without a variable, then + // the current exception can simply be destroyed + if (catch_op->without_variable) { + W << "CurException.destroy();" << NL; + } else { + move_exception(caught_class, catch_op->var()); + } + W << catch_op->cmd() << NL << END << NL; } diff --git a/compiler/gentree.cpp b/compiler/gentree.cpp index aebdcd0ddc..0a53a7d4b2 100644 --- a/compiler/gentree.cpp +++ b/compiler/gentree.cpp @@ -1999,7 +1999,14 @@ VertexAdaptor GenTree::get_catch() { auto exception_class = cur->str_val; CE (expect(tok_func_name, "type that implements Throwable")); auto exception_var_name = get_expression(); - CE (!kphp_error(exception_var_name, "Cannot parse catch")); + auto without_variable = false; + + // if 'catch' without variable + if (!exception_var_name) { + exception_var_name = create_superlocal_var("catch_"); + without_variable = true; + } + CE (!kphp_error(exception_var_name->type() == op_var, "Expected variable name in 'catch'")); CE (expect(tok_clpar, "')'")); @@ -2008,6 +2015,7 @@ VertexAdaptor GenTree::get_catch() { auto catch_op = VertexAdaptor::create(exception_var_name.as(), embrace(catch_body)); catch_op->type_declaration = resolve_uses(cur_function, static_cast(exception_class), '\\'); + catch_op->without_variable = without_variable; return catch_op; } diff --git a/compiler/vertex-desc.json b/compiler/vertex-desc.json index 1cfba930a4..db6542aa2c 100644 --- a/compiler/vertex-desc.json +++ b/compiler/vertex-desc.json @@ -1659,6 +1659,9 @@ }, "exception_class": { "type": "ClassPtr" + }, + "without_variable": { + "type": "bool" } }, "props": { diff --git a/tests/phpt/exceptions/18_catch_without_variable.php b/tests/phpt/exceptions/18_catch_without_variable.php new file mode 100644 index 0000000000..63b97b7b7d --- /dev/null +++ b/tests/phpt/exceptions/18_catch_without_variable.php @@ -0,0 +1,16 @@ +@ok php8 +