Commit 92f0112c by Than McIntosh Committed by Ian Lance Taylor

compiler: introduce size threshold for nil checks

    
    Add a new control variable to the Gogo class that stores the size
    threshold for nil checks. This value can be used to control the
    policy for deciding when a given deference operation needs a check and
    when it does not. A size threshold of -1 means that every potentially
    faulting dereference needs an explicit check (and branch to error
    call). A size threshold of K (where K > 0) means that if the size of
    the object being dereferenced is >= K, then we need a check.
    
    Reviewed-on: https://go-review.googlesource.com/80996

	* go-c.h (go_create_gogo_args): Add nil_check_size_threshold
	field.
	* go-lang.c (go_langhook_init): Set nil_check_size_threshold.

From-SVN: r255340
parent 19041dad
2017-12-01 Than McIntosh <thanm@google.com>
* go-c.h (go_create_gogo_args): Add nil_check_size_threshold
field.
* go-lang.c (go_langhook_init): Set nil_check_size_threshold.
2017-11-28 Jakub Jelinek <jakub@redhat.com>
* go-gcc.cc (Gcc_backend::switch_statement): Build SWITCH_EXPR using
......
......@@ -47,6 +47,7 @@ struct go_create_gogo_args
bool check_divide_overflow;
bool compiling_runtime;
int debug_escape_level;
int64_t nil_check_size_threshold;
};
extern void go_create_gogo (const struct go_create_gogo_args*);
......
......@@ -112,6 +112,7 @@ go_langhook_init (void)
args.check_divide_overflow = go_check_divide_overflow;
args.compiling_runtime = go_compiling_runtime;
args.debug_escape_level = go_debug_escape_level;
args.nil_check_size_threshold = 4096;
args.linemap = go_get_linemap();
args.backend = go_get_backend();
go_create_gogo (&args);
......
0d6b3abcbfe04949db947081651a503ceb12fe6e
8cd42a3e9e0e618bb09e67be73f7d2f2477a0faa
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
......@@ -506,6 +506,23 @@ class Expression
static Expression*
make_backend(Bexpression*, Type*, Location);
enum Nil_check_classification
{
// Use the default policy for deciding if this deref needs a check.
NIL_CHECK_DEFAULT,
// An explicit check is required for this dereference operation.
NIL_CHECK_NEEDED,
// No check needed for this dereference operation.
NIL_CHECK_NOT_NEEDED,
// A type error or error construct was encountered when determining
// whether this deref needs an explicit check.
NIL_CHECK_ERROR_ENCOUNTERED
};
// Make a dereference expression.
static Expression*
make_dereference(Expression*, Nil_check_classification, Location);
// Return the expression classification.
Expression_classification
classification() const
......@@ -1730,7 +1747,8 @@ class Unary_expression : public Expression
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
is_slice_init_(false), expr_(expr), issue_nil_check_(false)
is_slice_init_(false), expr_(expr),
issue_nil_check_(NIL_CHECK_DEFAULT)
{ }
// Return the operator.
......@@ -1792,6 +1810,17 @@ class Unary_expression : public Expression
static Expression*
do_import(Import*);
// Declare that this deref does or does not require an explicit nil check.
void
set_requires_nil_check(bool needed)
{
go_assert(this->op_ == OPERATOR_MULT);
if (needed)
this->issue_nil_check_ = NIL_CHECK_NEEDED;
else
this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED;
}
protected:
int
do_traverse(Traverse* traverse)
......@@ -1847,12 +1876,20 @@ class Unary_expression : public Expression
void
do_issue_nil_check()
{ this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
{
if (this->op_ == OPERATOR_MULT)
this->set_requires_nil_check(true);
}
private:
static bool
base_is_static_initializer(Expression*);
// Return a determination as to whether this dereference expression
// requires a nil check.
Nil_check_classification
requires_nil_check(Gogo*);
// The unary operator to apply.
Operator op_;
// Normally true. False if this is an address expression which does
......@@ -1874,7 +1911,7 @@ class Unary_expression : public Expression
Expression* expr_;
// Whether or not to issue a nil check for this expression if its address
// is being taken.
bool issue_nil_check_;
Nil_check_classification issue_nil_check_;
};
// A binary expression.
......
......@@ -41,6 +41,7 @@ go_create_gogo(const struct go_create_gogo_args* args)
if (args->c_header != NULL)
::gogo->set_c_header(args->c_header);
::gogo->set_debug_escape_level(args->debug_escape_level);
::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold);
}
// Parse the input files.
......
......@@ -55,6 +55,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
check_divide_overflow_(true),
compiling_runtime_(false),
debug_escape_level_(0),
nil_check_size_threshold_(4096),
verify_types_(),
interface_types_(),
specific_type_functions_(),
......@@ -5567,7 +5568,10 @@ Function::build(Gogo* gogo, Named_object* named_function)
vars.push_back(bvar);
Expression* parm_ref =
Expression::make_var_reference(parm_no, loc);
parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc);
parm_ref =
Expression::make_dereference(parm_ref,
Expression::NIL_CHECK_DEFAULT,
loc);
if ((*p)->var_value()->is_in_heap())
parm_ref = Expression::make_heap_expression(parm_ref, loc);
var_inits.push_back(parm_ref->get_backend(&context));
......
......@@ -318,6 +318,20 @@ class Gogo
set_debug_escape_level(int level)
{ this->debug_escape_level_ = level; }
// Return the size threshold used to determine whether to issue
// a nil-check for a given pointer dereference. A threshold of -1
// implies that all potentially faulting dereference ops should
// be nil-checked. A positive threshold of N implies that a deref
// of *P where P has size less than N doesn't need a nil check.
int64_t
nil_check_size_threshold() const
{ return this->nil_check_size_threshold_; }
// Set the nil-check size threshold, as described above.
void
set_nil_check_size_threshold(int64_t bytes)
{ this->nil_check_size_threshold_ = bytes; }
// Import a package. FILENAME is the file name argument, LOCAL_NAME
// is the local name to give to the package. If LOCAL_NAME is empty
// the declarations are added to the global scope.
......@@ -1025,6 +1039,8 @@ class Gogo
// The level of escape analysis debug information to emit, from the
// -fgo-debug-escape option.
int debug_escape_level_;
// Nil-check size threshhold.
int64_t nil_check_size_threshold_;
// A list of types to verify.
std::vector<Type*> verify_types_;
// A list of interface types defined while parsing.
......
......@@ -2745,14 +2745,17 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var,
Expression* closure_ref = Expression::make_var_reference(closure,
location);
closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location);
closure_ref =
Expression::make_dereference(closure_ref,
Expression::NIL_CHECK_DEFAULT,
location);
// The closure structure holds pointers to the variables, so we need
// to introduce an indirection.
Expression* e = Expression::make_field_reference(closure_ref,
ins.first->index(),
location);
e = Expression::make_unary(OPERATOR_MULT, e, location);
e = Expression::make_dereference(e, Expression::NIL_CHECK_DEFAULT, location);
return Expression::make_enclosing_var_reference(e, var, location);
}
......
......@@ -315,7 +315,8 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
if (binit != NULL)
{
Expression* e = Expression::make_temporary_reference(temp, loc);
e = Expression::make_unary(OPERATOR_MULT, e, loc);
e = Expression::make_dereference(e, Expression::NIL_CHECK_NOT_NEEDED,
loc);
Bexpression* be = e->get_backend(context);
set = context->backend()->assignment_statement(bfunction, be, binit, loc);
}
......@@ -740,7 +741,9 @@ Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
a1, a2, a3);
Type* ptrval_type = Type::make_pointer_type(mt->val_type());
call = Expression::make_cast(ptrval_type, call, loc);
Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc);
Expression* indir =
Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED,
loc);
ref = Expression::make_temporary_reference(val_temp, loc);
b->add_statement(Statement::make_assignment(indir, ref, loc));
......@@ -1292,7 +1295,8 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
// val = *val__ptr_temp
ref = Expression::make_temporary_reference(val_ptr_temp, loc);
Expression* ind = Expression::make_unary(OPERATOR_MULT, ref, loc);
Expression* ind =
Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc);
s = Statement::make_assignment(this->val_, ind, loc);
b->add_statement(s);
......@@ -2367,8 +2371,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
// ones used in build_struct.
Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
location);
thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
location);
thunk_parameter =
Expression::make_dereference(thunk_parameter,
Expression::NIL_CHECK_NOT_NEEDED,
location);
Interface_field_reference_expression* interface_method =
ce->fn()->interface_field_reference_expression();
......@@ -2421,8 +2427,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
{
Expression* thunk_param =
Expression::make_var_reference(named_parameter, location);
thunk_param =
Expression::make_unary(OPERATOR_MULT, thunk_param, location);
thunk_param =
Expression::make_dereference(thunk_param,
Expression::NIL_CHECK_NOT_NEEDED,
location);
param = Expression::make_field_reference(thunk_param,
next_index,
location);
......@@ -5837,7 +5845,8 @@ For_range_statement::lower_range_map(Gogo* gogo,
Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
Expression* rhs = Expression::make_temporary_reference(hiter, loc);
rhs = Expression::make_field_reference(ref, 0, loc);
rhs = Expression::make_unary(OPERATOR_MULT, ref, loc);
rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED,
loc);
Statement* set = Statement::make_assignment(lhs, rhs, loc);
iter_init->add_statement(set);
......@@ -5846,7 +5855,8 @@ For_range_statement::lower_range_map(Gogo* gogo,
lhs = Expression::make_temporary_reference(value_temp, loc);
rhs = Expression::make_temporary_reference(hiter, loc);
rhs = Expression::make_field_reference(rhs, 1, loc);
rhs = Expression::make_unary(OPERATOR_MULT, rhs, loc);
rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED,
loc);
set = Statement::make_assignment(lhs, rhs, loc);
iter_init->add_statement(set);
}
......
......@@ -2215,10 +2215,10 @@ Type::write_named_equal(Gogo* gogo, Named_type* name)
// Compare the values for equality.
Expression* t1 = Expression::make_temporary_reference(p1, bloc);
t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc);
t1 = Expression::make_dereference(t1, Expression::NIL_CHECK_NOT_NEEDED, bloc);
Expression* t2 = Expression::make_temporary_reference(p2, bloc);
t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc);
t2 = Expression::make_dereference(t2, Expression::NIL_CHECK_NOT_NEEDED, bloc);
Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc);
......@@ -5911,7 +5911,9 @@ Struct_type::field_reference_depth(Expression* struct_expr,
Expression* here = Expression::make_field_reference(struct_expr, i,
location);
if (pf->type()->points_to() != NULL)
here = Expression::make_unary(OPERATOR_MULT, here, location);
here = Expression::make_dereference(here,
Expression::NIL_CHECK_DEFAULT,
location);
while (sub->expr() != NULL)
{
sub = sub->expr()->deref()->field_reference_expression();
......@@ -6342,11 +6344,13 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
// Compare one field in both P1 and P2.
Expression* f1 = Expression::make_temporary_reference(p1, bloc);
f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
f1 = Expression::make_dereference(f1, Expression::NIL_CHECK_DEFAULT,
bloc);
f1 = Expression::make_field_reference(f1, field_index, bloc);
Expression* f2 = Expression::make_temporary_reference(p2, bloc);
f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc);
f2 = Expression::make_dereference(f2, Expression::NIL_CHECK_DEFAULT,
bloc);
f2 = Expression::make_field_reference(f2, field_index, bloc);
Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc);
......@@ -7193,12 +7197,12 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name)
// Compare element in P1 and P2.
Expression* e1 = Expression::make_temporary_reference(p1, bloc);
e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc);
e1 = Expression::make_dereference(e1, Expression::NIL_CHECK_DEFAULT, bloc);
ref = Expression::make_temporary_reference(index, bloc);
e1 = Expression::make_array_index(e1, ref, NULL, NULL, bloc);
Expression* e2 = Expression::make_temporary_reference(p2, bloc);
e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc);
e2 = Expression::make_dereference(e2, Expression::NIL_CHECK_DEFAULT, bloc);
ref = Expression::make_temporary_reference(index, bloc);
e2 = Expression::make_array_index(e2, ref, NULL, NULL, bloc);
......@@ -11219,7 +11223,8 @@ Type::apply_field_indexes(Expression* expr,
if (expr->type()->struct_type() == NULL)
{
go_assert(expr->type()->points_to() != NULL);
expr = Expression::make_unary(OPERATOR_MULT, expr, location);
expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
location);
go_assert(expr->type()->struct_type() == stype);
}
return Expression::make_field_reference(expr, field_indexes->field_index,
......@@ -11323,7 +11328,8 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
&& type->points_to() != NULL
&& type->points_to()->points_to() != NULL)
{
expr = Expression::make_unary(OPERATOR_MULT, expr, location);
expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
location);
type = type->points_to();
if (type->deref()->is_error_type())
return Expression::make_error(location);
......@@ -11356,8 +11362,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
return Expression::make_error(location);
}
go_assert(type->points_to() != NULL);
expr = Expression::make_unary(OPERATOR_MULT, expr,
location);
expr = Expression::make_dereference(expr,
Expression::NIL_CHECK_DEFAULT,
location);
go_assert(expr->type()->struct_type() == st);
}
ret = st->field_reference(expr, name, location);
......
......@@ -417,7 +417,8 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing,
rhs = Expression::make_temporary_reference(rhs_temp, loc);
}
Expression* indir = Expression::make_unary(OPERATOR_MULT, lhs, loc);
Expression* indir =
Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc);
Statement* assign = Statement::make_assignment(indir, rhs, loc);
lhs = Expression::make_temporary_reference(lhs_temp, loc);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment