-c257303eaef143663216e483857d5b259e05753f
+c8a9bccbc524381d150c84907a61ac257c1b07cc
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
}
break;
+ case Expression::EXPRESSION_SLICE_VALUE:
+ {
+ // Connect the pointer field to the slice value.
+ Node* slice_node = Node::make_node(*pexpr);
+ Node* ptr_node =
+ Node::make_node((*pexpr)->slice_value_expression()->valmem());
+ this->assign(slice_node, ptr_node);
+ }
+ break;
+
case Expression::EXPRESSION_HEAP:
{
Node* pointer_node = Node::make_node(*pexpr);
// DST = map[T]V{...}.
case Expression::EXPRESSION_STRUCT_CONSTRUCTION:
// DST = T{...}.
+ case Expression::EXPRESSION_SLICE_VALUE:
+ // DST = slice{ptr, len, cap}
case Expression::EXPRESSION_ALLOCATION:
// DST = new(T).
case Expression::EXPRESSION_BOUND_METHOD:
Expression* call;
if (is_slice)
{
+ Temporary_statement* len_temp = NULL;
+ if (!len_arg->is_constant())
+ {
+ len_temp = Statement::make_temporary(NULL, len_arg, loc);
+ inserter->insert(len_temp);
+ len_arg = Expression::make_temporary_reference(len_temp, loc);
+ }
+
if (cap_arg == NULL)
{
cap_small = len_small;
- if (len_arg->numeric_constant_value(&nclen)
- && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID)
- cap_arg = Expression::make_integer_ul(vlen, len_arg->type(), loc);
- else
- {
- Temporary_statement* temp = Statement::make_temporary(NULL,
- len_arg,
- loc);
- inserter->insert(temp);
- len_arg = Expression::make_temporary_reference(temp, loc);
- cap_arg = Expression::make_temporary_reference(temp, loc);
- }
+ if (len_temp == NULL)
+ cap_arg = len_arg->copy();
+ else
+ cap_arg = Expression::make_temporary_reference(len_temp, loc);
+ }
+ else if (!cap_arg->is_constant())
+ {
+ Temporary_statement* cap_temp = Statement::make_temporary(NULL,
+ cap_arg,
+ loc);
+ inserter->insert(cap_temp);
+ cap_arg = Expression::make_temporary_reference(cap_temp, loc);
}
Type* et = type->array_type()->element_type();
Runtime::Function code = Runtime::MAKESLICE;
if (!len_small || !cap_small)
code = Runtime::MAKESLICE64;
- call = Runtime::make_call(code, loc, 3, type_arg, len_arg, cap_arg);
+ Expression* mem = Runtime::make_call(code, loc, 3, type_arg, len_arg,
+ cap_arg);
+ mem = Expression::make_unsafe_cast(Type::make_pointer_type(et), mem,
+ loc);
+ call = Expression::make_slice_value(type, mem, len_arg->copy(),
+ cap_arg->copy(), loc);
}
else if (is_map)
{
go_assert(this->storage_escapes_ || this->element_count() == 0);
space = Expression::make_heap_expression(this->array_val_, loc);
}
+ Array_type* at = this->valtype_->array_type();
+ Type* et = at->element_type();
+ space = Expression::make_unsafe_cast(Type::make_pointer_type(et),
+ space, loc);
// Build a constructor for the slice.
- Expression* len = this->valtype_->array_type()->length();
+ Expression* len = at->length();
Expression* slice_val =
Expression::make_slice_value(this->type(), space, len, len, loc);
return slice_val->get_backend(context);
return new Slice_info_expression(slice, slice_info, location);
}
-// An expression that represents a slice value: a struct with value pointer,
-// length, and capacity fields.
-
-class Slice_value_expression : public Expression
-{
- public:
- Slice_value_expression(Type* type, Expression* valptr, Expression* len,
- Expression* cap, Location location)
- : Expression(EXPRESSION_SLICE_VALUE, location),
- type_(type), valptr_(valptr), len_(len), cap_(cap)
- { }
-
- protected:
- int
- do_traverse(Traverse*);
-
- Type*
- do_type()
- { return this->type_; }
-
- void
- do_determine_type(const Type_context*)
- { go_unreachable(); }
-
- Expression*
- do_copy()
- {
- return new Slice_value_expression(this->type_->copy_expressions(),
- this->valptr_->copy(),
- this->len_->copy(), this->cap_->copy(),
- this->location());
- }
-
- Bexpression*
- do_get_backend(Translate_context* context);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The type of the slice value.
- Type* type_;
- // The pointer to the values in the slice.
- Expression* valptr_;
- // The length of the slice.
- Expression* len_;
- // The capacity of the slice.
- Expression* cap_;
-};
+// Class Slice_value_expression.
int
Slice_value_expression::do_traverse(Traverse* traverse)
{
if (Type::traverse(this->type_, traverse) == TRAVERSE_EXIT
- || Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->valmem_, traverse) == TRAVERSE_EXIT
|| Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT
|| Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
return TRAVERSE_CONTINUE;
}
+Expression*
+Slice_value_expression::do_copy()
+{
+ return new Slice_value_expression(this->type_->copy_expressions(),
+ this->valmem_->copy(),
+ this->len_->copy(), this->cap_->copy(),
+ this->location());
+}
+
Bexpression*
Slice_value_expression::do_get_backend(Translate_context* context)
{
std::vector<Bexpression*> vals(3);
- vals[0] = this->valptr_->get_backend(context);
+ vals[0] = this->valmem_->get_backend(context);
vals[1] = this->len_->get_backend(context);
vals[2] = this->cap_->get_backend(context);
{
ast_dump_context->ostream() << "slicevalue(";
ast_dump_context->ostream() << "values: ";
- this->valptr_->dump_expression(ast_dump_context);
+ this->valmem_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ", length: ";
this->len_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ", capacity: ";
}
Expression*
-Expression::make_slice_value(Type* at, Expression* valptr, Expression* len,
+Expression::make_slice_value(Type* at, Expression* valmem, Expression* len,
Expression* cap, Location location)
{
go_assert(at->is_slice_type());
- return new Slice_value_expression(at, valptr, len, cap, location);
+ go_assert(valmem->is_nil_expression()
+ || (at->array_type()->element_type()
+ == valmem->type()->points_to()));
+ return new Slice_value_expression(at, valmem, len, cap, location);
}
// An expression that evaluates to some characteristic of a non-empty interface.
class Type_guard_expression;
class Heap_expression;
class Receive_expression;
+class Slice_value_expression;
class Conditional_expression;
class Compound_expression;
class Numeric_constant;
receive_expression()
{ return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); }
+ // If this is a slice value expression, return the Slice_valiue_expression
+ // structure. Otherwise, return NULL.
+ Slice_value_expression*
+ slice_value_expression()
+ { return this->convert<Slice_value_expression, EXPRESSION_SLICE_VALUE>(); }
+
// If this is a conditional expression, return the Conditional_expression
// structure. Otherwise, return NULL.
Conditional_expression*
Temporary_statement* temp_receiver_;
};
+// An expression that represents a slice value: a struct with value pointer,
+// length, and capacity fields.
+
+class Slice_value_expression : public Expression
+{
+ public:
+ Slice_value_expression(Type* type, Expression* valmem, Expression* len,
+ Expression* cap, Location location)
+ : Expression(EXPRESSION_SLICE_VALUE, location),
+ type_(type), valmem_(valmem), len_(len), cap_(cap)
+ { }
+
+ // The memory holding the values in the slice. The type should be a
+ // pointer to the element value of the slice.
+ Expression*
+ valmem() const
+ { return this->valmem_; }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return this->type_; }
+
+ void
+ do_determine_type(const Type_context*)
+ { }
+
+ Expression*
+ do_copy();
+
+ Bexpression*
+ do_get_backend(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The type of the slice value.
+ Type* type_;
+ // The memory holding the values in the slice.
+ Expression* valmem_;
+ // The length of the slice.
+ Expression* len_;
+ // The capacity of the slice.
+ Expression* cap_;
+};
+
// Conditional expressions.
class Conditional_expression : public Expression
// Make a slice.
DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT),
- R1(SLICE))
+ R1(POINTER))
DEF_GO_RUNTIME(MAKESLICE64, "runtime.makeslice64", P3(TYPE, INT64, INT64),
- R1(SLICE))
+ R1(POINTER))
// Make a map with a hint and an (optional, unused) map structure.
expression(Expression**);
private:
+ Call_expression*
+ find_makeslice_call(Expression*);
+
// General IR.
Gogo* gogo_;
// The function we are traversing.
return TRAVERSE_CONTINUE;
}
+// Look through the expression of a Slice_value_expression's valmem to
+// find an call to makeslice.
+
+Call_expression*
+Mark_address_taken::find_makeslice_call(Expression* expr)
+{
+ Unsafe_type_conversion_expression* utce =
+ expr->unsafe_conversion_expression();
+ if (utce != NULL)
+ expr = utce->expr();
+
+ Call_expression* call = expr->call_expression();
+ if (call == NULL)
+ return NULL;
+
+ Func_expression* fe = call->fn()->func_expression();
+ if (fe != NULL && fe->runtime_code() == Runtime::MAKESLICE)
+ return call;
+
+ // We don't worry about MAKESLICE64 bcause we don't want to use a
+ // stack allocation for a large slice anyhow.
+
+ return NULL;
+}
+
// Mark variable addresses taken.
int
}
// Rewrite non-escaping makeslice with constant size to stack allocation.
- Unsafe_type_conversion_expression* uce =
- expr->unsafe_conversion_expression();
- if (uce != NULL
- && uce->type()->is_slice_type()
- && Node::make_node(uce->expr())->encoding() == Node::ESCAPE_NONE
- && uce->expr()->call_expression() != NULL)
+ Slice_value_expression* sve = expr->slice_value_expression();
+ if (sve != NULL)
{
- Call_expression* call = uce->expr()->call_expression();
- if (call->fn()->func_expression() != NULL
- && call->fn()->func_expression()->runtime_code() == Runtime::MAKESLICE)
+ Call_expression* call = this->find_makeslice_call(sve->valmem());
+ if (call != NULL
+ && Node::make_node(call)->encoding() == Node::ESCAPE_NONE)
{
Expression* len_arg = call->args()->at(1);
Expression* cap_arg = call->args()->at(2);
&& nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID
&& nccap.to_unsigned_long(&vcap) == Numeric_constant::NC_UL_VALID)
{
- // Turn it into a slice expression of an addressable array,
- // which is allocated on stack.
+ // Stack allocate an array and make a slice value from it.
Location loc = expr->location();
Type* elmt_type = expr->type()->array_type()->element_type();
Expression* len_expr =
Type* array_type = Type::make_array_type(elmt_type, len_expr);
Expression* alloc = Expression::make_allocation(array_type, loc);
alloc->allocation_expression()->set_allocate_on_stack();
- Expression* array = Expression::make_unary(OPERATOR_MULT, alloc, loc);
- Expression* zero = Expression::make_integer_ul(0, len_arg->type(), loc);
- Expression* slice =
- Expression::make_array_index(array, zero, len_arg, cap_arg, loc);
+ Type* ptr_type = Type::make_pointer_type(elmt_type);
+ Expression* ptr = Expression::make_unsafe_cast(ptr_type, alloc,
+ loc);
+ Expression* slice =
+ Expression::make_slice_value(expr->type(), ptr, len_arg,
+ cap_arg, loc);
*pexpr = slice;
}
}
// Allocate transient memory using reflect.Call.
func allocateReflectTransient() {
- memSink = make([]byte, 2<<20)
+ memSink = make([]byte, 3<<20)
}
func allocateReflect() {
// GC means that sometimes the value is not collected.
fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @( 0x[0-9,a-f]+)+
# 0x[0-9,a-f]+ pprof\.allocateReflectTransient\+0x[0-9,a-f]+ .*/mprof_test.go:48
-`, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun),
+`, memoryProfilerRun, (3<<20)*memoryProfilerRun, memoryProfilerRun, (3<<20)*memoryProfilerRun),
}
for _, test := range tests {
panic(errorString("makeslice: cap out of range"))
}
-func makeslice(et *_type, len, cap int) slice {
+func makeslice(et *_type, len, cap int) unsafe.Pointer {
// NOTE: The len > maxElements check here is not strictly necessary,
// but it produces a 'len out of range' error instead of a 'cap out of range' error
// when someone does make([]T, bignumber). 'cap out of range' is true too,
panicmakeslicecap()
}
- p := mallocgc(et.size*uintptr(cap), et, true)
- return slice{p, len, cap}
+ return mallocgc(et.size*uintptr(cap), et, true)
}
-func makeslice64(et *_type, len64, cap64 int64) slice {
+func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer {
len := int(len64)
if int64(len) != len64 {
panicmakeslicelen()