mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
Support for "simple block" optimization, where we can run blocks
directly if there are no arguments or redirections to the block itself
This commit is contained in:
parent
45852f0497
commit
cb6be2a50d
2 changed files with 72 additions and 5 deletions
|
@ -19,6 +19,12 @@
|
||||||
#include "exec.h"
|
#include "exec.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
|
||||||
|
/* These are the specific statement types that support redirections */
|
||||||
|
static bool specific_statement_type_is_redirectable_block(const parse_node_t &node)
|
||||||
|
{
|
||||||
|
return node.type == symbol_block_statement || node.type == symbol_if_statement || node.type == symbol_switch_statement;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p) : tree(t), src(s), parser(p), eval_level(0)
|
parse_execution_context_t::parse_execution_context_t(const parse_node_tree_t &t, const wcstring &s, parser_t *p) : tree(t), src(s), parser(p), eval_level(0)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +198,41 @@ parse_execution_context_t::execution_cancellation_reason_t parse_execution_conte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return whether the job contains a single statement, of block type, with no redirections */
|
||||||
|
bool parse_execution_context_t::job_is_simple_block(const parse_node_t &job_node) const
|
||||||
|
{
|
||||||
|
assert(job_node.type == symbol_job);
|
||||||
|
|
||||||
|
/* Must have one statement */
|
||||||
|
const parse_node_t &statement = *get_child(job_node, 0, symbol_statement);
|
||||||
|
const parse_node_t &specific_statement = *get_child(statement, 0);
|
||||||
|
if (! specific_statement_type_is_redirectable_block(specific_statement))
|
||||||
|
{
|
||||||
|
/* Not an appropriate block type */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Must be no pipes */
|
||||||
|
const parse_node_t &continuation = *get_child(job_node, 1, symbol_job_continuation);
|
||||||
|
if (continuation.child_count > 0)
|
||||||
|
{
|
||||||
|
/* Multiple statements in this job, so there's pipes involved */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for arguments and redirections. All of the above types have an arguments / redirections list. It must be empty. */
|
||||||
|
const parse_node_t &args_and_redirections = tree.find_child(specific_statement, symbol_arguments_or_redirections_list);
|
||||||
|
if (args_and_redirections.child_count > 0)
|
||||||
|
{
|
||||||
|
/* Non-empty, we have an argument or redirection */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ok, we are a simple block! */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
parse_execution_result_t parse_execution_context_t::run_if_statement(const parse_node_t &statement)
|
parse_execution_result_t parse_execution_context_t::run_if_statement(const parse_node_t &statement)
|
||||||
{
|
{
|
||||||
assert(statement.type == symbol_if_statement);
|
assert(statement.type == symbol_if_statement);
|
||||||
|
@ -415,6 +456,9 @@ parse_execution_result_t parse_execution_context_t::run_for_statement(const pars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser->pop_block(fb);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1207,7 +1251,29 @@ parse_execution_result_t parse_execution_context_t::run_1_job(const parse_node_t
|
||||||
/* Increment the eval_level for the duration of this command */
|
/* Increment the eval_level for the duration of this command */
|
||||||
scoped_push<int> saved_eval_level(&eval_level, eval_level + 1);
|
scoped_push<int> saved_eval_level(&eval_level, eval_level + 1);
|
||||||
|
|
||||||
/* TODO: blocks-without-redirections optimization */
|
/* When we encounter a block construct (e.g. while loop) in the general case, we create a "block process" that has a pointer to its source. This allows us to handle block-level redirections. However, if there are no redirections, then we can just jump into the block directly, which is significantly faster. */
|
||||||
|
if (job_is_simple_block(job_node))
|
||||||
|
{
|
||||||
|
const parse_node_t &statement = *get_child(job_node, 0, symbol_statement);
|
||||||
|
const parse_node_t &specific_statement = *get_child(statement, 0);
|
||||||
|
assert(specific_statement_type_is_redirectable_block(specific_statement));
|
||||||
|
switch (specific_statement.type)
|
||||||
|
{
|
||||||
|
case symbol_block_statement:
|
||||||
|
return this->run_block_statement(specific_statement);
|
||||||
|
|
||||||
|
case symbol_if_statement:
|
||||||
|
return this->run_if_statement(specific_statement);
|
||||||
|
|
||||||
|
case symbol_switch_statement:
|
||||||
|
return this->run_switch_statement(specific_statement);
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Other types should be impossible due to the specific_statement_type_is_redirectable_block check */
|
||||||
|
PARSER_DIE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Profiling support */
|
/* Profiling support */
|
||||||
long long start_time = 0, parse_time = 0, exec_time = 0;
|
long long start_time = 0, parse_time = 0, exec_time = 0;
|
||||||
|
@ -1349,10 +1415,7 @@ parse_execution_result_t parse_execution_context_t::eval_node_at_offset(node_off
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Currently, we only expect to execute the top level job list, or a block node. Assert that. */
|
/* Currently, we only expect to execute the top level job list, or a block node. Assert that. */
|
||||||
assert(node.type == symbol_job_list ||
|
assert(node.type == symbol_job_list || specific_statement_type_is_redirectable_block(node));
|
||||||
node.type == symbol_block_statement ||
|
|
||||||
node.type == symbol_if_statement ||
|
|
||||||
node.type == symbol_switch_statement);
|
|
||||||
|
|
||||||
enum parse_execution_result_t status = parse_execution_success;
|
enum parse_execution_result_t status = parse_execution_success;
|
||||||
switch (node.type)
|
switch (node.type)
|
||||||
|
|
|
@ -64,6 +64,7 @@ class parse_execution_context_t
|
||||||
/* Wildcard error helper */
|
/* Wildcard error helper */
|
||||||
parse_execution_result_t report_unmatched_wildcard_error(const parse_node_t &unmatched_wildcard);
|
parse_execution_result_t report_unmatched_wildcard_error(const parse_node_t &unmatched_wildcard);
|
||||||
|
|
||||||
|
/* Command not found support */
|
||||||
void handle_command_not_found(const wcstring &cmd, const parse_node_t &statement_node, int err_code);
|
void handle_command_not_found(const wcstring &cmd, const parse_node_t &statement_node, int err_code);
|
||||||
|
|
||||||
/* Utilities */
|
/* Utilities */
|
||||||
|
@ -72,6 +73,9 @@ class parse_execution_context_t
|
||||||
node_offset_t get_offset(const parse_node_t &node) const;
|
node_offset_t get_offset(const parse_node_t &node) const;
|
||||||
const parse_node_t *infinite_recursive_statement_in_job_list(const parse_node_t &job_list, wcstring *out_func_name) const;
|
const parse_node_t *infinite_recursive_statement_in_job_list(const parse_node_t &job_list, wcstring *out_func_name) const;
|
||||||
|
|
||||||
|
/* Indicates whether a job is a simple block (one block, no redirections) */
|
||||||
|
bool job_is_simple_block(const parse_node_t &node) const;
|
||||||
|
|
||||||
enum process_type_t process_type_for_command(const parse_node_t &plain_statement, const wcstring &cmd) const;
|
enum process_type_t process_type_for_command(const parse_node_t &plain_statement, const wcstring &cmd) const;
|
||||||
|
|
||||||
/* These create process_t structures from statements */
|
/* These create process_t structures from statements */
|
||||||
|
|
Loading…
Reference in a new issue