-949c3b7aa603bc09e650d62e82c600b3463802f0
+2609f9b8420e2341fbbe40d7cf6af42b0fba7293
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
if (fe != NULL)
{
Named_object* no = fe->named_object();
+
+ if (no->is_function_declaration()
+ && no->func_declaration_value()->type()->is_builtin())
+ return TRAVERSE_CONTINUE;
+
std::pair<Unordered_set(Named_object*)::iterator, bool> ins =
this->exports_->insert(no);
if ((*p)->is_function()
&& (*p)->func_value()->export_for_inlining())
check_inline_refs.push_back(*p);
+ else if ((*p)->is_type())
+ {
+ const Bindings* methods = (*p)->type_value()->local_methods();
+ if (methods != NULL)
+ {
+ for (Bindings::const_definitions_iterator pm =
+ methods->begin_definitions();
+ pm != methods->end_definitions();
+ ++pm)
+ {
+ Function* fn = (*pm)->func_value();
+ if (fn->export_for_inlining())
+ check_inline_refs.push_back(*pm);
+ }
+ }
+ }
}
}
}
}
+ // Track all imported packages mentioned in export data.
+ Unordered_set(const Package*) all_imports;
+
// Export the symbols in sorted order. That will reduce cases where
// irrelevant changes to the source code affect the exported
// interface.
for (Unordered_set(Named_object*)::const_iterator p = exports.begin();
p != exports.end();
++p)
- sorted_exports.push_back(*p);
+ {
+ sorted_exports.push_back(*p);
+
+ const Package* pkg = (*p)->package();
+ if (pkg != NULL)
+ all_imports.insert(pkg);
+ }
std::sort(sorted_exports.begin(), sorted_exports.end(), Sort_bindings());
// Assign indexes to all exported types and types referenced by
// exported types, and collect all packages mentioned.
- Unordered_set(const Package*) type_imports;
int unexported_type_index = this->prepare_types(&sorted_exports,
- &type_imports);
+ &all_imports);
// Although the export data is readable, at least this version is,
// it is conceptually a binary format. Start with a four byte
this->write_packages(packages);
- this->write_imports(imports, type_imports);
+ this->write_imports(imports, all_imports);
this->write_imported_init_fns(package_name, import_init_fn,
imported_init_fns);
void
Export::write_imports(const std::map<std::string, Package*>& imports,
- const Unordered_set(const Package*)& type_imports)
+ const Unordered_set(const Package*)& all_imports)
{
// Sort the imports for more consistent output.
Unordered_set(const Package*) seen;
// Write out a separate list of indirectly imported packages.
std::vector<const Package*> indirect_imports;
for (Unordered_set(const Package*)::const_iterator p =
- type_imports.begin();
- p != type_imports.end();
+ all_imports.begin();
+ p != all_imports.end();
++p)
{
if (seen.find(*p) == seen.end())
return gogo->backend()->convert_expression(btype, bexpr, this->location());
}
+// The cost of inlining a function reference.
+
+int
+Func_expression::do_inlining_cost() const
+{
+ // FIXME: We don't inline references to nested functions.
+ if (this->closure_ != NULL)
+ return 0x100000;
+ if (this->function_->is_function()
+ && this->function_->func_value()->enclosing() != NULL)
+ return 0x100000;
+
+ return 1;
+}
+
+// Export a reference to a function.
+
+void
+Func_expression::do_export(Export_function_body* efb) const
+{
+ Expression::export_name(efb, this->function_);
+}
+
// Ast dump for function.
void
Builtin_call_expression::do_export(Export_function_body* efb) const
{
Numeric_constant nc;
- if (!this->numeric_constant_value(&nc))
+ if (this->numeric_constant_value(&nc))
{
- go_error_at(this->location(), "value is not constant");
- return;
- }
+ if (nc.is_int())
+ {
+ mpz_t val;
+ nc.get_int(&val);
+ Integer_expression::export_integer(efb, val);
+ mpz_clear(val);
+ }
+ else if (nc.is_float())
+ {
+ mpfr_t fval;
+ nc.get_float(&fval);
+ Float_expression::export_float(efb, fval);
+ mpfr_clear(fval);
+ }
+ else if (nc.is_complex())
+ {
+ mpc_t cval;
+ nc.get_complex(&cval);
+ Complex_expression::export_complex(efb, cval);
+ mpc_clear(cval);
+ }
+ else
+ go_unreachable();
- if (nc.is_int())
- {
- mpz_t val;
- nc.get_int(&val);
- Integer_expression::export_integer(efb, val);
- mpz_clear(val);
+ // A trailing space lets us reliably identify the end of the number.
+ efb->write_c_string(" ");
}
- else if (nc.is_float())
- {
- mpfr_t fval;
- nc.get_float(&fval);
- Float_expression::export_float(efb, fval);
- mpfr_clear(fval);
- }
- else if (nc.is_complex())
+ else
{
- mpc_t cval;
- nc.get_complex(&cval);
- Complex_expression::export_complex(efb, cval);
- mpc_clear(cval);
+ const char *s = NULL;
+ switch (this->code_)
+ {
+ default:
+ go_unreachable();
+ case BUILTIN_APPEND:
+ s = "append";
+ break;
+ case BUILTIN_COPY:
+ s = "copy";
+ break;
+ case BUILTIN_LEN:
+ s = "len";
+ break;
+ case BUILTIN_CAP:
+ s = "cap";
+ break;
+ case BUILTIN_PRINT:
+ s = "print";
+ break;
+ case BUILTIN_PRINTLN:
+ s = "println";
+ break;
+ case BUILTIN_PANIC:
+ s = "panic";
+ break;
+ case BUILTIN_RECOVER:
+ s = "recover";
+ break;
+ case BUILTIN_CLOSE:
+ s = "close";
+ break;
+ case BUILTIN_REAL:
+ s = "real";
+ break;
+ case BUILTIN_IMAG:
+ s = "imag";
+ break;
+ case BUILTIN_COMPLEX:
+ s = "complex";
+ break;
+ }
+ efb->write_c_string(s);
+ this->export_arguments(efb);
}
- else
- go_unreachable();
-
- // A trailing space lets us reliably identify the end of the number.
- efb->write_c_string(" ");
}
// Class Call_expression.
return this->call_;
}
-// Dump ast representation for a call expressin.
+// The cost of inlining a call expression.
+
+int
+Call_expression::do_inlining_cost() const
+{
+ Func_expression* fn = this->fn_->func_expression();
+
+ // FIXME: We don't yet support all kinds of calls.
+ if (fn != NULL && fn->closure() != NULL)
+ return 0x100000;
+ if (this->fn_->interface_field_reference_expression())
+ return 0x100000;
+ if (this->get_function_type()->is_method())
+ return 0x100000;
+
+ return 5;
+}
+
+// Export a call expression.
+
+void
+Call_expression::do_export(Export_function_body* efb) const
+{
+ this->fn_->export_expression(efb);
+ this->export_arguments(efb);
+}
+
+// Export call expression arguments.
+
+void
+Call_expression::export_arguments(Export_function_body* efb) const
+{
+ efb->write_c_string("(");
+ if (this->args_ != NULL && !this->args_->empty())
+ {
+ Expression_list::const_iterator pa = this->args_->begin();
+ (*pa)->export_expression(efb);
+ for (pa++; pa != this->args_->end(); pa++)
+ {
+ efb->write_c_string(", ");
+ (*pa)->export_expression(efb);
+ }
+ if (this->is_varargs_)
+ efb->write_c_string("...");
+ }
+ efb->write_c_string(")");
+}
+
+// Dump ast representation for a call expression.
void
Call_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const
Expression*
Expression::import_expression(Import_expression* imp, Location loc)
+{
+ Expression* expr = Expression::import_expression_without_suffix(imp, loc);
+ while (true)
+ {
+ if (imp->match_c_string("("))
+ {
+ imp->advance(1);
+ Expression_list* args = new Expression_list();
+ bool is_varargs = false;
+ while (!imp->match_c_string(")"))
+ {
+ Expression* arg = Expression::import_expression(imp, loc);
+ if (arg->is_error_expression())
+ return arg;
+ args->push_back(arg);
+ if (imp->match_c_string(")"))
+ break;
+ else if (imp->match_c_string("...)"))
+ {
+ imp->advance(3);
+ is_varargs = true;
+ break;
+ }
+ imp->require_c_string(", ");
+ }
+ imp->require_c_string(")");
+ expr = Expression::make_call(expr, args, is_varargs, loc);
+ }
+ else
+ break;
+ }
+
+ return expr;
+}
+
+// Import an expression without considering a suffix (function
+// arguments, index operations, etc.).
+
+Expression*
+Expression::import_expression_without_suffix(Import_expression* imp,
+ Location loc)
{
int c = imp->peek_char();
if (c == '+' || c == '-' || c == '!' || c == '^' || c == '&' || c == '*')
return Expression::make_error(loc);
}
- return Expression::make_var_reference(no, loc);
+ if (no->is_variable() || no->is_result_variable())
+ return Expression::make_var_reference(no, loc);
+ else if (no->is_function() || no->is_function_declaration())
+ return Expression::make_func_reference(no, NULL, loc);
+ else
+ {
+ if (!ifb->saw_error())
+ go_error_at(ifb->location(),
+ ("import error for %qs: "
+ "unexpected type of identifier %qs (%d)"),
+ ifb->name().c_str(),
+ id.c_str(), no->classification());
+ ifb->set_saw_error();
+ return Expression::make_error(loc);
+ }
}
// Class Expression_list.
static Expression*
import_identifier(Import_function_body*, Location);
+ static Expression*
+ import_expression_without_suffix(Import_expression*, Location);
+
// The expression classification.
Expression_classification classification_;
// The location in the input file.
virtual Bexpression*
do_get_backend(Translate_context*);
+ int
+ do_inlining_cost() const;
+
+ void
+ do_export(Export_function_body*) const;
+
virtual bool
do_is_recover_call() const;
bool
determining_types();
+ void
+ export_arguments(Export_function_body*) const;
+
void
do_dump_expression(Ast_dump_context*) const;
Bexpression*
do_get_backend(Translate_context*);
+ int
+ do_inlining_cost() const
+ { return 1; }
+
void
do_export(Export_function_body*) const;
Bexpression*
do_get_backend(Translate_context*);
+ int
+ do_inlining_cost() const;
+
+ void
+ do_export(Export_function_body*) const;
+
void
do_dump_expression(Ast_dump_context*) const;
void
Gogo::do_exports()
{
+ if (saw_errors())
+ return;
+
// Mark any functions whose body should be exported for inlining by
// other packages.
Mark_inline_candidates mic;
block = this->block_;
Function::export_func_with_type(exp, no, this->type_, this->results_,
this->is_method() && this->nointerface(),
- block, this->location_);
+ this->asm_name(), block, this->location_);
}
// Export a function with a type.
Function::export_func_with_type(Export* exp, const Named_object* no,
const Function_type* fntype,
Function::Results* result_vars,
- bool nointerface, Block* block, Location loc)
+ bool nointerface, const std::string& asm_name,
+ Block* block, Location loc)
{
exp->write_c_string("func ");
exp->write_c_string("/*nointerface*/ ");
}
+ if (!asm_name.empty())
+ {
+ exp->write_c_string("/*asm ");
+ exp->write_string(asm_name);
+ exp->write_c_string(" */ ");
+ }
+
if (fntype->is_method())
{
exp->write_c_string("(");
Typed_identifier_list** presults,
bool* is_varargs,
bool* nointerface,
+ std::string* asm_name,
std::string* body)
{
imp->require_c_string("func ");
*nointerface = false;
- if (imp->match_c_string("/*"))
+ while (imp->match_c_string("/*"))
{
- imp->require_c_string("/*nointerface*/ ");
- *nointerface = true;
+ imp->advance(2);
+ if (imp->match_c_string("nointerface"))
+ {
+ imp->require_c_string("nointerface*/ ");
+ *nointerface = true;
+ }
+ else if (imp->match_c_string("asm"))
+ {
+ imp->require_c_string("asm ");
+ *asm_name = imp->read_identifier();
+ imp->require_c_string(" */ ");
+ }
+ else
+ {
+ go_error_at(imp->location(),
+ "import error at %d: unrecognized function comment",
+ imp->pos());
+ return false;
+ }
+ }
+ if (*nointerface)
+ {
// Only a method can be nointerface.
go_assert(imp->peek_char() == '(');
}
Named_type* rtype = fntype->receiver()->type()->deref()->named_type();
go_assert(rtype != NULL);
no = rtype->add_method(no->name(), fn);
+ const Package* package = rtype->named_object()->package();
+ package->bindings()->add_method(no);
}
Import_function_body ifb(gogo, this->imp_, no, body, nl + 1, outer, indent);
static void
export_func_with_type(Export*, const Named_object*,
const Function_type*, Results*, bool nointerface,
- Block* block, Location);
+ const std::string& asm_name, Block* block, Location);
// Import a function. Reports whether the import succeeded.
static bool
bool* is_exported, Typed_identifier** receiver,
Typed_identifier_list** pparameters,
Typed_identifier_list** presults, bool* is_varargs,
- bool* nointerface, std::string* body);
+ bool* nointerface, std::string* asm_name, std::string* body);
private:
// Type for mapping from label names to Label objects.
{
Function::export_func_with_type(exp, no, this->fntype_, NULL,
this->is_method() && this->nointerface(),
- NULL, this->location_);
+ this->asm_name_, NULL, this->location_);
}
// Check that the types used in this declaration's signature are defined.
Typed_identifier_list* results;
bool is_varargs;
bool nointerface;
+ std::string asm_name;
std::string body;
if (!Function::import_func(this, &name, &fpkg, &is_exported, &receiver,
¶meters, &results, &is_varargs, &nointerface,
- &body))
+ &asm_name, &body))
return;
if (fpkg == NULL)
fpkg = package;
else
{
no = fpkg->add_function_declaration(name, fntype, loc);
- if (this->add_to_globals_)
+ if (this->add_to_globals_ && fpkg == package)
this->gogo_->add_dot_import_object(no);
}
if (nointerface)
no->func_declaration_value()->set_nointerface();
+ if (!asm_name.empty())
+ no->func_declaration_value()->set_asm_name(asm_name);
if (!body.empty() && !no->func_declaration_value()->has_imported_body())
no->func_declaration_value()->set_imported_body(this, body);
}
this->builtin_types_[index] = named_object->type_value();
}
+// Characters that stop read_identifier. We base this on the
+// characters that stop an identifier, without worrying about
+// characters that are permitted in an identifier. That lets us skip
+// UTF-8 parsing.
+static const char * const identifier_stop = " \n;,()[]";
+
// Read an identifier from the stream.
std::string
while (true)
{
c = stream->peek_char();
- if (c == -1 || c == ' ' || c == '\n' || c == ';' || c == ')')
+ if (c == -1 || strchr(identifier_stop, c) != NULL)
break;
+
+ // FIXME: Probably we shouldn't accept '.', but that might break
+ // some existing imports.
+ if (c == '.' && stream->match_c_string("..."))
+ break;
+
ret += c;
stream->advance(1);
}
for (size_t i = start; i < this->body_.length(); i++)
{
int c = static_cast<unsigned char>(this->body_[i]);
- if (c == ' ' || c == '\n' || c == ';' || c == ')')
+ if (strchr(identifier_stop, c) != NULL)
+ {
+ this->off_ = i;
+ return this->body_.substr(start, i - start);
+ }
+
+ // FIXME: Probably we shouldn't accept '.', but that might break
+ // some existing imports.
+ if (c == '.'
+ && i + 2 < this->body_.length()
+ && this->body_[i + 1] == '.'
+ && this->body_[i + 2] == '.')
{
this->off_ = i;
return this->body_.substr(start, i - start);
for p.tok == scanner.Ident {
p.expectKeyword("func")
if p.tok == '/' {
- // Skip a /*nointerface*/ comment.
+ // Skip a /*nointerface*/ or /*asm ID */ comment.
p.expect('/')
p.expect('*')
- p.expect(scanner.Ident)
+ if p.expect(scanner.Ident) == "asm" {
+ p.parseUnquotedString()
+ }
p.expect('*')
p.expect('/')
}
// Func = Name FunctionType [InlineBody] .
func (p *parser) parseFunc(pkg *types.Package) *types.Func {
+ if p.tok == '/' {
+ // Skip an /*asm ID */ comment.
+ p.expect('/')
+ p.expect('*')
+ if p.expect(scanner.Ident) == "asm" {
+ p.parseUnquotedString()
+ }
+ p.expect('*')
+ p.expect('/')
+ }
+
name := p.parseName()
if strings.ContainsRune(name, '$') {
// This is a Type$equal or Type$hash function, which we don't want to parse,