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:
ridiculousfish 2014-01-07 10:45:36 -08:00
parent 45852f0497
commit cb6be2a50d
2 changed files with 72 additions and 5 deletions

View file

@ -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)

View file

@ -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 */