Commit 1ad16c52 by Ian Lance Taylor

compiler, runtime: copy string code from Go 1.7

    
    Add compiler support for turning concatenating strings into a call to
    a runtime function that takes the appropriate number of arguments.
    
    Rename some local variables in mgc0.c to avoid macros that the new
    rune.go causes to appear in runtime.inc.
    
    Reviewed-on: https://go-review.googlesource.com/30827

From-SVN: r241074
parent 2ec69f56
c18d9f0e7270144ebd1f67d85995f434bbdab0b0 f38ba8837a0c961e18d982930e192132870f3836
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -1233,13 +1233,17 @@ Escape_analysis_assign::expression(Expression** pexpr) ...@@ -1233,13 +1233,17 @@ Escape_analysis_assign::expression(Expression** pexpr)
case Runtime::MAKESLICE2: case Runtime::MAKESLICE2:
case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE1BIG:
case Runtime::MAKESLICE2BIG: case Runtime::MAKESLICE2BIG:
case Runtime::BYTE_ARRAY_TO_STRING: case Runtime::SLICEBYTETOSTRING:
case Runtime::INT_ARRAY_TO_STRING: case Runtime::SLICERUNETOSTRING:
case Runtime::STRING_TO_BYTE_ARRAY: case Runtime::STRINGTOSLICEBYTE:
case Runtime::STRING_TO_INT_ARRAY: case Runtime::STRINGTOSLICERUNE:
case Runtime::STRING_PLUS: case Runtime::CONCATSTRINGS:
case Runtime::CONCATSTRING2:
case Runtime::CONCATSTRING3:
case Runtime::CONCATSTRING4:
case Runtime::CONCATSTRING5:
case Runtime::CONSTRUCT_MAP: case Runtime::CONSTRUCT_MAP:
case Runtime::INT_TO_STRING: case Runtime::INTSTRING:
{ {
Node* runtime_node = Node::make_node(fe); Node* runtime_node = Node::make_node(fe);
this->context_->track(runtime_node); this->context_->track(runtime_node);
...@@ -1842,21 +1846,25 @@ Escape_analysis_assign::assign(Node* dst, Node* src) ...@@ -1842,21 +1846,25 @@ Escape_analysis_assign::assign(Node* dst, Node* src)
case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE1BIG:
case Runtime::MAKESLICE2BIG: case Runtime::MAKESLICE2BIG:
// DST = make(...). // DST = make(...).
case Runtime::BYTE_ARRAY_TO_STRING: case Runtime::SLICEBYTETOSTRING:
// DST = string([]byte{...}). // DST = string([]byte{...}).
case Runtime::INT_ARRAY_TO_STRING: case Runtime::SLICERUNETOSTRING:
// DST = string([]int{...}). // DST = string([]int{...}).
case Runtime::STRING_TO_BYTE_ARRAY: case Runtime::STRINGTOSLICEBYTE:
// DST = []byte(str). // DST = []byte(str).
case Runtime::STRING_TO_INT_ARRAY: case Runtime::STRINGTOSLICERUNE:
// DST = []int(str). // DST = []rune(str).
case Runtime::STRING_PLUS: case Runtime::CONCATSTRINGS:
case Runtime::CONCATSTRING2:
case Runtime::CONCATSTRING3:
case Runtime::CONCATSTRING4:
case Runtime::CONCATSTRING5:
// DST = str1 + str2 // DST = str1 + str2
case Runtime::CONSTRUCT_MAP: case Runtime::CONSTRUCT_MAP:
// When building a map literal's backend representation. // When building a map literal's backend representation.
// Likely never seen here and covered in // Likely never seen here and covered in
// Expression::EXPRESSION_MAP_CONSTRUCTION. // Expression::EXPRESSION_MAP_CONSTRUCTION.
case Runtime::INT_TO_STRING: case Runtime::INTSTRING:
// DST = string(i). // DST = string(i).
case Runtime::IFACEE2E2: case Runtime::IFACEE2E2:
case Runtime::IFACEI2E2: case Runtime::IFACEI2E2:
...@@ -2614,13 +2622,17 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src, ...@@ -2614,13 +2622,17 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src,
case Runtime::MAKESLICE2: case Runtime::MAKESLICE2:
case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE1BIG:
case Runtime::MAKESLICE2BIG: case Runtime::MAKESLICE2BIG:
case Runtime::BYTE_ARRAY_TO_STRING: case Runtime::SLICEBYTETOSTRING:
case Runtime::INT_ARRAY_TO_STRING: case Runtime::SLICERUNETOSTRING:
case Runtime::STRING_TO_BYTE_ARRAY: case Runtime::STRINGTOSLICEBYTE:
case Runtime::STRING_TO_INT_ARRAY: case Runtime::STRINGTOSLICERUNE:
case Runtime::STRING_PLUS: case Runtime::CONCATSTRINGS:
case Runtime::CONCATSTRING2:
case Runtime::CONCATSTRING3:
case Runtime::CONCATSTRING4:
case Runtime::CONCATSTRING5:
case Runtime::CONSTRUCT_MAP: case Runtime::CONSTRUCT_MAP:
case Runtime::INT_TO_STRING: case Runtime::INTSTRING:
case Runtime::CONVERT_INTERFACE: case Runtime::CONVERT_INTERFACE:
// All runtime calls that involve allocation of memory // All runtime calls that involve allocation of memory
// except new. Runtime::NEW gets lowered into an // except new. Runtime::NEW gets lowered into an
......
...@@ -3419,7 +3419,8 @@ Type_conversion_expression::do_get_backend(Translate_context* context) ...@@ -3419,7 +3419,8 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
} }
Expression* i2s_expr = Expression* i2s_expr =
Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_); Runtime::make_call(Runtime::INTSTRING, loc, 2,
Expression::make_nil(loc), this->expr_);
return Expression::make_cast(type, i2s_expr, loc)->get_backend(context); return Expression::make_cast(type, i2s_expr, loc)->get_backend(context);
} }
else if (type->is_string_type() && expr_type->is_slice_type()) else if (type->is_string_type() && expr_type->is_slice_type())
...@@ -3431,16 +3432,14 @@ Type_conversion_expression::do_get_backend(Translate_context* context) ...@@ -3431,16 +3432,14 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
Runtime::Function code; Runtime::Function code;
if (e->integer_type()->is_byte()) if (e->integer_type()->is_byte())
code = Runtime::BYTE_ARRAY_TO_STRING; code = Runtime::SLICEBYTETOSTRING;
else else
{ {
go_assert(e->integer_type()->is_rune()); go_assert(e->integer_type()->is_rune());
code = Runtime::INT_ARRAY_TO_STRING; code = Runtime::SLICERUNETOSTRING;
} }
Expression* valptr = a->get_value_pointer(gogo, this->expr_); return Runtime::make_call(code, loc, 2, Expression::make_nil(loc),
Expression* len = a->get_length(gogo, this->expr_); this->expr_)->get_backend(context);
return Runtime::make_call(code, loc, 2, valptr,
len)->get_backend(context);
} }
else if (type->is_slice_type() && expr_type->is_string_type()) else if (type->is_slice_type() && expr_type->is_string_type())
{ {
...@@ -3449,13 +3448,15 @@ Type_conversion_expression::do_get_backend(Translate_context* context) ...@@ -3449,13 +3448,15 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
Runtime::Function code; Runtime::Function code;
if (e->integer_type()->is_byte()) if (e->integer_type()->is_byte())
code = Runtime::STRING_TO_BYTE_ARRAY; code = Runtime::STRINGTOSLICEBYTE;
else else
{ {
go_assert(e->integer_type()->is_rune()); go_assert(e->integer_type()->is_rune());
code = Runtime::STRING_TO_INT_ARRAY; code = Runtime::STRINGTOSLICERUNE;
} }
Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_); Expression* s2a = Runtime::make_call(code, loc, 2,
Expression::make_nil(loc),
this->expr_);
return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context); return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context);
} }
else if (type->is_numeric_type()) else if (type->is_numeric_type())
...@@ -5068,6 +5069,31 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, ...@@ -5068,6 +5069,31 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
return this->lower_interface_value_comparison(gogo, inserter); return this->lower_interface_value_comparison(gogo, inserter);
} }
// Lower string concatenation to String_concat_expression, so that
// we can group sequences of string additions.
if (this->left_->type()->is_string_type() && this->op_ == OPERATOR_PLUS)
{
Expression_list* exprs;
String_concat_expression* left_sce =
this->left_->string_concat_expression();
if (left_sce != NULL)
exprs = left_sce->exprs();
else
{
exprs = new Expression_list();
exprs->push_back(this->left_);
}
String_concat_expression* right_sce =
this->right_->string_concat_expression();
if (right_sce != NULL)
exprs->append(right_sce->exprs());
else
exprs->push_back(this->right_);
return Expression::make_string_concat(exprs);
}
return this; return this;
} }
...@@ -5277,25 +5303,6 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, ...@@ -5277,25 +5303,6 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*,
} }
Temporary_statement* temp; Temporary_statement* temp;
if (this->left_->type()->is_string_type()
&& this->op_ == OPERATOR_PLUS)
{
if (!this->left_->is_variable()
&& !this->left_->is_constant())
{
temp = Statement::make_temporary(NULL, this->left_, loc);
inserter->insert(temp);
this->left_ = Expression::make_temporary_reference(temp, loc);
}
if (!this->right_->is_variable()
&& !this->right_->is_constant())
{
temp =
Statement::make_temporary(this->left_->type(), this->right_, loc);
this->right_ = Expression::make_temporary_reference(temp, loc);
inserter->insert(temp);
}
}
Type* left_type = this->left_->type(); Type* left_type = this->left_->type();
bool is_shift_op = (this->op_ == OPERATOR_LSHIFT bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
...@@ -5792,14 +5799,9 @@ Binary_expression::do_get_backend(Translate_context* context) ...@@ -5792,14 +5799,9 @@ Binary_expression::do_get_backend(Translate_context* context)
go_unreachable(); go_unreachable();
} }
if (left_type->is_string_type()) // The only binary operation for string is +, and that should have
{ // been converted to a String_concat_expression in do_lower.
go_assert(this->op_ == OPERATOR_PLUS); go_assert(!left_type->is_string_type());
Expression* string_plus =
Runtime::make_call(Runtime::STRING_PLUS, loc, 2,
this->left_, this->right_);
return string_plus->get_backend(context);
}
// For complex division Go might want slightly different results than the // For complex division Go might want slightly different results than the
// backend implementation provides, so we have our own runtime routine. // backend implementation provides, so we have our own runtime routine.
...@@ -6294,6 +6296,182 @@ Expression::comparison(Translate_context* context, Type* result_type, ...@@ -6294,6 +6296,182 @@ Expression::comparison(Translate_context* context, Type* result_type,
return ret; return ret;
} }
// Class String_concat_expression.
bool
String_concat_expression::do_is_constant() const
{
for (Expression_list::const_iterator pe = this->exprs_->begin();
pe != this->exprs_->end();
++pe)
{
if (!(*pe)->is_constant())
return false;
}
return true;
}
bool
String_concat_expression::do_is_immutable() const
{
for (Expression_list::const_iterator pe = this->exprs_->begin();
pe != this->exprs_->end();
++pe)
{
if (!(*pe)->is_immutable())
return false;
}
return true;
}
Type*
String_concat_expression::do_type()
{
Type* t = this->exprs_->front()->type();
Expression_list::iterator pe = this->exprs_->begin();
++pe;
for (; pe != this->exprs_->end(); ++pe)
{
Type* t1;
if (!Binary_expression::operation_type(OPERATOR_PLUS, t,
(*pe)->type(),
&t1))
return Type::make_error_type();
t = t1;
}
return t;
}
void
String_concat_expression::do_determine_type(const Type_context* context)
{
Type_context subcontext(*context);
for (Expression_list::iterator pe = this->exprs_->begin();
pe != this->exprs_->end();
++pe)
{
Type* t = (*pe)->type();
if (!t->is_abstract())
{
subcontext.type = t;
break;
}
}
if (subcontext.type == NULL)
subcontext.type = this->exprs_->front()->type();
for (Expression_list::iterator pe = this->exprs_->begin();
pe != this->exprs_->end();
++pe)
(*pe)->determine_type(&subcontext);
}
void
String_concat_expression::do_check_types(Gogo*)
{
if (this->is_error_expression())
return;
Type* t = this->exprs_->front()->type();
if (t->is_error())
{
this->set_is_error();
return;
}
Expression_list::iterator pe = this->exprs_->begin();
++pe;
for (; pe != this->exprs_->end(); ++pe)
{
Type* t1 = (*pe)->type();
if (!Type::are_compatible_for_binop(t, t1))
{
this->report_error("incompatible types in binary expression");
return;
}
if (!Binary_expression::check_operator_type(OPERATOR_PLUS, t, t1,
this->location()))
{
this->set_is_error();
return;
}
}
}
Expression*
String_concat_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter*)
{
if (this->is_error_expression())
return this;
Location loc = this->location();
Type* type = this->type();
Expression* nil_arg = Expression::make_nil(loc);
Expression* call;
switch (this->exprs_->size())
{
case 0: case 1:
go_unreachable();
case 2: case 3: case 4: case 5:
{
Expression* len = Expression::make_integer_ul(this->exprs_->size(),
NULL, loc);
Array_type* arg_type = Type::make_array_type(type, len);
arg_type->set_is_array_incomparable();
Expression* arg =
Expression::make_array_composite_literal(arg_type, this->exprs_,
loc);
Runtime::Function code;
switch (this->exprs_->size())
{
default:
go_unreachable();
case 2:
code = Runtime::CONCATSTRING2;
break;
case 3:
code = Runtime::CONCATSTRING3;
break;
case 4:
code = Runtime::CONCATSTRING4;
break;
case 5:
code = Runtime::CONCATSTRING5;
break;
}
call = Runtime::make_call(code, loc, 2, nil_arg, arg);
}
break;
default:
{
Type* arg_type = Type::make_array_type(type, NULL);
Slice_construction_expression* sce =
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,
sce);
}
break;
}
return Expression::make_cast(type, call, loc);
}
void
String_concat_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << "concat(";
ast_dump_context->dump_expression_list(this->exprs_, false);
ast_dump_context->ostream() << ")";
}
Expression*
Expression::make_string_concat(Expression_list* exprs)
{
return new String_concat_expression(exprs);
}
// Class Bound_method_expression. // Class Bound_method_expression.
// Traversal. // Traversal.
......
...@@ -37,6 +37,7 @@ class Type_conversion_expression; ...@@ -37,6 +37,7 @@ class Type_conversion_expression;
class Unsafe_type_conversion_expression; class Unsafe_type_conversion_expression;
class Unary_expression; class Unary_expression;
class Binary_expression; class Binary_expression;
class String_concat_expression;
class Call_expression; class Call_expression;
class Call_result_expression; class Call_result_expression;
class Func_expression; class Func_expression;
...@@ -85,6 +86,7 @@ class Expression ...@@ -85,6 +86,7 @@ class Expression
EXPRESSION_TYPE, EXPRESSION_TYPE,
EXPRESSION_UNARY, EXPRESSION_UNARY,
EXPRESSION_BINARY, EXPRESSION_BINARY,
EXPRESSION_STRING_CONCAT,
EXPRESSION_CONST_REFERENCE, EXPRESSION_CONST_REFERENCE,
EXPRESSION_VAR_REFERENCE, EXPRESSION_VAR_REFERENCE,
EXPRESSION_ENCLOSED_VAR_REFERENCE, EXPRESSION_ENCLOSED_VAR_REFERENCE,
...@@ -160,6 +162,10 @@ class Expression ...@@ -160,6 +162,10 @@ class Expression
static Expression* static Expression*
make_binary(Operator, Expression*, Expression*, Location); make_binary(Operator, Expression*, Expression*, Location);
// Make a string concatenation expression.
static Expression*
make_string_concat(Expression_list*);
// Make a reference to a constant in an expression. // Make a reference to a constant in an expression.
static Expression* static Expression*
make_const_reference(Named_object*, Location); make_const_reference(Named_object*, Location);
...@@ -620,6 +626,14 @@ class Expression ...@@ -620,6 +626,14 @@ class Expression
binary_expression() binary_expression()
{ return this->convert<Binary_expression, EXPRESSION_BINARY>(); } { return this->convert<Binary_expression, EXPRESSION_BINARY>(); }
// If this is a string concatenation expression, return the
// String_concat_expression structure. Otherwise, return NULL.
String_concat_expression*
string_concat_expression()
{
return this->convert<String_concat_expression, EXPRESSION_STRING_CONCAT>();
}
// If this is a call expression, return the Call_expression // If this is a call expression, return the Call_expression
// structure. Otherwise, return NULL. This is a controlled dynamic // structure. Otherwise, return NULL. This is a controlled dynamic
// cast. // cast.
...@@ -1877,6 +1891,13 @@ class Binary_expression : public Expression ...@@ -1877,6 +1891,13 @@ class Binary_expression : public Expression
static bool static bool
check_operator_type(Operator op, Type* type, Type* otype, Location); check_operator_type(Operator op, Type* type, Type* otype, Location);
// Set *RESULT_TYPE to the resulting type when OP is applied to
// operands of type LEFT_TYPE and RIGHT_TYPE. Return true on
// success, false on failure.
static bool
operation_type(Operator op, Type* left_type, Type* right_type,
Type** result_type);
protected: protected:
int int
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
...@@ -1928,10 +1949,6 @@ class Binary_expression : public Expression ...@@ -1928,10 +1949,6 @@ class Binary_expression : public Expression
private: private:
static bool static bool
operation_type(Operator op, Type* left_type, Type* right_type,
Type** result_type);
static bool
cmp_to_bool(Operator op, int cmp); cmp_to_bool(Operator op, int cmp);
static bool static bool
...@@ -1980,6 +1997,69 @@ class Binary_expression : public Expression ...@@ -1980,6 +1997,69 @@ class Binary_expression : public Expression
Type* type_; Type* type_;
}; };
// A string concatenation expression. This is a sequence of strings
// added together. It is created when lowering Binary_expression.
class String_concat_expression : public Expression
{
public:
String_concat_expression(Expression_list* exprs)
: Expression(EXPRESSION_STRING_CONCAT, exprs->front()->location()),
exprs_(exprs)
{ }
// Return the list of string expressions to be concatenated.
Expression_list*
exprs()
{ return this->exprs_; }
protected:
int
do_traverse(Traverse* traverse)
{ return this->exprs_->traverse(traverse); }
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int)
{ return this; }
Expression*
do_flatten(Gogo*, Named_object*, Statement_inserter*);
bool
do_is_constant() const;
bool
do_is_immutable() const;
Type*
do_type();
void
do_determine_type(const Type_context*);
void
do_check_types(Gogo*);
Expression*
do_copy()
{ return Expression::make_string_concat(this->exprs_->copy()); }
Bexpression*
do_get_backend(Translate_context*)
{ go_unreachable(); }
void
do_export(Export*) const
{ go_unreachable(); }
void
do_dump_expression(Ast_dump_context*) const;
private:
// The string expressions to concatenate.
Expression_list* exprs_;
};
// A call expression. The go statement needs to dig inside this. // A call expression. The go statement needs to dig inside this.
class Call_expression : public Expression class Call_expression : public Expression
......
...@@ -64,6 +64,14 @@ enum Runtime_function_type ...@@ -64,6 +64,14 @@ enum Runtime_function_type
RFT_FUNC_PTR, RFT_FUNC_PTR,
// Pointer to Go type descriptor. // Pointer to Go type descriptor.
RFT_TYPE, RFT_TYPE,
// [2]string.
RFT_ARRAY2STRING,
// [3]string.
RFT_ARRAY3STRING,
// [4]string.
RFT_ARRAY4STRING,
// [5]string.
RFT_ARRAY5STRING,
NUMBER_OF_RUNTIME_FUNCTION_TYPES NUMBER_OF_RUNTIME_FUNCTION_TYPES
}; };
...@@ -180,6 +188,30 @@ runtime_function_type(Runtime_function_type bft) ...@@ -180,6 +188,30 @@ runtime_function_type(Runtime_function_type bft)
case RFT_TYPE: case RFT_TYPE:
t = Type::make_type_descriptor_ptr_type(); t = Type::make_type_descriptor_ptr_type();
break; break;
case RFT_ARRAY2STRING:
t = Type::make_array_type(Type::make_string_type(),
Expression::make_integer_ul(2, NULL,
bloc));
break;
case RFT_ARRAY3STRING:
t = Type::make_array_type(Type::make_string_type(),
Expression::make_integer_ul(3, NULL,
bloc));
break;
case RFT_ARRAY4STRING:
t = Type::make_array_type(Type::make_string_type(),
Expression::make_integer_ul(4, NULL,
bloc));
break;
case RFT_ARRAY5STRING:
t = Type::make_array_type(Type::make_string_type(),
Expression::make_integer_ul(5, NULL,
bloc));
break;
} }
runtime_function_types[bft] = t; runtime_function_types[bft] = t;
...@@ -226,6 +258,10 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, ...@@ -226,6 +258,10 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_CHAN: case RFT_CHAN:
case RFT_IFACE: case RFT_IFACE:
case RFT_EFACE: case RFT_EFACE:
case RFT_ARRAY2STRING:
case RFT_ARRAY3STRING:
case RFT_ARRAY4STRING:
case RFT_ARRAY5STRING:
return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
case RFT_TYPE: case RFT_TYPE:
......
...@@ -38,8 +38,17 @@ DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT)) ...@@ -38,8 +38,17 @@ DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))
DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT), DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT),
R2(INT, RUNE)) R2(INT, RUNE))
// Concatenate two strings. // Concatenate strings.
DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING)) DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings", P2(POINTER, SLICE),
R1(STRING))
DEF_GO_RUNTIME(CONCATSTRING2, "runtime.concatstring2",
P2(POINTER, ARRAY2STRING), R1(STRING))
DEF_GO_RUNTIME(CONCATSTRING3, "runtime.concatstring3",
P2(POINTER, ARRAY3STRING), R1(STRING))
DEF_GO_RUNTIME(CONCATSTRING4, "runtime.concatstring4",
P2(POINTER, ARRAY4STRING), R1(STRING))
DEF_GO_RUNTIME(CONCATSTRING5, "runtime.concatstring5",
P2(POINTER, ARRAY5STRING), R1(STRING))
// Compare two strings. // Compare two strings.
DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT)) DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT))
...@@ -49,23 +58,23 @@ DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT), ...@@ -49,23 +58,23 @@ DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT),
R1(STRING)) R1(STRING))
// Convert an integer to a string. // Convert an integer to a string.
DEF_GO_RUNTIME(INT_TO_STRING, "__go_int_to_string", P1(INT), R1(STRING)) DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING))
// Convert a byte array to a string. // Convert a []byte to a string.
DEF_GO_RUNTIME(BYTE_ARRAY_TO_STRING, "__go_byte_array_to_string", DEF_GO_RUNTIME(SLICEBYTETOSTRING, "runtime.slicebytetostring",
P2(POINTER, INT), R1(STRING)) P2(POINTER, SLICE), R1(STRING))
// Convert an int array to a string. // Convert a []rune to a string.
DEF_GO_RUNTIME(INT_ARRAY_TO_STRING, "__go_int_array_to_string", DEF_GO_RUNTIME(SLICERUNETOSTRING, "runtime.slicerunetostring",
P2(POINTER, INT), R1(STRING)) P2(POINTER, SLICE), R1(STRING))
// Convert a string to a byte slice. // Convert a string to a []byte.
DEF_GO_RUNTIME(STRING_TO_BYTE_ARRAY, "__go_string_to_byte_array", DEF_GO_RUNTIME(STRINGTOSLICEBYTE, "runtime.stringtoslicebyte",
P1(STRING), R1(SLICE)) P2(POINTER, STRING), R1(SLICE))
// Convert a string to an int slice. // Convert a string to a []rune.
DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array", DEF_GO_RUNTIME(STRINGTOSLICERUNE, "runtime.stringtoslicerune",
P1(STRING), R1(SLICE)) P2(POINTER, STRING), R1(SLICE))
// Complex division. // Complex division.
......
...@@ -441,7 +441,6 @@ runtime_files = \ ...@@ -441,7 +441,6 @@ runtime_files = \
runtime/go-append.c \ runtime/go-append.c \
runtime/go-assert.c \ runtime/go-assert.c \
runtime/go-assert-interface.c \ runtime/go-assert-interface.c \
runtime/go-byte-array-to-string.c \
runtime/go-breakpoint.c \ runtime/go-breakpoint.c \
runtime/go-caller.c \ runtime/go-caller.c \
runtime/go-callers.c \ runtime/go-callers.c \
...@@ -458,8 +457,6 @@ runtime_files = \ ...@@ -458,8 +457,6 @@ runtime_files = \
runtime/go-eface-val-compare.c \ runtime/go-eface-val-compare.c \
runtime/go-ffi.c \ runtime/go-ffi.c \
runtime/go-fieldtrack.c \ runtime/go-fieldtrack.c \
runtime/go-int-array-to-string.c \
runtime/go-int-to-string.c \
runtime/go-interface-compare.c \ runtime/go-interface-compare.c \
runtime/go-interface-eface-compare.c \ runtime/go-interface-eface-compare.c \
runtime/go-interface-val-compare.c \ runtime/go-interface-val-compare.c \
...@@ -476,14 +473,10 @@ runtime_files = \ ...@@ -476,14 +473,10 @@ runtime_files = \
runtime/go-panic.c \ runtime/go-panic.c \
runtime/go-recover.c \ runtime/go-recover.c \
runtime/go-reflect-call.c \ runtime/go-reflect-call.c \
runtime/go-rune.c \
runtime/go-runtime-error.c \ runtime/go-runtime-error.c \
runtime/go-setenv.c \ runtime/go-setenv.c \
runtime/go-signal.c \ runtime/go-signal.c \
runtime/go-strcmp.c \ runtime/go-strcmp.c \
runtime/go-string-to-byte-array.c \
runtime/go-string-to-int-array.c \
runtime/go-strplus.c \
runtime/go-strslice.c \ runtime/go-strslice.c \
runtime/go-traceback.c \ runtime/go-traceback.c \
runtime/go-type-complex.c \ runtime/go-type-complex.c \
...@@ -529,7 +522,6 @@ runtime_files = \ ...@@ -529,7 +522,6 @@ runtime_files = \
reflect.c \ reflect.c \
runtime1.c \ runtime1.c \
sigqueue.c \ sigqueue.c \
string.c \
time.c \ time.c \
$(runtime_getncpu_file) $(runtime_getncpu_file)
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
package runtime package runtime
import "unsafe"
// The Error interface identifies a run time error. // The Error interface identifies a run time error.
type Error interface { type Error interface {
error error
...@@ -107,10 +109,8 @@ type errorCString struct{ cstr uintptr } ...@@ -107,10 +109,8 @@ type errorCString struct{ cstr uintptr }
func (e errorCString) RuntimeError() {} func (e errorCString) RuntimeError() {}
func cstringToGo(uintptr) string
func (e errorCString) Error() string { func (e errorCString) Error() string {
return "runtime error: " + cstringToGo(e.cstr) return "runtime error: " + gostringnocopy((*byte)(unsafe.Pointer(e.cstr)))
} }
// For calling from C. // For calling from C.
......
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Portions Copyright 2009 The Go Authors. All rights reserved.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
/*
* This code is copied, with slight editing due to type differences,
* from a subset of ../lib9/utf/rune.c [which no longer exists]
*/
package runtime
const (
bit1 = 7
bitx = 6
bit2 = 5
bit3 = 4
bit4 = 3
bit5 = 2
t1 = ((1 << (bit1 + 1)) - 1) ^ 0xFF /* 0000 0000 */
tx = ((1 << (bitx + 1)) - 1) ^ 0xFF /* 1000 0000 */
t2 = ((1 << (bit2 + 1)) - 1) ^ 0xFF /* 1100 0000 */
t3 = ((1 << (bit3 + 1)) - 1) ^ 0xFF /* 1110 0000 */
t4 = ((1 << (bit4 + 1)) - 1) ^ 0xFF /* 1111 0000 */
t5 = ((1 << (bit5 + 1)) - 1) ^ 0xFF /* 1111 1000 */
rune1 = (1 << (bit1 + 0*bitx)) - 1 /* 0000 0000 0111 1111 */
rune2 = (1 << (bit2 + 1*bitx)) - 1 /* 0000 0111 1111 1111 */
rune3 = (1 << (bit3 + 2*bitx)) - 1 /* 1111 1111 1111 1111 */
rune4 = (1 << (bit4 + 3*bitx)) - 1 /* 0001 1111 1111 1111 1111 1111 */
maskx = (1 << bitx) - 1 /* 0011 1111 */
testx = maskx ^ 0xFF /* 1100 0000 */
runeerror = 0xFFFD
runeself = 0x80
surrogateMin = 0xD800
surrogateMax = 0xDFFF
bad = runeerror
runemax = 0x10FFFF /* maximum rune value */
)
/*
* Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
* This is a slower but "safe" version of the old chartorune
* that works on strings that are not necessarily null-terminated.
*
* If you know for sure that your string is null-terminated,
* chartorune will be a bit faster.
*
* It is guaranteed not to attempt to access "length"
* past the incoming pointer. This is to avoid
* possible access violations. If the string appears to be
* well-formed but incomplete (i.e., to get the whole Rune
* we'd need to read past str+length) then we'll set the Rune
* to Bad and return 0.
*
* Note that if we have decoding problems for other
* reasons, we return 1 instead of 0.
*/
func charntorune(s string) (rune, int) {
/* When we're not allowed to read anything */
if len(s) <= 0 {
return bad, 1
}
/*
* one character sequence (7-bit value)
* 00000-0007F => T1
*/
c := s[0]
if c < tx {
return rune(c), 1
}
// If we can't read more than one character we must stop
if len(s) <= 1 {
return bad, 1
}
/*
* two character sequence (11-bit value)
* 0080-07FF => t2 tx
*/
c1 := s[1] ^ tx
if (c1 & testx) != 0 {
return bad, 1
}
if c < t3 {
if c < t2 {
return bad, 1
}
l := ((rune(c) << bitx) | rune(c1)) & rune2
if l <= rune1 {
return bad, 1
}
return l, 2
}
// If we can't read more than two characters we must stop
if len(s) <= 2 {
return bad, 1
}
/*
* three character sequence (16-bit value)
* 0800-FFFF => t3 tx tx
*/
c2 := s[2] ^ tx
if (c2 & testx) != 0 {
return bad, 1
}
if c < t4 {
l := ((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) & rune3
if l <= rune2 {
return bad, 1
}
if surrogateMin <= l && l <= surrogateMax {
return bad, 1
}
return l, 3
}
if len(s) <= 3 {
return bad, 1
}
/*
* four character sequence (21-bit value)
* 10000-1FFFFF => t4 tx tx tx
*/
c3 := s[3] ^ tx
if (c3 & testx) != 0 {
return bad, 1
}
if c < t5 {
l := ((((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) << bitx) | rune(c3)) & rune4
if l <= rune3 || l > runemax {
return bad, 1
}
return l, 4
}
// Support for 5-byte or longer UTF-8 would go here, but
// since we don't have that, we'll just return bad.
return bad, 1
}
// runetochar converts r to bytes and writes the result to str.
// returns the number of bytes generated.
func runetochar(str []byte, r rune) int {
/* runes are signed, so convert to unsigned for range check. */
c := uint32(r)
/*
* one character sequence
* 00000-0007F => 00-7F
*/
if c <= rune1 {
str[0] = byte(c)
return 1
}
/*
* two character sequence
* 0080-07FF => t2 tx
*/
if c <= rune2 {
str[0] = byte(t2 | (c >> (1 * bitx)))
str[1] = byte(tx | (c & maskx))
return 2
}
/*
* If the rune is out of range or a surrogate half, convert it to the error rune.
* Do this test here because the error rune encodes to three bytes.
* Doing it earlier would duplicate work, since an out of range
* rune wouldn't have fit in one or two bytes.
*/
if c > runemax {
c = runeerror
}
if surrogateMin <= c && c <= surrogateMax {
c = runeerror
}
/*
* three character sequence
* 0800-FFFF => t3 tx tx
*/
if c <= rune3 {
str[0] = byte(t3 | (c >> (2 * bitx)))
str[1] = byte(tx | ((c >> (1 * bitx)) & maskx))
str[2] = byte(tx | (c & maskx))
return 3
}
/*
* four character sequence (21-bit value)
* 10000-1FFFFF => t4 tx tx tx
*/
str[0] = byte(t4 | (c >> (3 * bitx)))
str[1] = byte(tx | ((c >> (2 * bitx)) & maskx))
str[2] = byte(tx | ((c >> (1 * bitx)) & maskx))
str[3] = byte(tx | (c & maskx))
return 4
}
...@@ -223,7 +223,9 @@ func TestIntStringAllocs(t *testing.T) { ...@@ -223,7 +223,9 @@ func TestIntStringAllocs(t *testing.T) {
t.Fatalf("bad") t.Fatalf("bad")
} }
}) })
if n != 0 { // was n != 0, changed for gccgo, which currently does one
// allocation for each call to string(unknown).
if n > 2 {
t.Fatalf("want 0 allocs, got %v", n) t.Fatalf("want 0 allocs, got %v", n)
} }
} }
......
...@@ -250,17 +250,6 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) { ...@@ -250,17 +250,6 @@ func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
memmove(dst, src, typ.size) memmove(dst, src, typ.size)
} }
// Here for gccgo unless and until we port string.go.
type stringStruct struct {
str unsafe.Pointer
len int
}
// Here for gccgo unless and until we port string.go.
func stringStructOf(sp *string) *stringStruct {
return (*stringStruct)(unsafe.Pointer(sp))
}
// Here for gccgo unless and until we port slice.go. // Here for gccgo unless and until we port slice.go.
type slice struct { type slice struct {
array unsafe.Pointer array unsafe.Pointer
...@@ -286,76 +275,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { ...@@ -286,76 +275,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
return c_mallocgc(size, uintptr(unsafe.Pointer(typ)), flag) return c_mallocgc(size, uintptr(unsafe.Pointer(typ)), flag)
} }
// Here for gccgo unless and until we port string.go.
func rawstring(size int) (p unsafe.Pointer, s string) {
p = mallocgc(uintptr(size), nil, false)
(*(*stringStruct)(unsafe.Pointer(&s))).str = p
(*(*stringStruct)(unsafe.Pointer(&s))).len = size
return
}
// Here for gccgo unless and until we port string.go.
func gostring(p *byte) string {
l := findnull(p)
if l == 0 {
return ""
}
m, s := rawstring(l)
memmove(m, unsafe.Pointer(p), uintptr(l))
return s
}
// Here for gccgo unless and until we port string.go.
func index(s, t string) int {
if len(t) == 0 {
return 0
}
for i := 0; i < len(s); i++ {
if s[i] == t[0] && hasprefix(s[i:], t) {
return i
}
}
return -1
}
// Here for gccgo unless and until we port string.go.
func hasprefix(s, t string) bool {
return len(s) >= len(t) && s[:len(t)] == t
}
// Here for gccgo unless and until we port string.go.
//go:nosplit
func findnull(s *byte) int {
if s == nil {
return 0
}
p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
l := 0
for p[l] != 0 {
l++
}
return l
}
// Here for gccgo unless and until we port string.go.
//go:nosplit
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
return *(*string)(unsafe.Pointer(&ss))
}
// Here for gccgo unless and until we port string.go.
func atoi(s string) int {
n := 0
for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
n = n*10 + int(s[0]) - '0'
s = s[1:]
}
return n
}
// Here for gccgo until we port mgc.go. // Here for gccgo until we port mgc.go.
var writeBarrier struct { var writeBarrier struct {
enabled bool // compiler emits a check of this before calling write barrier enabled bool // compiler emits a check of this before calling write barrier
...@@ -445,3 +364,6 @@ func releaseSudog(s *sudog) { ...@@ -445,3 +364,6 @@ func releaseSudog(s *sudog) {
// Temporary hack for gccgo until we port the garbage collector. // Temporary hack for gccgo until we port the garbage collector.
func typeBitsBulkBarrier(typ *_type, p, size uintptr) {} func typeBitsBulkBarrier(typ *_type, p, size uintptr) {}
// Here for gccgo until we port msize.go.
func roundupsize(uintptr) uintptr
/* go-byte-array-to-string.c -- convert an array of bytes to a string in Go.
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. */
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
String
__go_byte_array_to_string (const void* p, intgo len)
{
const unsigned char *bytes;
unsigned char *retdata;
String ret;
bytes = (const unsigned char *) p;
retdata = runtime_mallocgc ((uintptr) len, 0, FlagNoScan);
__builtin_memcpy (retdata, bytes, len);
ret.str = retdata;
ret.len = len;
return ret;
}
/* go-int-array-to-string.c -- convert an array of ints to a string in Go.
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. */
#include "go-assert.h"
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
String
__go_int_array_to_string (const void* p, intgo len)
{
const int32 *ints;
intgo slen;
intgo i;
unsigned char *retdata;
String ret;
unsigned char *s;
ints = (const int32 *) p;
slen = 0;
for (i = 0; i < len; ++i)
{
int32 v;
v = ints[i];
if (v < 0 || v > 0x10ffff)
v = 0xfffd;
else if (0xd800 <= v && v <= 0xdfff)
v = 0xfffd;
if (v <= 0x7f)
slen += 1;
else if (v <= 0x7ff)
slen += 2;
else if (v <= 0xffff)
slen += 3;
else
slen += 4;
}
retdata = runtime_mallocgc ((uintptr) slen, 0, FlagNoScan);
ret.str = retdata;
ret.len = slen;
s = retdata;
for (i = 0; i < len; ++i)
{
int32 v;
v = ints[i];
/* If V is out of range for UTF-8, substitute the replacement
character. */
if (v < 0 || v > 0x10ffff)
v = 0xfffd;
else if (0xd800 <= v && v <= 0xdfff)
v = 0xfffd;
if (v <= 0x7f)
*s++ = v;
else if (v <= 0x7ff)
{
*s++ = 0xc0 | ((v >> 6) & 0x1f);
*s++ = 0x80 | (v & 0x3f);
}
else if (v <= 0xffff)
{
*s++ = 0xe0 | ((v >> 12) & 0xf);
*s++ = 0x80 | ((v >> 6) & 0x3f);
*s++ = 0x80 | (v & 0x3f);
}
else
{
*s++ = 0xf0 | ((v >> 18) & 0x7);
*s++ = 0x80 | ((v >> 12) & 0x3f);
*s++ = 0x80 | ((v >> 6) & 0x3f);
*s++ = 0x80 | (v & 0x3f);
}
}
__go_assert (s - retdata == slen);
return ret;
}
/* go-int-to-string.c -- convert an integer to a string in Go.
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. */
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
String
__go_int_to_string (intgo v)
{
char buf[4];
int len;
unsigned char *retdata;
String ret;
/* A negative value is not valid UTF-8; turn it into the replacement
character. */
if (v < 0)
v = 0xfffd;
if (v <= 0x7f)
{
buf[0] = v;
len = 1;
}
else if (v <= 0x7ff)
{
buf[0] = 0xc0 + (v >> 6);
buf[1] = 0x80 + (v & 0x3f);
len = 2;
}
else
{
/* If the value is out of range for UTF-8, turn it into the
"replacement character". */
if (v > 0x10ffff)
v = 0xfffd;
/* If the value is a surrogate pair, which is invalid in UTF-8,
turn it into the replacement character. */
if (v >= 0xd800 && v < 0xe000)
v = 0xfffd;
if (v <= 0xffff)
{
buf[0] = 0xe0 + (v >> 12);
buf[1] = 0x80 + ((v >> 6) & 0x3f);
buf[2] = 0x80 + (v & 0x3f);
len = 3;
}
else
{
buf[0] = 0xf0 + (v >> 18);
buf[1] = 0x80 + ((v >> 12) & 0x3f);
buf[2] = 0x80 + ((v >> 6) & 0x3f);
buf[3] = 0x80 + (v & 0x3f);
len = 4;
}
}
retdata = runtime_mallocgc (len, 0, FlagNoScan);
__builtin_memcpy (retdata, buf, len);
ret.str = retdata;
ret.len = len;
return ret;
}
/* go-rune.c -- rune functions for Go.
Copyright 2009, 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 "runtime.h"
#include "go-string.h"
/* Get a character from the UTF-8 string STR, of length LEN. Store
the Unicode character, if any, in *RUNE. Return the number of
characters used from STR. */
int
__go_get_rune (const unsigned char *str, size_t len, int32 *rune)
{
int c, c1, c2, c3, l;
/* Default to the "replacement character". */
*rune = 0xfffd;
if (len <= 0)
return 1;
c = *str;
if (c <= 0x7f)
{
*rune = c;
return 1;
}
if (len <= 1)
return 1;
c1 = str[1];
if ((c & 0xe0) == 0xc0
&& (c1 & 0xc0) == 0x80)
{
l = (((c & 0x1f) << 6) + (c1 & 0x3f));
if (l <= 0x7f)
return 1;
*rune = l;
return 2;
}
if (len <= 2)
return 1;
c2 = str[2];
if ((c & 0xf0) == 0xe0
&& (c1 & 0xc0) == 0x80
&& (c2 & 0xc0) == 0x80)
{
l = (((c & 0xf) << 12)
+ ((c1 & 0x3f) << 6)
+ (c2 & 0x3f));
if (l <= 0x7ff)
return 1;
if (l >= 0xd800 && l < 0xe000)
{
/* Invalid surrogate half; return replace character. */
return 1;
}
*rune = l;
return 3;
}
if (len <= 3)
return 1;
c3 = str[3];
if ((c & 0xf8) == 0xf0
&& (c1 & 0xc0) == 0x80
&& (c2 & 0xc0) == 0x80
&& (c3 & 0xc0) == 0x80)
{
l = (((c & 0x7) << 18)
+ ((c1 & 0x3f) << 12)
+ ((c2 & 0x3f) << 6)
+ (c3 & 0x3f));
if (l <= 0xffff || l > 0x10ffff)
return 1;
*rune = l;
return 4;
}
/* Invalid encoding. Return 1 so that we advance. */
return 1;
}
/* go-string-to-byte-array.c -- convert a string to an array of bytes in Go.
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 "array.h"
#include "arch.h"
#include "malloc.h"
struct __go_open_array
__go_string_to_byte_array (String str)
{
uintptr cap;
unsigned char *data;
struct __go_open_array ret;
cap = runtime_roundupsize (str.len);
data = (unsigned char *) runtime_mallocgc (cap, 0, FlagNoScan | FlagNoZero);
__builtin_memcpy (data, str.str, str.len);
if (cap != (uintptr) str.len)
__builtin_memset (data + str.len, 0, cap - (uintptr) str.len);
ret.__values = (void *) data;
ret.__count = str.len;
ret.__capacity = str.len;
return ret;
}
/* go-string-to-int-array.c -- convert a string to an array of ints in Go.
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-alloc.h"
#include "go-string.h"
#include "array.h"
#include "arch.h"
#include "malloc.h"
struct __go_open_array
__go_string_to_int_array (String str)
{
size_t c;
const unsigned char *p;
const unsigned char *pend;
uintptr mem;
uint32_t *data;
uint32_t *pd;
struct __go_open_array ret;
c = 0;
p = str.str;
pend = p + str.len;
while (p < pend)
{
int rune;
++c;
p += __go_get_rune (p, pend - p, &rune);
}
if (c > MaxMem / sizeof (uint32_t))
runtime_throw ("out of memory");
mem = runtime_roundupsize (c * sizeof (uint32_t));
data = (uint32_t *) runtime_mallocgc (mem, 0, FlagNoScan | FlagNoZero);
p = str.str;
pd = data;
while (p < pend)
{
int rune;
p += __go_get_rune (p, pend - p, &rune);
*pd++ = rune;
}
if (mem > (uintptr) c * sizeof (uint32_t))
__builtin_memset (data + c, 0, mem - (uintptr) c * sizeof (uint32_t));
ret.__values = (void *) data;
ret.__count = c;
ret.__capacity = (intgo) (mem / sizeof (uint32_t));
return ret;
}
/* go-strplus.c -- the go string append function.
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. */
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
String
__go_string_plus (String s1, String s2)
{
int len;
byte *retdata;
String ret;
if (s1.len == 0)
return s2;
else if (s2.len == 0)
return s1;
len = s1.len + s2.len;
retdata = runtime_mallocgc (len, 0, FlagNoScan | FlagNoZero);
__builtin_memcpy (retdata, s1.str, s1.len);
__builtin_memcpy (retdata + s1.len, s2.str, s2.len);
ret.str = retdata;
ret.len = len;
return ret;
}
...@@ -285,7 +285,8 @@ void runtime_updatememstats(GCStats *stats); ...@@ -285,7 +285,8 @@ void runtime_updatememstats(GCStats *stats);
// making new objects in class i // making new objects in class i
int32 runtime_SizeToClass(int32); int32 runtime_SizeToClass(int32);
uintptr runtime_roundupsize(uintptr); uintptr runtime_roundupsize(uintptr)
__asm__(GOSYM_PREFIX "runtime.roundupsize");
extern int32 runtime_class_to_size[_NumSizeClasses]; extern int32 runtime_class_to_size[_NumSizeClasses];
extern int32 runtime_class_to_allocnpages[_NumSizeClasses]; extern int32 runtime_class_to_allocnpages[_NumSizeClasses];
extern int8 runtime_size_to_class8[1024/8 + 1]; extern int8 runtime_size_to_class8[1024/8 + 1];
......
...@@ -2216,7 +2216,7 @@ static void ...@@ -2216,7 +2216,7 @@ static void
gc(struct gc_args *args) gc(struct gc_args *args)
{ {
M *m; M *m;
int64 t0, t1, t2, t3, t4; int64 tm0, tm1, tm2, tm3, tm4;
uint64 heap0, heap1, obj, ninstr; uint64 heap0, heap1, obj, ninstr;
GCStats stats; GCStats stats;
uint32 i; uint32 i;
...@@ -2228,7 +2228,7 @@ gc(struct gc_args *args) ...@@ -2228,7 +2228,7 @@ gc(struct gc_args *args)
runtime_tracegc(); runtime_tracegc();
m->traceback = 2; m->traceback = 2;
t0 = args->start_time; tm0 = args->start_time;
work.tstart = args->start_time; work.tstart = args->start_time;
if(CollectStats) if(CollectStats)
...@@ -2239,9 +2239,9 @@ gc(struct gc_args *args) ...@@ -2239,9 +2239,9 @@ gc(struct gc_args *args)
work.markfor = runtime_parforalloc(MaxGcproc); work.markfor = runtime_parforalloc(MaxGcproc);
m->locks--; m->locks--;
t1 = 0; tm1 = 0;
if(runtime_debug.gctrace) if(runtime_debug.gctrace)
t1 = runtime_nanotime(); tm1 = runtime_nanotime();
// Sweep what is not sweeped by bgsweep. // Sweep what is not sweeped by bgsweep.
while(runtime_sweepone() != (uintptr)-1) while(runtime_sweepone() != (uintptr)-1)
...@@ -2256,17 +2256,17 @@ gc(struct gc_args *args) ...@@ -2256,17 +2256,17 @@ gc(struct gc_args *args)
runtime_helpgc(work.nproc); runtime_helpgc(work.nproc);
} }
t2 = 0; tm2 = 0;
if(runtime_debug.gctrace) if(runtime_debug.gctrace)
t2 = runtime_nanotime(); tm2 = runtime_nanotime();
gchelperstart(); gchelperstart();
runtime_parfordo(work.markfor); runtime_parfordo(work.markfor);
scanblock(nil, true); scanblock(nil, true);
t3 = 0; tm3 = 0;
if(runtime_debug.gctrace) if(runtime_debug.gctrace)
t3 = runtime_nanotime(); tm3 = runtime_nanotime();
bufferList[m->helpgc].busy = 0; bufferList[m->helpgc].busy = 0;
if(work.nproc > 1) if(work.nproc > 1)
...@@ -2280,14 +2280,14 @@ gc(struct gc_args *args) ...@@ -2280,14 +2280,14 @@ gc(struct gc_args *args)
// concurrent/lazy sweep will reduce this number while discovering new garbage // concurrent/lazy sweep will reduce this number while discovering new garbage
mstats.next_gc = mstats.heap_alloc+(mstats.heap_alloc-runtime_stacks_sys)*gcpercent/100; mstats.next_gc = mstats.heap_alloc+(mstats.heap_alloc-runtime_stacks_sys)*gcpercent/100;
t4 = runtime_nanotime(); tm4 = runtime_nanotime();
mstats.last_gc = runtime_unixnanotime(); // must be Unix time to make sense to user mstats.last_gc = runtime_unixnanotime(); // must be Unix time to make sense to user
mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0; mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = tm4 - tm0;
mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = mstats.last_gc; mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = mstats.last_gc;
mstats.pause_total_ns += t4 - t0; mstats.pause_total_ns += tm4 - tm0;
mstats.numgc++; mstats.numgc++;
if(mstats.debuggc) if(mstats.debuggc)
runtime_printf("pause %D\n", t4-t0); runtime_printf("pause %D\n", tm4-tm0);
if(runtime_debug.gctrace) { if(runtime_debug.gctrace) {
heap1 = mstats.heap_alloc; heap1 = mstats.heap_alloc;
...@@ -2305,7 +2305,7 @@ gc(struct gc_args *args) ...@@ -2305,7 +2305,7 @@ gc(struct gc_args *args)
runtime_printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects," runtime_printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
" %d/%d/%d sweeps," " %d/%d/%d sweeps,"
" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n", " %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
mstats.numgc, work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000, mstats.numgc, work.nproc, (tm1-tm0)/1000, (tm2-tm1)/1000, (tm3-tm2)/1000, (tm4-tm3)/1000,
heap0>>20, heap1>>20, obj, heap0>>20, heap1>>20, obj,
mstats.nmalloc, mstats.nfree, mstats.nmalloc, mstats.nfree,
sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep, sweep.nspan, gcstats.nbgsweep, gcstats.npausesweep,
......
...@@ -307,8 +307,8 @@ extern bool runtime_isarchive; ...@@ -307,8 +307,8 @@ extern bool runtime_isarchive;
#define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2)) #define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
#define runtime_strncmp(s1, s2, n) __builtin_strncmp((s1), (s2), (n)) #define runtime_strncmp(s1, s2, n) __builtin_strncmp((s1), (s2), (n))
#define runtime_strstr(s1, s2) __builtin_strstr((s1), (s2)) #define runtime_strstr(s1, s2) __builtin_strstr((s1), (s2))
intgo runtime_findnull(const byte*); intgo runtime_findnull(const byte*)
intgo runtime_findnullw(const uint16*); __asm__ (GOSYM_PREFIX "runtime.findnull");
void runtime_gogo(G*); void runtime_gogo(G*);
struct __go_func_type; struct __go_func_type;
...@@ -328,8 +328,8 @@ int32 runtime_snprintf(byte*, int32, const char*, ...); ...@@ -328,8 +328,8 @@ int32 runtime_snprintf(byte*, int32, const char*, ...);
#define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s)) #define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
#define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s)) #define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
void* runtime_mal(uintptr); void* runtime_mal(uintptr);
String runtime_gostring(const byte*); String runtime_gostringnocopy(const byte*)
String runtime_gostringnocopy(const byte*); __asm__ (GOSYM_PREFIX "runtime.gostringnocopy");
void runtime_schedinit(void); void runtime_schedinit(void);
void runtime_initsig(bool); void runtime_initsig(bool);
void runtime_sigenable(uint32 sig); void runtime_sigenable(uint32 sig);
......
// Copyright 2009, 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.
package runtime
#include "runtime.h"
#include "arch.h"
#include "malloc.h"
#include "go-string.h"
#define charntorune(pv, str, len) __go_get_rune(str, len, pv)
const String runtime_emptystring;
intgo
runtime_findnull(const byte *s)
{
if(s == nil)
return 0;
return __builtin_strlen((const char*) s);
}
intgo
runtime_findnullw(const uint16 *s)
{
intgo l;
if(s == nil)
return 0;
for(l=0; s[l]!=0; l++)
;
return l;
}
static String
gostringsize(intgo l, byte** pmem)
{
String s;
byte *mem;
if(l == 0) {
*pmem = nil;
return runtime_emptystring;
}
mem = runtime_mallocgc(l, 0, FlagNoScan|FlagNoZero);
s.str = mem;
s.len = l;
*pmem = mem;
return s;
}
String
runtime_gostring(const byte *str)
{
intgo l;
String s;
byte *mem;
l = runtime_findnull(str);
s = gostringsize(l, &mem);
runtime_memmove(mem, str, l);
return s;
}
String
runtime_gostringnocopy(const byte *str)
{
String s;
s.str = str;
s.len = runtime_findnull(str);
return s;
}
func cstringToGo(str *byte) (s String) {
s = runtime_gostringnocopy(str);
}
enum
{
Runeself = 0x80,
};
func stringiter(s String, k int) (retk int) {
int32 l;
if(k >= s.len) {
// retk=0 is end of iteration
retk = 0;
goto out;
}
l = s.str[k];
if(l < Runeself) {
retk = k+1;
goto out;
}
// multi-char rune
retk = k + charntorune(&l, s.str+k, s.len-k);
out:
}
func stringiter2(s String, k int) (retk int, retv int32) {
if(k >= s.len) {
// retk=0 is end of iteration
retk = 0;
retv = 0;
goto out;
}
retv = s.str[k];
if(retv < Runeself) {
retk = k+1;
goto out;
}
// multi-char rune
retk = k + charntorune(&retv, s.str+k, s.len-k);
out:
}
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