===================================================================
@@ -1,4 +1,4 @@
-62d1b667f3e85f72a186b04aad36d701160a4611
+0e4aa31b26a20b6a6a2ca102b85ba8c8b8cdf876
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
===================================================================
@@ -3739,8 +3739,11 @@ Type_conversion_expression::do_flatten(G
this->expr_ = Expression::make_temporary_reference(temp, this->location());
}
- // For interface conversion, decide if we can allocate on stack.
- if (this->type()->interface_type() != NULL)
+ // For interface conversion and string to/from slice conversions,
+ // decide if we can allocate on stack.
+ if (this->type()->interface_type() != NULL
+ || this->type()->is_string_type()
+ || this->expr_->type()->is_string_type())
{
Node* n = Node::make_node(this);
if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
@@ -3984,9 +3987,21 @@ Type_conversion_expression::do_get_backe
return se->get_backend(context);
}
+ Expression* buf;
+ if (this->no_escape_)
+ {
+ Type* byte_type = Type::lookup_integer_type("uint8");
+ Expression* buflen =
+ Expression::make_integer_ul(4, NULL, loc);
+ Type* array_type = Type::make_array_type(byte_type, buflen);
+ buf = Expression::make_allocation(array_type, loc);
+ buf->allocation_expression()->set_allocate_on_stack();
+ buf->allocation_expression()->set_no_zero();
+ }
+ else
+ buf = Expression::make_nil(loc);
Expression* i2s_expr =
- Runtime::make_call(Runtime::INTSTRING, loc, 2,
- Expression::make_nil(loc), this->expr_);
+ Runtime::make_call(Runtime::INTSTRING, loc, 2, buf, this->expr_);
return Expression::make_cast(type, i2s_expr, loc)->get_backend(context);
}
else if (type->is_string_type() && expr_type->is_slice_type())
@@ -4019,7 +4034,21 @@ Type_conversion_expression::do_get_backe
go_assert(e->integer_type()->is_rune());
code = Runtime::SLICERUNETOSTRING;
}
- return Runtime::make_call(code, loc, 2, Expression::make_nil(loc),
+
+ Expression* buf;
+ if (this->no_escape_)
+ {
+ Type* byte_type = Type::lookup_integer_type("uint8");
+ Expression* buflen =
+ Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
+ Type* array_type = Type::make_array_type(byte_type, buflen);
+ buf = Expression::make_allocation(array_type, loc);
+ buf->allocation_expression()->set_allocate_on_stack();
+ buf->allocation_expression()->set_no_zero();
+ }
+ else
+ buf = Expression::make_nil(loc);
+ return Runtime::make_call(code, loc, 2, buf,
this->expr_)->get_backend(context);
}
else if (type->is_slice_type() && expr_type->is_string_type())
@@ -4035,9 +4064,20 @@ Type_conversion_expression::do_get_backe
go_assert(e->integer_type()->is_rune());
code = Runtime::STRINGTOSLICERUNE;
}
- Expression* s2a = Runtime::make_call(code, loc, 2,
- Expression::make_nil(loc),
- this->expr_);
+
+ Expression* buf;
+ if (this->no_escape_)
+ {
+ Expression* buflen =
+ Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
+ Type* array_type = Type::make_array_type(e, buflen);
+ buf = Expression::make_allocation(array_type, loc);
+ buf->allocation_expression()->set_allocate_on_stack();
+ buf->allocation_expression()->set_no_zero();
+ }
+ else
+ buf = Expression::make_nil(loc);
+ Expression* s2a = Runtime::make_call(code, loc, 2, buf, this->expr_);
return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context);
}
else if (type->is_numeric_type())
@@ -7428,7 +7468,35 @@ String_concat_expression::do_flatten(Gog
tce->set_no_copy(true);
}
- Expression* nil_arg = Expression::make_nil(loc);
+ Expression* buf = NULL;
+ Node* n = Node::make_node(this);
+ if ((n->encoding() & ESCAPE_MASK) == Node::ESCAPE_NONE)
+ {
+ size_t size = 0;
+ for (Expression_list::iterator p = this->exprs_->begin();
+ p != this->exprs_->end();
+ ++p)
+ {
+ std::string s;
+ if ((*p)->string_constant_value(&s))
+ size += s.length();
+ }
+ // Make a buffer on stack if the result does not escape.
+ // But don't do this if we know it won't fit.
+ if (size < (size_t)tmp_string_buf_size)
+ {
+ Type* byte_type = Type::lookup_integer_type("uint8");
+ Expression* buflen =
+ Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
+ Expression::make_integer_ul(tmp_string_buf_size, NULL, loc);
+ Type* array_type = Type::make_array_type(byte_type, buflen);
+ buf = Expression::make_allocation(array_type, loc);
+ buf->allocation_expression()->set_allocate_on_stack();
+ buf->allocation_expression()->set_no_zero();
+ }
+ }
+ if (buf == NULL)
+ buf = Expression::make_nil(loc);
Expression* call;
switch (this->exprs_->size())
{
@@ -7462,7 +7530,7 @@ String_concat_expression::do_flatten(Gog
code = Runtime::CONCATSTRING5;
break;
}
- call = Runtime::make_call(code, loc, 2, nil_arg, arg);
+ call = Runtime::make_call(code, loc, 2, buf, arg);
}
break;
@@ -7473,7 +7541,7 @@ String_concat_expression::do_flatten(Gog
Expression::make_slice_composite_literal(arg_type, this->exprs_,
loc);
sce->set_storage_does_not_escape();
- call = Runtime::make_call(Runtime::CONCATSTRINGS, loc, 2, nil_arg,
+ call = Runtime::make_call(Runtime::CONCATSTRINGS, loc, 2, buf,
sce);
}
break;
@@ -14254,6 +14322,8 @@ Allocation_expression::do_copy()
this->location());
if (this->allocate_on_stack_)
alloc->set_allocate_on_stack();
+ if (this->no_zero_)
+ alloc->set_no_zero();
return alloc;
}
@@ -14279,10 +14349,12 @@ Allocation_expression::do_get_backend(Tr
Named_object* fn = context->function();
go_assert(fn != NULL);
Bfunction* fndecl = fn->func_value()->get_or_make_decl(gogo, fn);
- Bexpression* zero = gogo->backend()->zero_expression(btype);
+ Bexpression* init = (this->no_zero_
+ ? NULL
+ : gogo->backend()->zero_expression(btype));
Bvariable* temp =
gogo->backend()->temporary_variable(fndecl, context->bblock(), btype,
- zero, true, loc, &decl);
+ init, true, loc, &decl);
Bexpression* ret = gogo->backend()->var_expression(temp, loc);
ret = gogo->backend()->address_expression(ret, loc);
ret = gogo->backend()->compound_expression(decl, ret, loc);
===================================================================
@@ -1822,9 +1822,8 @@ class Type_conversion_expression : publi
// True if a string([]byte) conversion can reuse the backing store
// without copying. Only used in string([]byte) conversion.
bool no_copy_;
- // True if a conversion to interface does not escape, so it does
- // not need a heap allocation. Only used in type-to-interface
- // conversion.
+ // True if a conversion does not escape. Used in type-to-interface
+ // conversions and slice-to/from-string conversions.
bool no_escape_;
};
@@ -3561,13 +3560,19 @@ class Allocation_expression : public Exp
public:
Allocation_expression(Type* type, Location location)
: Expression(EXPRESSION_ALLOCATION, location),
- type_(type), allocate_on_stack_(false)
+ type_(type), allocate_on_stack_(false),
+ no_zero_(false)
{ }
void
set_allocate_on_stack()
{ this->allocate_on_stack_ = true; }
+ // Mark that the allocated memory doesn't need zeroing.
+ void
+ set_no_zero()
+ { this->no_zero_ = true; }
+
protected:
int
do_traverse(Traverse*);
@@ -3596,6 +3601,8 @@ class Allocation_expression : public Exp
Type* type_;
// Whether or not this is a stack allocation.
bool allocate_on_stack_;
+ // Whether we don't need to zero the allocated memory.
+ bool no_zero_;
};
// A general composite literal. This is lowered to a type specific
@@ -4541,4 +4548,8 @@ class Numeric_constant
Type* type_;
};
+// Temporary buffer size for string conversions.
+// Also known to the runtime as tmpStringBufSize in runtime/string.go.
+static const int tmp_string_buf_size = 32;
+
#endif // !defined(GO_EXPRESSIONS_H)