aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-01-07 10:45:36 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-01-07 10:45:36 -0800
commitcb6be2a50dbf6718fad88c3586e409a53c785324 (patch)
tree9526141f9224dc726582dbfc8dccd1b6d0966414
parent45852f0497b0c73d0d7e3547e77abec65842e0f4 (diff)
Support for "simple block" optimization, where we can run blocks
directly if there are no arguments or redirections to the block itself
-rw-r--r--parse_execution.cpp73
-rw-r--r--parse_execution.h4
2 files changed, 72 insertions, 5 deletions
diff --git a/parse_execution.cpp b/parse_execution.cpp
index e5a9b9f3..aeca11a7 100644
--- a/parse_execution.cpp
+++ b/parse_execution.cpp
@@ -19,6 +19,12 @@
#include "exec.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)
{
@@ -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)
{
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;
}
@@ -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 */
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 */
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. */
- assert(node.type == symbol_job_list ||
- node.type == symbol_block_statement ||
- node.type == symbol_if_statement ||
- node.type == symbol_switch_statement);
+ assert(node.type == symbol_job_list || specific_statement_type_is_redirectable_block(node));
enum parse_execution_result_t status = parse_execution_success;
switch (node.type)
diff --git a/parse_execution.h b/parse_execution.h
index 0d924b8e..6c022cb2 100644
--- a/parse_execution.h
+++ b/parse_execution.h
@@ -64,6 +64,7 @@ class parse_execution_context_t
/* Wildcard error helper */
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);
/* Utilities */
@@ -72,6 +73,9 @@ class parse_execution_context_t
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;
+ /* 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;
/* These create process_t structures from statements */