aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2015-12-07 14:51:44 +0100
committerBjörn Gustavsson <[email protected]>2016-04-07 15:28:29 +0200
commitc6cabe0b76dda183d209498e1e4e13e3407dcf9b (patch)
tree1ab158a8dae450d21f72e7bb3d4b1b1d512292a4
parent6d51b25958393d95dee32baafd708aa3909ddb5a (diff)
downloadotp-c6cabe0b76dda183d209498e1e4e13e3407dcf9b.tar.gz
otp-c6cabe0b76dda183d209498e1e4e13e3407dcf9b.tar.bz2
otp-c6cabe0b76dda183d209498e1e4e13e3407dcf9b.zip
Simplify window management for the transformation engine
Generic instructions have a min_window field. Its purpose is to avoid calling transform_engine() when there are too few instructions in the current "transformation window" for a transformation to succeed. Currently it does not do much good since the window size will be decremented by one before being used. The reason for the subtraction is probably that in some circumstances in the past, the loader could read past the end of the BEAM module while attempting to fetch instructions to increase the window size. Therefore, it would not be safe to just remove the subtraction by one. The simplest and safest solution seems to always ensure that there are always at least TWO instructions when calling transform_engine(). That will be safe, as long as a BEAM module is always finished with an int_code_end/0 that is not involved in any transformation.
-rw-r--r--erts/emulator/beam/beam_load.c16
-rw-r--r--erts/emulator/beam/beam_load.h1
-rwxr-xr-xerts/emulator/utils/beam_makeops13
3 files changed, 11 insertions, 19 deletions
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index c6c35e74c9..5d03c98657 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -2030,14 +2030,14 @@ load_code(LoaderState* stp)
do_transform:
ASSERT(stp->genop != NULL);
if (gen_opc[stp->genop->op].transform != -1) {
- int need;
- tmp_op = stp->genop;
-
- for (need = gen_opc[stp->genop->op].min_window-1; need > 0; need--) {
- if (tmp_op == NULL) {
- goto get_next_instr;
- }
- tmp_op = tmp_op->next;
+ if (stp->genop->next == NULL) {
+ /*
+ * Simple heuristic: Most transformations requires
+ * at least two instructions, so make sure that
+ * there are. That will reduce the number of
+ * TE_SHORT_WINDOWs.
+ */
+ goto get_next_instr;
}
switch (transform_engine(stp)) {
case TE_FAIL:
diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h
index 22ab71c868..68f4b96893 100644
--- a/erts/emulator/beam/beam_load.h
+++ b/erts/emulator/beam/beam_load.h
@@ -33,7 +33,6 @@ typedef struct gen_op_entry {
int specific;
int num_specific;
int transform;
- int min_window;
} GenOpEntry;
extern GenOpEntry gen_opc[];
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 86bfb5d746..8f99fdb201 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -113,7 +113,6 @@ my @if_line;
#
my $te_max_vars = 0; # Max number of variables ever needed.
my %gen_transform;
-my %min_window;
my %match_engine_ops; # All opcodes for the match engine.
my %gen_transform_offset;
my @transformations;
@@ -382,7 +381,6 @@ while (<>) {
$gen_arity{$name} = $arity;
$gen_to_spec{"$name/$arity"} = undef;
$num_specific{"$name/$arity"} = 0;
- $min_window{"$name/$arity"} = 255;
$obsolete[$op_num] = defined $obsolete;
} else { # Unnumbered generic operation.
push(@unnumbered_generic, [$name, $arity]);
@@ -440,7 +438,6 @@ $num_file_opcodes = @gen_opname;
$gen_arity{$name} = $arity;
$gen_to_spec{"$name/$arity"} = undef;
$num_specific{"$name/$arity"} = 0;
- $min_window{"$name/$arity"} = 255;
}
}
@@ -607,7 +604,7 @@ sub emulator_output {
$is_transformed{$name,$arity} or
error("instruction $key has no specific instruction");
$spec_op = -1 unless defined $spec_op;
- &init_item($name, $arity, $spec_op, $num_specific, $tr, $min_window{$key});
+ &init_item($name, $arity, $spec_op, $num_specific, $tr);
}
}
print "};\n";
@@ -1503,7 +1500,6 @@ sub tr_gen_from {
my(%var_type);
my($var_num) = 0;
my(@code);
- my($min_window) = 0;
my($op, $ref); # Loop variables.
my $where = "left side of transformation in line $line: ";
my %var_used = %$used_ref;
@@ -1551,7 +1547,6 @@ sub tr_gen_from {
$opnum = $gen_opnum{$name,$arity};
push(@code, make_op("$name/$arity", 'next_instr', $opnum));
- $min_window++;
foreach $op (@ops) {
my($var, $type, $type_val, $cond, $val) = @$op;
my $ignored_var = "$var (ignored)";
@@ -1642,12 +1637,12 @@ sub tr_gen_from {
$te_max_vars = $var_num
if $te_max_vars < $var_num;
- [$min_window, \%var, \%var_type, \@code];
+ [\%var, \%var_type, \@code];
}
sub tr_gen_to {
my($line, $orig_transform, $so_far, @tr) = @_;
- my($min_window, $var_ref, $var_type_ref, $code_ref) = @$so_far;
+ my($var_ref, $var_type_ref, $code_ref) = @$so_far;
my(%var) = %$var_ref;
my(%var_type) = %$var_type_ref;
my(@code) = @$code_ref;
@@ -1731,8 +1726,6 @@ sub tr_gen_to {
my($dummy, $arity);
($dummy, $op, $arity) = @$first;
my($comment) = "\n/*\n * Line $line:\n * $orig_transform\n */\n\n";
- $min_window{$key} = $min_window
- if $min_window{$key} > $min_window;
my $prev_last;
$prev_last = pop(@{$gen_transform{$key}})