compiler, runtime: copy slice code from Go 1.7 runtime
Change the compiler handle append as the gc compiler does: call a function to grow the slice, but otherwise assign the new elements directly to the final slice. For the current gccgo memory allocator the slice code has to call runtime_newarray, not mallocgc directly, so that the allocator sets the TypeInfo_Array bit in the type pointer. Rename the static function cnew to runtime_docnew, so that the stack trace ignores it when ignoring runtime functions. This was needed to fix the runtime/pprof tests on 386. Reviewed-on: https://go-review.googlesource.com/32218 From-SVN: r241667
This commit is contained in:
parent
21f1031d6c
commit
94f56408db
14 changed files with 661 additions and 472 deletions
|
@ -1,4 +1,4 @@
|
|||
5ddcdfb0b2bb992a70b391ab34bf15291a514e48
|
||||
fe38baff61b9b9426a4f60ff078cf3c8722bf94d
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -284,20 +284,19 @@ Node::op_format() const
|
|||
op << "panic";
|
||||
break;
|
||||
|
||||
case Runtime::APPEND:
|
||||
case Runtime::GROWSLICE:
|
||||
op << "append";
|
||||
break;
|
||||
|
||||
case Runtime::COPY:
|
||||
case Runtime::SLICECOPY:
|
||||
case Runtime::SLICESTRINGCOPY:
|
||||
case Runtime::TYPEDSLICECOPY:
|
||||
op << "copy";
|
||||
break;
|
||||
|
||||
case Runtime::MAKECHAN:
|
||||
case Runtime::MAKEMAP:
|
||||
case Runtime::MAKESLICE1:
|
||||
case Runtime::MAKESLICE2:
|
||||
case Runtime::MAKESLICE1BIG:
|
||||
case Runtime::MAKESLICE2BIG:
|
||||
case Runtime::MAKESLICE:
|
||||
op << "make";
|
||||
break;
|
||||
|
||||
|
@ -419,10 +418,7 @@ Node::is_big(Escape_context* context) const
|
|||
Func_expression* fn = call->fn()->func_expression();
|
||||
if (fn != NULL
|
||||
&& fn->is_runtime_function()
|
||||
&& (fn->runtime_code() == Runtime::MAKESLICE1
|
||||
|| fn->runtime_code() == Runtime::MAKESLICE2
|
||||
|| fn->runtime_code() == Runtime::MAKESLICE1BIG
|
||||
|| fn->runtime_code() == Runtime::MAKESLICE2BIG))
|
||||
&& fn->runtime_code() == Runtime::MAKESLICE)
|
||||
{
|
||||
// Second argument is length.
|
||||
Expression_list::iterator p = call->args()->begin();
|
||||
|
@ -1201,13 +1197,25 @@ Escape_analysis_assign::expression(Expression** pexpr)
|
|||
}
|
||||
break;
|
||||
|
||||
case Runtime::APPEND:
|
||||
case Runtime::GROWSLICE:
|
||||
{
|
||||
// Unlike gc/esc.go, a call to append has already had its
|
||||
// varargs lowered into a slice of arguments.
|
||||
// The content of the appended slice leaks.
|
||||
Node* appended = Node::make_node(call->args()->back());
|
||||
this->assign_deref(this->context_->sink(), appended);
|
||||
// The contents being appended leak.
|
||||
if (call->is_varargs())
|
||||
{
|
||||
Node* appended = Node::make_node(call->args()->back());
|
||||
this->assign_deref(this->context_->sink(), appended);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Expression_list::const_iterator pa =
|
||||
call->args()->begin();
|
||||
pa != call->args()->end();
|
||||
++pa)
|
||||
{
|
||||
Node* arg = Node::make_node(*pa);
|
||||
this->assign(this->context_->sink(), arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_level > 2)
|
||||
go_error_at((*pexpr)->location(),
|
||||
|
@ -1219,7 +1227,9 @@ Escape_analysis_assign::expression(Expression** pexpr)
|
|||
}
|
||||
break;
|
||||
|
||||
case Runtime::COPY:
|
||||
case Runtime::SLICECOPY:
|
||||
case Runtime::SLICESTRINGCOPY:
|
||||
case Runtime::TYPEDSLICECOPY:
|
||||
{
|
||||
// Lose track of the copied content.
|
||||
Node* copied = Node::make_node(call->args()->back());
|
||||
|
@ -1229,10 +1239,7 @@ Escape_analysis_assign::expression(Expression** pexpr)
|
|||
|
||||
case Runtime::MAKECHAN:
|
||||
case Runtime::MAKEMAP:
|
||||
case Runtime::MAKESLICE1:
|
||||
case Runtime::MAKESLICE2:
|
||||
case Runtime::MAKESLICE1BIG:
|
||||
case Runtime::MAKESLICE2BIG:
|
||||
case Runtime::MAKESLICE:
|
||||
case Runtime::SLICEBYTETOSTRING:
|
||||
case Runtime::SLICERUNETOSTRING:
|
||||
case Runtime::STRINGTOSLICEBYTE:
|
||||
|
@ -1829,7 +1836,7 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
|
|||
{
|
||||
switch (fe->runtime_code())
|
||||
{
|
||||
case Runtime::APPEND:
|
||||
case Runtime::GROWSLICE:
|
||||
{
|
||||
// Append returns the first argument.
|
||||
// The subsequent arguments are already leaked because
|
||||
|
@ -1841,10 +1848,7 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
|
|||
|
||||
case Runtime::MAKECHAN:
|
||||
case Runtime::MAKEMAP:
|
||||
case Runtime::MAKESLICE1:
|
||||
case Runtime::MAKESLICE2:
|
||||
case Runtime::MAKESLICE1BIG:
|
||||
case Runtime::MAKESLICE2BIG:
|
||||
case Runtime::MAKESLICE:
|
||||
// DST = make(...).
|
||||
case Runtime::SLICEBYTETOSTRING:
|
||||
// DST = string([]byte{...}).
|
||||
|
@ -2608,7 +2612,7 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
|
|||
{
|
||||
switch (func->runtime_code())
|
||||
{
|
||||
case Runtime::APPEND:
|
||||
case Runtime::GROWSLICE:
|
||||
{
|
||||
// Propagate escape information to appendee.
|
||||
Expression* appendee = call->args()->front();
|
||||
|
@ -2618,10 +2622,7 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
|
|||
|
||||
case Runtime::MAKECHAN:
|
||||
case Runtime::MAKEMAP:
|
||||
case Runtime::MAKESLICE1:
|
||||
case Runtime::MAKESLICE2:
|
||||
case Runtime::MAKESLICE1BIG:
|
||||
case Runtime::MAKESLICE2BIG:
|
||||
case Runtime::MAKESLICE:
|
||||
case Runtime::SLICEBYTETOSTRING:
|
||||
case Runtime::SLICERUNETOSTRING:
|
||||
case Runtime::STRINGTOSLICEBYTE:
|
||||
|
|
|
@ -6951,7 +6951,9 @@ class Builtin_call_expression : public Call_expression
|
|||
complex_type(Type*);
|
||||
|
||||
Expression*
|
||||
lower_make();
|
||||
lower_make(Statement_inserter*);
|
||||
|
||||
Expression* flatten_append(Gogo*, Named_object*, Statement_inserter*);
|
||||
|
||||
bool
|
||||
check_int_value(Expression*, bool is_length);
|
||||
|
@ -7052,7 +7054,7 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg)
|
|||
// specific expressions. We also convert to a constant if we can.
|
||||
|
||||
Expression*
|
||||
Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||
Builtin_call_expression::do_lower(Gogo*, Named_object* function,
|
||||
Statement_inserter* inserter, int)
|
||||
{
|
||||
if (this->is_error_expression())
|
||||
|
@ -7130,7 +7132,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
|||
break;
|
||||
|
||||
case BUILTIN_MAKE:
|
||||
return this->lower_make();
|
||||
return this->lower_make(inserter);
|
||||
|
||||
case BUILTIN_RECOVER:
|
||||
if (function != NULL)
|
||||
|
@ -7144,30 +7146,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
|||
}
|
||||
break;
|
||||
|
||||
case BUILTIN_APPEND:
|
||||
{
|
||||
// Lower the varargs.
|
||||
const Expression_list* args = this->args();
|
||||
if (args == NULL || args->empty())
|
||||
return this;
|
||||
Type* slice_type = args->front()->type();
|
||||
if (!slice_type->is_slice_type())
|
||||
{
|
||||
if (slice_type->is_nil_type())
|
||||
go_error_at(args->front()->location(), "use of untyped nil");
|
||||
else
|
||||
go_error_at(args->front()->location(),
|
||||
"argument 1 must be a slice");
|
||||
this->set_is_error();
|
||||
return this;
|
||||
}
|
||||
Type* element_type = slice_type->array_type()->element_type();
|
||||
this->lower_varargs(gogo, function, inserter,
|
||||
Type::make_array_type(element_type, NULL),
|
||||
2, SLICE_STORAGE_DOES_NOT_ESCAPE);
|
||||
}
|
||||
break;
|
||||
|
||||
case BUILTIN_DELETE:
|
||||
{
|
||||
// Lower to a runtime function call.
|
||||
|
@ -7233,7 +7211,7 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
|
|||
// append into temporary expressions.
|
||||
|
||||
Expression*
|
||||
Builtin_call_expression::do_flatten(Gogo*, Named_object*,
|
||||
Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
|
||||
Statement_inserter* inserter)
|
||||
{
|
||||
Location loc = this->location();
|
||||
|
@ -7244,6 +7222,8 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
|
|||
break;
|
||||
|
||||
case BUILTIN_APPEND:
|
||||
return this->flatten_append(gogo, function, inserter);
|
||||
|
||||
case BUILTIN_COPY:
|
||||
{
|
||||
Type* at = this->args()->front()->type();
|
||||
|
@ -7285,16 +7265,19 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
|
|||
|
||||
case BUILTIN_LEN:
|
||||
case BUILTIN_CAP:
|
||||
Expression_list::iterator pa = this->args()->begin();
|
||||
if (!(*pa)->is_variable()
|
||||
&& ((*pa)->type()->map_type() != NULL
|
||||
|| (*pa)->type()->channel_type() != NULL))
|
||||
{
|
||||
Temporary_statement* temp =
|
||||
Statement::make_temporary(NULL, *pa, loc);
|
||||
inserter->insert(temp);
|
||||
*pa = Expression::make_temporary_reference(temp, loc);
|
||||
}
|
||||
{
|
||||
Expression_list::iterator pa = this->args()->begin();
|
||||
if (!(*pa)->is_variable()
|
||||
&& ((*pa)->type()->map_type() != NULL
|
||||
|| (*pa)->type()->channel_type() != NULL))
|
||||
{
|
||||
Temporary_statement* temp =
|
||||
Statement::make_temporary(NULL, *pa, loc);
|
||||
inserter->insert(temp);
|
||||
*pa = Expression::make_temporary_reference(temp, loc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -7303,7 +7286,7 @@ Builtin_call_expression::do_flatten(Gogo*, Named_object*,
|
|||
// Lower a make expression.
|
||||
|
||||
Expression*
|
||||
Builtin_call_expression::lower_make()
|
||||
Builtin_call_expression::lower_make(Statement_inserter* inserter)
|
||||
{
|
||||
Location loc = this->location();
|
||||
|
||||
|
@ -7340,10 +7323,6 @@ Builtin_call_expression::lower_make()
|
|||
return Expression::make_error(this->location());
|
||||
}
|
||||
|
||||
bool have_big_args = false;
|
||||
Type* uintptr_type = Type::lookup_integer_type("uintptr");
|
||||
int uintptr_bits = uintptr_type->integer_type()->bits();
|
||||
|
||||
Type_context int_context(Type::lookup_integer_type("int"), false);
|
||||
|
||||
++parg;
|
||||
|
@ -7363,9 +7342,6 @@ Builtin_call_expression::lower_make()
|
|||
len_arg->determine_type(&int_context);
|
||||
if (!this->check_int_value(len_arg, true))
|
||||
return Expression::make_error(this->location());
|
||||
if (len_arg->type()->integer_type() != NULL
|
||||
&& len_arg->type()->integer_type()->bits() > uintptr_bits)
|
||||
have_big_args = true;
|
||||
++parg;
|
||||
}
|
||||
|
||||
|
@ -7391,9 +7367,6 @@ Builtin_call_expression::lower_make()
|
|||
return Expression::make_error(this->location());
|
||||
}
|
||||
|
||||
if (cap_arg->type()->integer_type() != NULL
|
||||
&& cap_arg->type()->integer_type()->bits() > uintptr_bits)
|
||||
have_big_args = true;
|
||||
++parg;
|
||||
}
|
||||
|
||||
|
@ -7404,34 +7377,236 @@ Builtin_call_expression::lower_make()
|
|||
}
|
||||
|
||||
Location type_loc = first_arg->location();
|
||||
Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
|
||||
|
||||
Expression* call;
|
||||
if (is_slice)
|
||||
{
|
||||
Type* et = type->array_type()->element_type();
|
||||
Expression* type_arg = Expression::make_type_descriptor(et, type_loc);
|
||||
if (cap_arg == NULL)
|
||||
call = Runtime::make_call((have_big_args
|
||||
? Runtime::MAKESLICE1BIG
|
||||
: Runtime::MAKESLICE1),
|
||||
loc, 2, type_arg, len_arg);
|
||||
else
|
||||
call = Runtime::make_call((have_big_args
|
||||
? Runtime::MAKESLICE2BIG
|
||||
: Runtime::MAKESLICE2),
|
||||
loc, 3, type_arg, len_arg, cap_arg);
|
||||
{
|
||||
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);
|
||||
}
|
||||
call = Runtime::make_call(Runtime::MAKESLICE, loc, 3, type_arg,
|
||||
len_arg, cap_arg);
|
||||
}
|
||||
else if (is_map)
|
||||
call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
|
||||
Expression::make_nil(loc),
|
||||
Expression::make_nil(loc));
|
||||
{
|
||||
Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
|
||||
call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg,
|
||||
Expression::make_nil(loc),
|
||||
Expression::make_nil(loc));
|
||||
}
|
||||
else if (is_chan)
|
||||
call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
|
||||
{
|
||||
Expression* type_arg = Expression::make_type_descriptor(type, type_loc);
|
||||
call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
|
||||
}
|
||||
else
|
||||
go_unreachable();
|
||||
|
||||
return Expression::make_unsafe_cast(type, call, loc);
|
||||
}
|
||||
|
||||
// Flatten a call to the predeclared append function. We do this in
|
||||
// the flatten phase, not the lowering phase, so that we run after
|
||||
// type checking and after order_evaluations.
|
||||
|
||||
Expression*
|
||||
Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
|
||||
Statement_inserter* inserter)
|
||||
{
|
||||
if (this->is_error_expression())
|
||||
return this;
|
||||
|
||||
Location loc = this->location();
|
||||
|
||||
const Expression_list* args = this->args();
|
||||
go_assert(args != NULL && !args->empty());
|
||||
|
||||
Type* slice_type = args->front()->type();
|
||||
go_assert(slice_type->is_slice_type());
|
||||
Type* element_type = slice_type->array_type()->element_type();
|
||||
|
||||
if (args->size() == 1)
|
||||
{
|
||||
// append(s) evaluates to s.
|
||||
return args->front();
|
||||
}
|
||||
|
||||
Type* int_type = Type::lookup_integer_type("int");
|
||||
Type* uint_type = Type::lookup_integer_type("uint");
|
||||
|
||||
// Implementing
|
||||
// append(s1, s2...)
|
||||
// or
|
||||
// append(s1, a1, a2, a3, ...)
|
||||
|
||||
// s1tmp := s1
|
||||
Temporary_statement* s1tmp = Statement::make_temporary(NULL, args->front(),
|
||||
loc);
|
||||
inserter->insert(s1tmp);
|
||||
|
||||
// l1tmp := len(s1tmp)
|
||||
Named_object* lenfn = gogo->lookup_global("len");
|
||||
Expression* lenref = Expression::make_func_reference(lenfn, NULL, loc);
|
||||
Expression_list* call_args = new Expression_list();
|
||||
call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
|
||||
Expression* len = Expression::make_call(lenref, call_args, false, loc);
|
||||
gogo->lower_expression(function, inserter, &len);
|
||||
gogo->flatten_expression(function, inserter, &len);
|
||||
Temporary_statement* l1tmp = Statement::make_temporary(int_type, len, loc);
|
||||
inserter->insert(l1tmp);
|
||||
|
||||
Temporary_statement* s2tmp = NULL;
|
||||
Temporary_statement* l2tmp = NULL;
|
||||
Expression_list* add = NULL;
|
||||
Expression* len2;
|
||||
if (this->is_varargs())
|
||||
{
|
||||
go_assert(args->size() == 2);
|
||||
|
||||
// s2tmp := s2
|
||||
s2tmp = Statement::make_temporary(NULL, args->back(), loc);
|
||||
inserter->insert(s2tmp);
|
||||
|
||||
// l2tmp := len(s2tmp)
|
||||
lenref = Expression::make_func_reference(lenfn, NULL, loc);
|
||||
call_args = new Expression_list();
|
||||
call_args->push_back(Expression::make_temporary_reference(s2tmp, loc));
|
||||
len = Expression::make_call(lenref, call_args, false, loc);
|
||||
gogo->lower_expression(function, inserter, &len);
|
||||
gogo->flatten_expression(function, inserter, &len);
|
||||
l2tmp = Statement::make_temporary(int_type, len, loc);
|
||||
inserter->insert(l2tmp);
|
||||
|
||||
// len2 = l2tmp
|
||||
len2 = Expression::make_temporary_reference(l2tmp, loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have to ensure that all the arguments are in variables
|
||||
// now, because otherwise if one of them is an index expression
|
||||
// into the current slice we could overwrite it before we fetch
|
||||
// it.
|
||||
add = new Expression_list();
|
||||
Expression_list::const_iterator pa = args->begin();
|
||||
for (++pa; pa != args->end(); ++pa)
|
||||
{
|
||||
if ((*pa)->is_variable())
|
||||
add->push_back(*pa);
|
||||
else
|
||||
{
|
||||
Temporary_statement* tmp = Statement::make_temporary(NULL, *pa,
|
||||
loc);
|
||||
inserter->insert(tmp);
|
||||
add->push_back(Expression::make_temporary_reference(tmp, loc));
|
||||
}
|
||||
}
|
||||
|
||||
// len2 = len(add)
|
||||
len2 = Expression::make_integer_ul(add->size(), int_type, loc);
|
||||
}
|
||||
|
||||
// ntmp := l1tmp + len2
|
||||
Expression* ref = Expression::make_temporary_reference(l1tmp, loc);
|
||||
Expression* sum = Expression::make_binary(OPERATOR_PLUS, ref, len2, loc);
|
||||
gogo->lower_expression(function, inserter, &sum);
|
||||
gogo->flatten_expression(function, inserter, &sum);
|
||||
Temporary_statement* ntmp = Statement::make_temporary(int_type, sum, loc);
|
||||
inserter->insert(ntmp);
|
||||
|
||||
// s1tmp = uint(ntmp) > uint(cap(s1tmp)) ?
|
||||
// growslice(type, s1tmp, ntmp) :
|
||||
// s1tmp[:ntmp]
|
||||
// Using uint here means that if the computation of ntmp overflowed,
|
||||
// we will call growslice which will panic.
|
||||
|
||||
Expression* left = Expression::make_temporary_reference(ntmp, loc);
|
||||
left = Expression::make_cast(uint_type, left, loc);
|
||||
|
||||
Named_object* capfn = gogo->lookup_global("cap");
|
||||
Expression* capref = Expression::make_func_reference(capfn, NULL, loc);
|
||||
call_args = new Expression_list();
|
||||
call_args->push_back(Expression::make_temporary_reference(s1tmp, loc));
|
||||
Expression* right = Expression::make_call(capref, call_args, false, loc);
|
||||
right = Expression::make_cast(uint_type, right, loc);
|
||||
|
||||
Expression* cond = Expression::make_binary(OPERATOR_GT, left, right, loc);
|
||||
|
||||
Expression* a1 = Expression::make_type_descriptor(element_type, loc);
|
||||
Expression* a2 = Expression::make_temporary_reference(s1tmp, loc);
|
||||
Expression* a3 = Expression::make_temporary_reference(ntmp, loc);
|
||||
Expression* call = Runtime::make_call(Runtime::GROWSLICE, loc, 3,
|
||||
a1, a2, a3);
|
||||
call = Expression::make_unsafe_cast(slice_type, call, loc);
|
||||
|
||||
ref = Expression::make_temporary_reference(s1tmp, loc);
|
||||
Expression* zero = Expression::make_integer_ul(0, int_type, loc);
|
||||
Expression* ref2 = Expression::make_temporary_reference(ntmp, loc);
|
||||
// FIXME: Mark this index as not requiring bounds checks.
|
||||
ref = Expression::make_index(ref, zero, ref2, NULL, loc);
|
||||
|
||||
Expression* rhs = Expression::make_conditional(cond, call, ref, loc);
|
||||
|
||||
gogo->lower_expression(function, inserter, &rhs);
|
||||
gogo->flatten_expression(function, inserter, &rhs);
|
||||
|
||||
Expression* lhs = Expression::make_temporary_reference(s1tmp, loc);
|
||||
Statement* assign = Statement::make_assignment(lhs, rhs, loc);
|
||||
inserter->insert(assign);
|
||||
|
||||
if (this->is_varargs())
|
||||
{
|
||||
// copy(s1tmp[l1tmp:], s2tmp)
|
||||
a1 = Expression::make_temporary_reference(s1tmp, loc);
|
||||
ref = Expression::make_temporary_reference(l1tmp, loc);
|
||||
Expression* nil = Expression::make_nil(loc);
|
||||
// FIXME: Mark this index as not requiring bounds checks.
|
||||
a1 = Expression::make_index(a1, ref, nil, NULL, loc);
|
||||
|
||||
a2 = Expression::make_temporary_reference(s2tmp, loc);
|
||||
|
||||
Named_object* copyfn = gogo->lookup_global("copy");
|
||||
Expression* copyref = Expression::make_func_reference(copyfn, NULL, loc);
|
||||
call_args = new Expression_list();
|
||||
call_args->push_back(a1);
|
||||
call_args->push_back(a2);
|
||||
call = Expression::make_call(copyref, call_args, false, loc);
|
||||
gogo->lower_expression(function, inserter, &call);
|
||||
gogo->flatten_expression(function, inserter, &call);
|
||||
inserter->insert(Statement::make_statement(call, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each argument:
|
||||
// s1tmp[l1tmp+i] = a
|
||||
unsigned long i = 0;
|
||||
for (Expression_list::const_iterator pa = add->begin();
|
||||
pa != add->end();
|
||||
++pa, ++i)
|
||||
{
|
||||
ref = Expression::make_temporary_reference(s1tmp, loc);
|
||||
ref2 = Expression::make_temporary_reference(l1tmp, loc);
|
||||
Expression* off = Expression::make_integer_ul(i, int_type, loc);
|
||||
ref2 = Expression::make_binary(OPERATOR_PLUS, ref2, off, loc);
|
||||
// FIXME: Mark this index as not requiring bounds checks.
|
||||
lhs = Expression::make_index(ref, ref2, NULL, NULL, loc);
|
||||
gogo->lower_expression(function, inserter, &lhs);
|
||||
gogo->flatten_expression(function, inserter, &lhs);
|
||||
assign = Statement::make_assignment(lhs, *pa, loc);
|
||||
inserter->insert(assign);
|
||||
}
|
||||
}
|
||||
|
||||
return Expression::make_temporary_reference(s1tmp, loc);
|
||||
}
|
||||
|
||||
// Return whether an expression has an integer value. Report an error
|
||||
// if not. This is used when handling calls to the predeclared make
|
||||
// function.
|
||||
|
@ -8011,6 +8186,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
|
|||
|
||||
bool is_print;
|
||||
Type* arg_type = NULL;
|
||||
Type* trailing_arg_types = NULL;
|
||||
switch (this->code_)
|
||||
{
|
||||
case BUILTIN_PRINT:
|
||||
|
@ -8047,6 +8223,16 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
|
|||
}
|
||||
break;
|
||||
|
||||
case BUILTIN_APPEND:
|
||||
if (!this->is_varargs()
|
||||
&& args != NULL
|
||||
&& !args->empty()
|
||||
&& args->front()->type()->is_slice_type())
|
||||
trailing_arg_types =
|
||||
args->front()->type()->array_type()->element_type();
|
||||
is_print = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
is_print = false;
|
||||
break;
|
||||
|
@ -8103,6 +8289,12 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
|
|||
}
|
||||
|
||||
(*pa)->determine_type(&subcontext);
|
||||
|
||||
if (trailing_arg_types != NULL)
|
||||
{
|
||||
arg_type = trailing_arg_types;
|
||||
trailing_arg_types = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8309,54 +8501,102 @@ Builtin_call_expression::do_check_types(Gogo*)
|
|||
case BUILTIN_APPEND:
|
||||
{
|
||||
const Expression_list* args = this->args();
|
||||
if (args == NULL || args->size() < 2)
|
||||
if (args == NULL || args->empty())
|
||||
{
|
||||
this->report_error(_("not enough arguments"));
|
||||
break;
|
||||
}
|
||||
if (args->size() > 2)
|
||||
{
|
||||
this->report_error(_("too many arguments"));
|
||||
break;
|
||||
}
|
||||
if (args->front()->type()->is_error()
|
||||
|| args->back()->type()->is_error())
|
||||
|
||||
Type* slice_type = args->front()->type();
|
||||
if (!slice_type->is_slice_type())
|
||||
{
|
||||
if (slice_type->is_error_type())
|
||||
break;
|
||||
if (slice_type->is_nil_type())
|
||||
go_error_at(args->front()->location(), "use of untyped nil");
|
||||
else
|
||||
go_error_at(args->front()->location(),
|
||||
"argument 1 must be a slice");
|
||||
this->set_is_error();
|
||||
break;
|
||||
}
|
||||
|
||||
Array_type* at = args->front()->type()->array_type();
|
||||
Type* e = at->element_type();
|
||||
|
||||
// The language permits appending a string to a []byte, as a
|
||||
// special case.
|
||||
if (args->back()->type()->is_string_type())
|
||||
Type* element_type = slice_type->array_type()->element_type();
|
||||
if (this->is_varargs())
|
||||
{
|
||||
if (e->integer_type() != NULL && e->integer_type()->is_byte())
|
||||
break;
|
||||
}
|
||||
if (!args->back()->type()->is_slice_type()
|
||||
&& !args->back()->type()->is_string_type())
|
||||
{
|
||||
go_error_at(args->back()->location(),
|
||||
"invalid use of %<...%> with non-slice/non-string");
|
||||
this->set_is_error();
|
||||
break;
|
||||
}
|
||||
|
||||
// The language says that the second argument must be
|
||||
// assignable to a slice of the element type of the first
|
||||
// argument. We already know the first argument is a slice
|
||||
// type.
|
||||
Type* arg2_type = Type::make_array_type(e, NULL);
|
||||
std::string reason;
|
||||
if (!Type::are_assignable(arg2_type, args->back()->type(), &reason))
|
||||
{
|
||||
if (reason.empty())
|
||||
this->report_error(_("argument 2 has invalid type"));
|
||||
if (args->size() < 2)
|
||||
{
|
||||
this->report_error(_("not enough arguments"));
|
||||
break;
|
||||
}
|
||||
if (args->size() > 2)
|
||||
{
|
||||
this->report_error(_("too many arguments"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (args->back()->type()->is_string_type()
|
||||
&& element_type->integer_type() != NULL
|
||||
&& element_type->integer_type()->is_byte())
|
||||
{
|
||||
// Permit append(s1, s2...) when s1 is a slice of
|
||||
// bytes and s2 is a string type.
|
||||
}
|
||||
else
|
||||
{
|
||||
go_error_at(this->location(),
|
||||
"argument 2 has invalid type (%s)",
|
||||
reason.c_str());
|
||||
this->set_is_error();
|
||||
// We have to test for assignment compatibility to a
|
||||
// slice of the element type, which is not necessarily
|
||||
// the same as the type of the first argument: the
|
||||
// first argument might have a named type.
|
||||
Type* check_type = Type::make_array_type(element_type, NULL);
|
||||
std::string reason;
|
||||
if (!Type::are_assignable(check_type, args->back()->type(),
|
||||
&reason))
|
||||
{
|
||||
if (reason.empty())
|
||||
go_error_at(args->back()->location(),
|
||||
"argument 2 has invalid type");
|
||||
else
|
||||
go_error_at(args->back()->location(),
|
||||
"argument 2 has invalid type (%s)",
|
||||
reason.c_str());
|
||||
this->set_is_error();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression_list::const_iterator pa = args->begin();
|
||||
int i = 2;
|
||||
for (++pa; pa != args->end(); ++pa, ++i)
|
||||
{
|
||||
std::string reason;
|
||||
if (!Type::are_assignable(element_type, (*pa)->type(),
|
||||
&reason))
|
||||
{
|
||||
if (reason.empty())
|
||||
go_error_at((*pa)->location(),
|
||||
"argument %d has incompatible type", i);
|
||||
else
|
||||
go_error_at((*pa)->location(),
|
||||
"argument %d has incompatible type (%s)",
|
||||
i, reason.c_str());
|
||||
this->set_is_error();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case BUILTIN_REAL:
|
||||
case BUILTIN_IMAG:
|
||||
|
@ -8719,97 +8959,39 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
|
|||
Type* arg1_type = arg1->type();
|
||||
Array_type* at = arg1_type->array_type();
|
||||
go_assert(arg1->is_variable());
|
||||
Expression* arg1_val = at->get_value_pointer(gogo, arg1);
|
||||
Expression* arg1_len = at->get_length(gogo, arg1);
|
||||
|
||||
Expression* call;
|
||||
|
||||
Type* arg2_type = arg2->type();
|
||||
go_assert(arg2->is_variable());
|
||||
Expression* arg2_val;
|
||||
Expression* arg2_len;
|
||||
if (arg2_type->is_slice_type())
|
||||
{
|
||||
at = arg2_type->array_type();
|
||||
arg2_val = at->get_value_pointer(gogo, arg2);
|
||||
arg2_len = at->get_length(gogo, arg2);
|
||||
}
|
||||
if (arg2_type->is_string_type())
|
||||
call = Runtime::make_call(Runtime::SLICESTRINGCOPY, location,
|
||||
2, arg1, arg2);
|
||||
else
|
||||
{
|
||||
go_assert(arg2->is_variable());
|
||||
arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
|
||||
location);
|
||||
arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
|
||||
location);
|
||||
Type* et = at->element_type();
|
||||
if (et->has_pointer())
|
||||
{
|
||||
Expression* td = Expression::make_type_descriptor(et,
|
||||
location);
|
||||
call = Runtime::make_call(Runtime::TYPEDSLICECOPY, location,
|
||||
3, td, arg1, arg2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression* sz = Expression::make_type_info(et,
|
||||
TYPE_INFO_SIZE);
|
||||
call = Runtime::make_call(Runtime::SLICECOPY, location, 3,
|
||||
arg1, arg2, sz);
|
||||
}
|
||||
}
|
||||
Expression* cond =
|
||||
Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location);
|
||||
Expression* length =
|
||||
Expression::make_conditional(cond, arg1_len, arg2_len, location);
|
||||
|
||||
Type* element_type = at->element_type();
|
||||
int64_t element_size;
|
||||
bool ok = element_type->backend_type_size(gogo, &element_size);
|
||||
if (!ok)
|
||||
{
|
||||
go_assert(saw_errors());
|
||||
return gogo->backend()->error_expression();
|
||||
}
|
||||
|
||||
Expression* size_expr = Expression::make_integer_int64(element_size,
|
||||
length->type(),
|
||||
location);
|
||||
Expression* bytecount =
|
||||
Expression::make_binary(OPERATOR_MULT, size_expr, length, location);
|
||||
Expression* copy = Runtime::make_call(Runtime::COPY, location, 3,
|
||||
arg1_val, arg2_val, bytecount);
|
||||
|
||||
Expression* compound = Expression::make_compound(copy, length, location);
|
||||
return compound->get_backend(context);
|
||||
return call->get_backend(context);
|
||||
}
|
||||
|
||||
case BUILTIN_APPEND:
|
||||
{
|
||||
const Expression_list* args = this->args();
|
||||
go_assert(args != NULL && args->size() == 2);
|
||||
Expression* arg1 = args->front();
|
||||
Expression* arg2 = args->back();
|
||||
|
||||
Array_type* at = arg1->type()->array_type();
|
||||
Type* element_type = at->element_type()->forwarded();
|
||||
|
||||
go_assert(arg2->is_variable());
|
||||
Expression* arg2_val;
|
||||
Expression* arg2_len;
|
||||
int64_t size;
|
||||
if (arg2->type()->is_string_type()
|
||||
&& element_type->integer_type() != NULL
|
||||
&& element_type->integer_type()->is_byte())
|
||||
{
|
||||
arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
|
||||
location);
|
||||
arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
|
||||
location);
|
||||
size = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
arg2_val = at->get_value_pointer(gogo, arg2);
|
||||
arg2_len = at->get_length(gogo, arg2);
|
||||
bool ok = element_type->backend_type_size(gogo, &size);
|
||||
if (!ok)
|
||||
{
|
||||
go_assert(saw_errors());
|
||||
return gogo->backend()->error_expression();
|
||||
}
|
||||
}
|
||||
Expression* element_size =
|
||||
Expression::make_integer_int64(size, NULL, location);
|
||||
|
||||
Expression* append = Runtime::make_call(Runtime::APPEND, location, 4,
|
||||
arg1, arg2_val, arg2_len,
|
||||
element_size);
|
||||
append = Expression::make_unsafe_cast(arg1->type(), append, location);
|
||||
return append->get_backend(context);
|
||||
}
|
||||
// Handled in Builtin_call_expression::flatten_append.
|
||||
go_unreachable();
|
||||
|
||||
case BUILTIN_REAL:
|
||||
case BUILTIN_IMAG:
|
||||
|
|
|
@ -425,9 +425,9 @@ Runtime::name_to_code(const std::string& name)
|
|||
else if (name == "close")
|
||||
code = Runtime::CLOSE;
|
||||
else if (name == "copy")
|
||||
code = Runtime::COPY;
|
||||
code = Runtime::SLICECOPY;
|
||||
else if (name == "append")
|
||||
code = Runtime::APPEND;
|
||||
code = Runtime::GROWSLICE;
|
||||
else if (name == "delete")
|
||||
code = Runtime::MAPDELETE;
|
||||
else
|
||||
|
|
|
@ -87,12 +87,7 @@ DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div",
|
|||
P2(COMPLEX128, COMPLEX128), R1(COMPLEX128))
|
||||
|
||||
// Make a slice.
|
||||
DEF_GO_RUNTIME(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE))
|
||||
DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR),
|
||||
R1(SLICE))
|
||||
DEF_GO_RUNTIME(MAKESLICE1BIG, "__go_make_slice1_big", P2(TYPE, UINT64),
|
||||
R1(SLICE))
|
||||
DEF_GO_RUNTIME(MAKESLICE2BIG, "__go_make_slice2_big", P3(TYPE, UINT64, UINT64),
|
||||
DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT64, INT64),
|
||||
R1(SLICE))
|
||||
|
||||
|
||||
|
@ -211,11 +206,20 @@ DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0())
|
|||
|
||||
|
||||
// Copy.
|
||||
DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0())
|
||||
DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy", P3(SLICE, SLICE, UINTPTR),
|
||||
R1(INT))
|
||||
|
||||
// Append.
|
||||
DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR),
|
||||
R1(SLICE))
|
||||
// Copy from string.
|
||||
DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy", P2(SLICE, STRING),
|
||||
R1(INT))
|
||||
|
||||
// Copy of value containing pointers.
|
||||
DEF_GO_RUNTIME(TYPEDSLICECOPY, "runtime.typedslicecopy",
|
||||
P3(TYPE, SLICE, SLICE), R1(INT))
|
||||
|
||||
|
||||
// Grow a slice for append.
|
||||
DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice", P3(TYPE, SLICE, INT), R1(SLICE))
|
||||
|
||||
|
||||
// Register roots (global variables) for the garbage collector.
|
||||
|
|
|
@ -428,7 +428,6 @@ endif
|
|||
endif
|
||||
|
||||
runtime_files = \
|
||||
runtime/go-append.c \
|
||||
runtime/go-assert.c \
|
||||
runtime/go-breakpoint.c \
|
||||
runtime/go-caller.c \
|
||||
|
@ -436,12 +435,10 @@ runtime_files = \
|
|||
runtime/go-cdiv.c \
|
||||
runtime/go-cgo.c \
|
||||
runtime/go-construct-map.c \
|
||||
runtime/go-copy.c \
|
||||
runtime/go-defer.c \
|
||||
runtime/go-deferred-recover.c \
|
||||
runtime/go-ffi.c \
|
||||
runtime/go-fieldtrack.c \
|
||||
runtime/go-make-slice.c \
|
||||
runtime/go-matherr.c \
|
||||
runtime/go-memclr.c \
|
||||
runtime/go-memcmp.c \
|
||||
|
|
|
@ -237,23 +237,22 @@ libgo_llgo_la_DEPENDENCIES = $(am__DEPENDENCIES_4)
|
|||
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@am__objects_4 = \
|
||||
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@ getncpu-bsd.lo
|
||||
@LIBGO_IS_LINUX_TRUE@am__objects_4 = getncpu-linux.lo
|
||||
am__objects_5 = go-append.lo go-assert.lo go-breakpoint.lo \
|
||||
go-caller.lo go-callers.lo go-cdiv.lo go-cgo.lo \
|
||||
go-construct-map.lo go-copy.lo go-defer.lo \
|
||||
go-deferred-recover.lo go-ffi.lo go-fieldtrack.lo \
|
||||
go-make-slice.lo go-matherr.lo go-memclr.lo go-memcmp.lo \
|
||||
go-memequal.lo go-memmove.lo go-nanotime.lo go-now.lo \
|
||||
go-new.lo go-nosys.lo go-panic.lo go-recover.lo \
|
||||
go-reflect-call.lo go-runtime-error.lo go-setenv.lo \
|
||||
go-signal.lo go-strslice.lo go-type-complex.lo \
|
||||
go-type-float.lo go-type-identity.lo go-type-string.lo \
|
||||
go-typedesc-equal.lo go-unsafe-new.lo go-unsafe-newarray.lo \
|
||||
go-unsafe-pointer.lo go-unsetenv.lo go-unwind.lo go-varargs.lo \
|
||||
env_posix.lo heapdump.lo mcache.lo mcentral.lo \
|
||||
$(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo msize.lo \
|
||||
panic.lo parfor.lo print.lo proc.lo runtime.lo signal_unix.lo \
|
||||
thread.lo $(am__objects_2) yield.lo $(am__objects_3) malloc.lo \
|
||||
runtime1.lo sigqueue.lo $(am__objects_4)
|
||||
am__objects_5 = go-assert.lo go-breakpoint.lo go-caller.lo \
|
||||
go-callers.lo go-cdiv.lo go-cgo.lo go-construct-map.lo \
|
||||
go-defer.lo go-deferred-recover.lo go-ffi.lo go-fieldtrack.lo \
|
||||
go-matherr.lo go-memclr.lo go-memcmp.lo go-memequal.lo \
|
||||
go-memmove.lo go-nanotime.lo go-now.lo go-new.lo go-nosys.lo \
|
||||
go-panic.lo go-recover.lo go-reflect-call.lo \
|
||||
go-runtime-error.lo go-setenv.lo go-signal.lo go-strslice.lo \
|
||||
go-type-complex.lo go-type-float.lo go-type-identity.lo \
|
||||
go-type-string.lo go-typedesc-equal.lo go-unsafe-new.lo \
|
||||
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unsetenv.lo \
|
||||
go-unwind.lo go-varargs.lo env_posix.lo heapdump.lo mcache.lo \
|
||||
mcentral.lo $(am__objects_1) mfixalloc.lo mgc0.lo mheap.lo \
|
||||
msize.lo panic.lo parfor.lo print.lo proc.lo runtime.lo \
|
||||
signal_unix.lo thread.lo $(am__objects_2) yield.lo \
|
||||
$(am__objects_3) malloc.lo runtime1.lo sigqueue.lo \
|
||||
$(am__objects_4)
|
||||
am_libgo_llgo_la_OBJECTS = $(am__objects_5)
|
||||
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
|
||||
libgo_llgo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
|
@ -824,7 +823,6 @@ toolexeclibgounicode_DATA = \
|
|||
@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_LINUX_FALSE@runtime_getncpu_file = runtime/getncpu-bsd.c
|
||||
@LIBGO_IS_LINUX_TRUE@runtime_getncpu_file = runtime/getncpu-linux.c
|
||||
runtime_files = \
|
||||
runtime/go-append.c \
|
||||
runtime/go-assert.c \
|
||||
runtime/go-breakpoint.c \
|
||||
runtime/go-caller.c \
|
||||
|
@ -832,12 +830,10 @@ runtime_files = \
|
|||
runtime/go-cdiv.c \
|
||||
runtime/go-cgo.c \
|
||||
runtime/go-construct-map.c \
|
||||
runtime/go-copy.c \
|
||||
runtime/go-defer.c \
|
||||
runtime/go-deferred-recover.c \
|
||||
runtime/go-ffi.c \
|
||||
runtime/go-fieldtrack.c \
|
||||
runtime/go-make-slice.c \
|
||||
runtime/go-matherr.c \
|
||||
runtime/go-memclr.c \
|
||||
runtime/go-memcmp.c \
|
||||
|
@ -1519,7 +1515,6 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-linux.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-none.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getncpu-solaris.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-append.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-assert.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-breakpoint.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-caller.Plo@am__quote@
|
||||
|
@ -1527,12 +1522,10 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cdiv.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-cgo.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-construct-map.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-copy.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-defer.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-ffi.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-make-slice.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-matherr.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memclr.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-memcmp.Plo@am__quote@
|
||||
|
@ -1650,13 +1643,6 @@ libgolibbegin_a-go-libmain.obj: runtime/go-libmain.c
|
|||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgolibbegin_a_CFLAGS) $(CFLAGS) -c -o libgolibbegin_a-go-libmain.obj `if test -f 'runtime/go-libmain.c'; then $(CYGPATH_W) 'runtime/go-libmain.c'; else $(CYGPATH_W) '$(srcdir)/runtime/go-libmain.c'; fi`
|
||||
|
||||
go-append.lo: runtime/go-append.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-append.lo -MD -MP -MF $(DEPDIR)/go-append.Tpo -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-append.Tpo $(DEPDIR)/go-append.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-append.c' object='go-append.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-append.lo `test -f 'runtime/go-append.c' || echo '$(srcdir)/'`runtime/go-append.c
|
||||
|
||||
go-assert.lo: runtime/go-assert.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-assert.lo -MD -MP -MF $(DEPDIR)/go-assert.Tpo -c -o go-assert.lo `test -f 'runtime/go-assert.c' || echo '$(srcdir)/'`runtime/go-assert.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-assert.Tpo $(DEPDIR)/go-assert.Plo
|
||||
|
@ -1706,13 +1692,6 @@ go-construct-map.lo: runtime/go-construct-map.c
|
|||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-construct-map.lo `test -f 'runtime/go-construct-map.c' || echo '$(srcdir)/'`runtime/go-construct-map.c
|
||||
|
||||
go-copy.lo: runtime/go-copy.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-copy.lo -MD -MP -MF $(DEPDIR)/go-copy.Tpo -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-copy.Tpo $(DEPDIR)/go-copy.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-copy.c' object='go-copy.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-copy.lo `test -f 'runtime/go-copy.c' || echo '$(srcdir)/'`runtime/go-copy.c
|
||||
|
||||
go-defer.lo: runtime/go-defer.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-defer.lo -MD -MP -MF $(DEPDIR)/go-defer.Tpo -c -o go-defer.lo `test -f 'runtime/go-defer.c' || echo '$(srcdir)/'`runtime/go-defer.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-defer.Tpo $(DEPDIR)/go-defer.Plo
|
||||
|
@ -1741,13 +1720,6 @@ go-fieldtrack.lo: runtime/go-fieldtrack.c
|
|||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
|
||||
|
||||
go-make-slice.lo: runtime/go-make-slice.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-make-slice.lo -MD -MP -MF $(DEPDIR)/go-make-slice.Tpo -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-make-slice.Tpo $(DEPDIR)/go-make-slice.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-make-slice.c' object='go-make-slice.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-make-slice.lo `test -f 'runtime/go-make-slice.c' || echo '$(srcdir)/'`runtime/go-make-slice.c
|
||||
|
||||
go-matherr.lo: runtime/go-matherr.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-matherr.lo -MD -MP -MF $(DEPDIR)/go-matherr.Tpo -c -o go-matherr.lo `test -f 'runtime/go-matherr.c' || echo '$(srcdir)/'`runtime/go-matherr.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-matherr.Tpo $(DEPDIR)/go-matherr.Plo
|
||||
|
|
212
libgo/go/runtime/slice.go
Normal file
212
libgo/go/runtime/slice.go
Normal file
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// For gccgo, use go:linkname to rename compiler-called functions to
|
||||
// themselves, so that the compiler will export them.
|
||||
//
|
||||
//go:linkname makeslice runtime.makeslice
|
||||
//go:linkname growslice runtime.growslice
|
||||
//go:linkname slicecopy runtime.slicecopy
|
||||
//go:linkname slicestringcopy runtime.slicestringcopy
|
||||
|
||||
type slice struct {
|
||||
array unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
}
|
||||
|
||||
// maxElems is a lookup table containing the maximum capacity for a slice.
|
||||
// The index is the size of the slice element.
|
||||
var maxElems = [...]uintptr{
|
||||
^uintptr(0),
|
||||
_MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4,
|
||||
_MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8,
|
||||
_MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12,
|
||||
_MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16,
|
||||
_MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20,
|
||||
_MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24,
|
||||
_MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28,
|
||||
_MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32,
|
||||
}
|
||||
|
||||
// maxSliceCap returns the maximum capacity for a slice.
|
||||
func maxSliceCap(elemsize uintptr) uintptr {
|
||||
if elemsize < uintptr(len(maxElems)) {
|
||||
return maxElems[elemsize]
|
||||
}
|
||||
return _MaxMem / elemsize
|
||||
}
|
||||
|
||||
// TODO: take uintptrs instead of int64s?
|
||||
func makeslice(et *_type, len64, cap64 int64) slice {
|
||||
// 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,
|
||||
// but since the cap is only being supplied implicitly, saying len is clearer.
|
||||
// See issue 4085.
|
||||
maxElements := maxSliceCap(et.size)
|
||||
len := int(len64)
|
||||
if len64 < 0 || int64(len) != len64 || uintptr(len) > maxElements {
|
||||
panic(errorString("makeslice: len out of range"))
|
||||
}
|
||||
|
||||
cap := int(cap64)
|
||||
if cap < len || int64(cap) != cap64 || uintptr(cap) > maxElements {
|
||||
panic(errorString("makeslice: cap out of range"))
|
||||
}
|
||||
|
||||
// gccgo's current garbage collector requires using newarray,
|
||||
// not mallocgc here. This can change back to mallocgc when
|
||||
// we port the garbage collector.
|
||||
p := newarray(et, cap)
|
||||
return slice{p, len, cap}
|
||||
}
|
||||
|
||||
// growslice handles slice growth during append.
|
||||
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
|
||||
// and it returns a new slice with at least that capacity, with the old data
|
||||
// copied into it.
|
||||
// The new slice's length is set to the requested capacity.
|
||||
func growslice(et *_type, old slice, cap int) slice {
|
||||
if raceenabled {
|
||||
callerpc := getcallerpc(unsafe.Pointer(&et))
|
||||
racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
|
||||
}
|
||||
if msanenabled {
|
||||
msanread(old.array, uintptr(old.len*int(et.size)))
|
||||
}
|
||||
|
||||
if et.size == 0 {
|
||||
if cap < old.cap {
|
||||
panic(errorString("growslice: cap out of range"))
|
||||
}
|
||||
// append should not create a slice with nil pointer but non-zero len.
|
||||
// We assume that append doesn't need to preserve old.array in this case.
|
||||
return slice{unsafe.Pointer(&zerobase), cap, cap}
|
||||
}
|
||||
|
||||
newcap := old.cap
|
||||
doublecap := newcap + newcap
|
||||
if cap > doublecap {
|
||||
newcap = cap
|
||||
} else {
|
||||
if old.len < 1024 {
|
||||
newcap = doublecap
|
||||
} else {
|
||||
for newcap < cap {
|
||||
newcap += newcap / 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lenmem, capmem uintptr
|
||||
const ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||
switch et.size {
|
||||
case 1:
|
||||
lenmem = uintptr(old.len)
|
||||
capmem = roundupsize(uintptr(newcap))
|
||||
newcap = int(capmem)
|
||||
case ptrSize:
|
||||
lenmem = uintptr(old.len) * ptrSize
|
||||
capmem = roundupsize(uintptr(newcap) * ptrSize)
|
||||
newcap = int(capmem / ptrSize)
|
||||
default:
|
||||
lenmem = uintptr(old.len) * et.size
|
||||
capmem = roundupsize(uintptr(newcap) * et.size)
|
||||
newcap = int(capmem / et.size)
|
||||
}
|
||||
|
||||
if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) {
|
||||
panic(errorString("growslice: cap out of range"))
|
||||
}
|
||||
|
||||
var p unsafe.Pointer
|
||||
if et.kind&kindNoPointers != 0 {
|
||||
// gccgo's current GC requires newarray, not mallocgc.
|
||||
p = newarray(et, newcap)
|
||||
memmove(p, old.array, lenmem)
|
||||
// The call to memclr is not needed for gccgo since
|
||||
// the newarray function will zero the memory.
|
||||
// Calling memclr is also wrong since we allocated
|
||||
// newcap*et.size bytes, which is not the same as capmem.
|
||||
// memclr(add(p, lenmem), capmem-lenmem)
|
||||
} else {
|
||||
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
|
||||
// gccgo's current GC requires newarray, not mallocgc.
|
||||
p = newarray(et, newcap)
|
||||
if !writeBarrier.enabled {
|
||||
memmove(p, old.array, lenmem)
|
||||
} else {
|
||||
for i := uintptr(0); i < lenmem; i += et.size {
|
||||
typedmemmove(et, add(p, i), add(old.array, i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return slice{p, cap, newcap}
|
||||
}
|
||||
|
||||
func slicecopy(to, fm slice, width uintptr) int {
|
||||
if fm.len == 0 || to.len == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
n := fm.len
|
||||
if to.len < n {
|
||||
n = to.len
|
||||
}
|
||||
|
||||
if width == 0 {
|
||||
return n
|
||||
}
|
||||
|
||||
if raceenabled {
|
||||
callerpc := getcallerpc(unsafe.Pointer(&to))
|
||||
pc := funcPC(slicecopy)
|
||||
racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
|
||||
racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
|
||||
}
|
||||
if msanenabled {
|
||||
msanwrite(to.array, uintptr(n*int(width)))
|
||||
msanread(fm.array, uintptr(n*int(width)))
|
||||
}
|
||||
|
||||
size := uintptr(n) * width
|
||||
if size == 1 { // common case worth about 2x to do here
|
||||
// TODO: is this still worth it with new memmove impl?
|
||||
*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
|
||||
} else {
|
||||
memmove(to.array, fm.array, size)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func slicestringcopy(to []byte, fm string) int {
|
||||
if len(fm) == 0 || len(to) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
n := len(fm)
|
||||
if len(to) < n {
|
||||
n = len(to)
|
||||
}
|
||||
|
||||
if raceenabled {
|
||||
callerpc := getcallerpc(unsafe.Pointer(&to))
|
||||
pc := funcPC(slicestringcopy)
|
||||
racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
|
||||
}
|
||||
if msanenabled {
|
||||
msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
|
||||
}
|
||||
|
||||
memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
|
||||
return n
|
||||
}
|
|
@ -253,11 +253,18 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
|
|||
memmove(dst, src, typ.size)
|
||||
}
|
||||
|
||||
// Here for gccgo unless and until we port slice.go.
|
||||
type slice struct {
|
||||
array unsafe.Pointer
|
||||
len int
|
||||
cap int
|
||||
// Temporary for gccgo until we port mbarrier.go.
|
||||
//go:linkname typedslicecopy runtime.typedslicecopy
|
||||
func typedslicecopy(typ *_type, dst, src slice) int {
|
||||
n := dst.len
|
||||
if n > src.len {
|
||||
n = src.len
|
||||
}
|
||||
if n == 0 {
|
||||
return 0
|
||||
}
|
||||
memmove(dst.array, src.array, uintptr(n)*typ.size)
|
||||
return n
|
||||
}
|
||||
|
||||
// Here for gccgo until we port malloc.go.
|
||||
|
@ -474,3 +481,11 @@ func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
|
|||
func writebarrierptr(dst *uintptr, src uintptr) {
|
||||
*dst = src
|
||||
}
|
||||
|
||||
// Temporary for gccgo until we port malloc.go
|
||||
var zerobase uintptr
|
||||
|
||||
//go:linkname getZerobase runtime.getZerobase
|
||||
func getZerobase() *uintptr {
|
||||
return &zerobase
|
||||
}
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
/* go-append.c -- the go builtin append function.
|
||||
|
||||
Copyright 2010 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file. */
|
||||
|
||||
#include "runtime.h"
|
||||
#include "go-panic.h"
|
||||
#include "go-type.h"
|
||||
#include "array.h"
|
||||
#include "arch.h"
|
||||
#include "malloc.h"
|
||||
|
||||
/* We should be OK if we don't split the stack here, since the only
|
||||
libc functions we call are memcpy and memmove. If we don't do
|
||||
this, we will always split the stack, because of memcpy and
|
||||
memmove. */
|
||||
extern struct __go_open_array
|
||||
__go_append (struct __go_open_array, void *, uintptr_t, uintptr_t)
|
||||
__attribute__ ((no_split_stack));
|
||||
|
||||
struct __go_open_array
|
||||
__go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
|
||||
uintptr_t element_size)
|
||||
{
|
||||
uintptr_t ucount;
|
||||
intgo count;
|
||||
|
||||
if (bvalues == NULL || bcount == 0)
|
||||
return a;
|
||||
|
||||
ucount = (uintptr_t) a.__count + bcount;
|
||||
count = (intgo) ucount;
|
||||
if ((uintptr_t) count != ucount || count <= a.__count)
|
||||
runtime_panicstring ("append: slice overflow");
|
||||
|
||||
if (count > a.__capacity)
|
||||
{
|
||||
intgo m;
|
||||
uintptr capmem;
|
||||
void *n;
|
||||
|
||||
m = a.__capacity;
|
||||
if (m + m < count)
|
||||
m = count;
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
if (a.__count < 1024)
|
||||
m += m;
|
||||
else
|
||||
m += m / 4;
|
||||
}
|
||||
while (m < count);
|
||||
}
|
||||
|
||||
if (element_size > 0 && (uintptr) m > MaxMem / element_size)
|
||||
runtime_panicstring ("growslice: cap out of range");
|
||||
|
||||
capmem = runtime_roundupsize (m * element_size);
|
||||
|
||||
n = __go_alloc (capmem);
|
||||
__builtin_memcpy (n, a.__values, a.__count * element_size);
|
||||
|
||||
a.__values = n;
|
||||
a.__capacity = m;
|
||||
}
|
||||
|
||||
__builtin_memmove ((char *) a.__values + a.__count * element_size,
|
||||
bvalues, bcount * element_size);
|
||||
a.__count = count;
|
||||
return a;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/* go-append.c -- the go builtin copy function.
|
||||
|
||||
Copyright 2010 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* We should be OK if we don't split the stack here, since we are just
|
||||
calling memmove which shouldn't need much stack. If we don't do
|
||||
this we will always split the stack, because of memmove. */
|
||||
|
||||
extern void
|
||||
__go_copy (void *, void *, uintptr_t)
|
||||
__attribute__ ((no_split_stack));
|
||||
|
||||
void
|
||||
__go_copy (void *a, void *b, uintptr_t len)
|
||||
{
|
||||
__builtin_memmove (a, b, len);
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/* go-make-slice.c -- make a slice.
|
||||
|
||||
Copyright 2011 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "runtime.h"
|
||||
#include "go-alloc.h"
|
||||
#include "go-assert.h"
|
||||
#include "go-panic.h"
|
||||
#include "go-type.h"
|
||||
#include "array.h"
|
||||
#include "arch.h"
|
||||
#include "malloc.h"
|
||||
|
||||
/* Dummy word to use as base pointer for make([]T, 0).
|
||||
Since you cannot take the address of such a slice,
|
||||
you can't tell that they all have the same base pointer. */
|
||||
uintptr runtime_zerobase;
|
||||
|
||||
struct __go_open_array
|
||||
__go_make_slice2 (const struct __go_type_descriptor *td, uintptr_t len,
|
||||
uintptr_t cap)
|
||||
{
|
||||
const struct __go_slice_type* std;
|
||||
intgo ilen;
|
||||
intgo icap;
|
||||
uintptr_t size;
|
||||
struct __go_open_array ret;
|
||||
|
||||
__go_assert ((td->__code & GO_CODE_MASK) == GO_SLICE);
|
||||
std = (const struct __go_slice_type *) td;
|
||||
|
||||
ilen = (intgo) len;
|
||||
if (ilen < 0
|
||||
|| (uintptr_t) ilen != len
|
||||
|| (std->__element_type->__size > 0
|
||||
&& len > MaxMem / std->__element_type->__size))
|
||||
runtime_panicstring ("makeslice: len out of range");
|
||||
|
||||
icap = (intgo) cap;
|
||||
if (cap < len
|
||||
|| (uintptr_t) icap != cap
|
||||
|| (std->__element_type->__size > 0
|
||||
&& cap > MaxMem / std->__element_type->__size))
|
||||
runtime_panicstring ("makeslice: cap out of range");
|
||||
|
||||
ret.__count = ilen;
|
||||
ret.__capacity = icap;
|
||||
|
||||
size = cap * std->__element_type->__size;
|
||||
|
||||
if (size == 0)
|
||||
ret.__values = &runtime_zerobase;
|
||||
else if ((std->__element_type->__code & GO_NO_POINTERS) != 0)
|
||||
ret.__values =
|
||||
runtime_mallocgc (size,
|
||||
(uintptr) std->__element_type | TypeInfo_Array,
|
||||
FlagNoScan);
|
||||
else
|
||||
ret.__values =
|
||||
runtime_mallocgc (size,
|
||||
(uintptr) std->__element_type | TypeInfo_Array,
|
||||
0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct __go_open_array
|
||||
__go_make_slice1 (const struct __go_type_descriptor *td, uintptr_t len)
|
||||
{
|
||||
return __go_make_slice2 (td, len, len);
|
||||
}
|
||||
|
||||
struct __go_open_array
|
||||
__go_make_slice2_big (const struct __go_type_descriptor *td, uint64_t len,
|
||||
uint64_t cap)
|
||||
{
|
||||
uintptr_t slen;
|
||||
uintptr_t scap;
|
||||
|
||||
slen = (uintptr_t) len;
|
||||
if ((uint64_t) slen != len)
|
||||
runtime_panicstring ("makeslice: len out of range");
|
||||
|
||||
scap = (uintptr_t) cap;
|
||||
if ((uint64_t) scap != cap)
|
||||
runtime_panicstring ("makeslice: cap out of range");
|
||||
|
||||
return __go_make_slice2 (td, slen, scap);
|
||||
}
|
||||
|
||||
struct __go_open_array
|
||||
__go_make_slice1_big (const struct __go_type_descriptor *td, uint64_t len)
|
||||
{
|
||||
return __go_make_slice2_big (td, len, len);
|
||||
}
|
|
@ -81,7 +81,7 @@ runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
|
|||
// All 0-length allocations use this pointer.
|
||||
// The language does not require the allocations to
|
||||
// have distinct values.
|
||||
return &runtime_zerobase;
|
||||
return runtime_getZerobase();
|
||||
}
|
||||
|
||||
g = runtime_g();
|
||||
|
@ -881,7 +881,7 @@ func new(typ *Type) (ret *uint8) {
|
|||
}
|
||||
|
||||
static void*
|
||||
cnew(const Type *typ, intgo n, int32 objtyp)
|
||||
runtime_docnew(const Type *typ, intgo n, int32 objtyp)
|
||||
{
|
||||
if((objtyp&(PtrSize-1)) != objtyp)
|
||||
runtime_throw("runtime: invalid objtyp");
|
||||
|
@ -894,13 +894,13 @@ cnew(const Type *typ, intgo n, int32 objtyp)
|
|||
void*
|
||||
runtime_cnew(const Type *typ)
|
||||
{
|
||||
return cnew(typ, 1, TypeInfo_SingleObject);
|
||||
return runtime_docnew(typ, 1, TypeInfo_SingleObject);
|
||||
}
|
||||
|
||||
void*
|
||||
runtime_cnewarray(const Type *typ, intgo n)
|
||||
{
|
||||
return cnew(typ, n, TypeInfo_Array);
|
||||
return runtime_docnew(typ, n, TypeInfo_Array);
|
||||
}
|
||||
|
||||
func GC() {
|
||||
|
|
|
@ -234,7 +234,8 @@ enum
|
|||
/*
|
||||
* external data
|
||||
*/
|
||||
extern uintptr runtime_zerobase;
|
||||
extern uintptr* runtime_getZerobase(void)
|
||||
__asm__(GOSYM_PREFIX "runtime.getZerobase");
|
||||
extern G** runtime_allg;
|
||||
extern uintptr runtime_allglen;
|
||||
extern G* runtime_lastg;
|
||||
|
|
Loading…
Add table
Reference in a new issue