// export.h -- Export declarations in Go frontend. -*- C++ -*- // 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. #ifndef GO_EXPORT_H #define GO_EXPORT_H #include "string-dump.h" class Go_sha1_helper; class Gogo; class Named_object; class Export_function_body; class Import_init; class Named_object; class Bindings; class Type; class Package; class Import_init_set; class Backend; class Temporary_statement; class Unnamed_label; struct Export_impl; // Codes used for the builtin types. These are all negative to make // them easily distinct from the codes assigned by Export::write_type. // Note that these codes may not be changed! Changing them would // break existing export data. enum Builtin_code { BUILTIN_INT8 = -1, BUILTIN_INT16 = -2, BUILTIN_INT32 = -3, BUILTIN_INT64 = -4, BUILTIN_UINT8 = -5, BUILTIN_UINT16 = -6, BUILTIN_UINT32 = -7, BUILTIN_UINT64 = -8, BUILTIN_FLOAT32 = -9, BUILTIN_FLOAT64 = -10, BUILTIN_INT = -11, BUILTIN_UINT = -12, BUILTIN_UINTPTR = -13, BUILTIN_BOOL = -15, BUILTIN_STRING = -16, BUILTIN_COMPLEX64 = -17, BUILTIN_COMPLEX128 = -18, BUILTIN_ERROR = -19, BUILTIN_BYTE = -20, BUILTIN_RUNE = -21, SMALLEST_BUILTIN_CODE = -21 }; // Export data version number. New export data is written with the // "current" version, but there is support for reading files with // older version export data (at least for now). enum Export_data_version { EXPORT_FORMAT_UNKNOWN = 0, EXPORT_FORMAT_V1 = 1, EXPORT_FORMAT_V2 = 2, EXPORT_FORMAT_V3 = 3, EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V3 }; // This class manages exporting Go declarations. It handles the main // loop of exporting. A pointer to this class is also passed to the // various specific export implementations. class Export : public String_dump { public: // The Stream class is an interface used to output the exported // information. The caller should instantiate a child of this // class. class Stream { public: Stream(); virtual ~Stream(); // Write a string. Implements the String_dump interface. void write_string(const std::string& s) { this->write_and_sum_bytes(s.data(), s.length()); } // Write a nul terminated string. Implements the String_dump interface. void write_c_string(const char* s) { this->write_and_sum_bytes(s, strlen(s)); } // Write some bytes. void write_bytes(const char* bytes, size_t length) { this->write_and_sum_bytes(bytes, length); } // Return the raw bytes of the checksum data. std::string checksum(); // Write a checksum string to the stream. This will be called at // the end of the other output. void write_checksum(const std::string&); protected: // This function is called with data to export. This data must be // made available as a contiguous stream for the importer. virtual void do_write(const char* bytes, size_t length) = 0; private: void write_and_sum_bytes(const char*, size_t); // The checksum helper. Go_sha1_helper* sha1_helper_; }; Export(Stream*); ~Export(); // Size of export data magic string (which includes version number). static const int magic_len = 4; // Magic strings (current version and older versions). static const char cur_magic[magic_len]; static const char v1_magic[magic_len]; static const char v2_magic[magic_len]; // The length of the checksum string. static const int checksum_len = 20; // Register the builtin types. void register_builtin_types(Gogo*); // Export the identifiers in BINDINGS which are marked for export. // The exporting is done via a series of calls to THIS->STREAM_. If // is nothing to export, this->stream_->write will not be called. // PREFIX is the package prefix. PKGPATH is the package path. // Only one of PREFIX and PKGPATH will be non-empty. // PACKAGES is all the packages we have seen. // IMPORTS is the explicitly imported packages. // IMPORT_INIT_FN is the name of the import initialization function // for this package; it will be empty if none is needed. // IMPORTED_INIT_FNS is the list of initialization functions for // imported packages. void export_globals(const std::string& package_name, const std::string& prefix, const std::string& pkgpath, const std::map& packages, const std::map& imports, const std::string& import_init_fn, const Import_init_set& imported_init_fns, const Bindings* bindings, Unordered_set(Named_object*)* marked_inline_functions); // Record a type that is mentioned in export data. Return value is // TRUE for newly visited types, FALSE for types that have been seen // previously. bool record_type(Type*); // Assign type indices to types mentioned in export data. int assign_type_indices(const std::vector& sorted_exports); // Write a string to the export stream. void write_string(const std::string& s) { this->stream_->write_string(s); } // Write a nul terminated string to the export stream. void write_c_string(const char* s) { this->stream_->write_c_string(s); } // Write some bytes to the export stream. void write_bytes(const char* bytes, size_t length) { this->stream_->write_bytes(bytes, length); } // Write a name to the export stream. If NAME is empty, write "?". void write_name(const std::string& name); // Write out a type. This handles references back to previous // definitions. void write_type(const Type*); // Write a type to an exported function body. void write_type_to(const Type*, Export_function_body*); // Write the escape note to the export stream. If NOTE is NULL, write // nothing. void write_escape(std::string* note); // Write an integer value. void write_int(int); // Write an unsigned value. void write_unsigned(unsigned); // Return the index of a package. int package_index(const Package* p) const; // Return the index of the "unsafe" package, which must be one of // the exported packages. int unsafe_package_index() const; private: Export(const Export&); Export& operator=(const Export&); // Write out all known packages. void write_packages(const std::map& packages); typedef std::map > Init_graph; static void add_init_graph_edge(Init_graph* init_graph, unsigned src, unsigned sink); static void populate_init_graph(Init_graph* init_graph, const Import_init_set& imported_init_fns, const std::map& init_idx); // Write out the imported packages. void write_imports(const std::map& imports, const Unordered_set(const Package*)& type_imports); // Write out the imported initialization functions and init graph. void write_imported_init_fns(const std::string& package_name, const std::string&, const Import_init_set&); // Write out all types. void write_types(int unexported_type_index); // Write out one type definition. void write_type_definition(const Type* type, int index); // Register one builtin type. void register_builtin_type(Gogo*, const char* name, Builtin_code); // Return the index of a type in the export data. int type_index(const Type*); // Set the index of a type. void set_type_index(const Type*); // The stream to which we are writing data. Stream* stream_; // Index number of next type. int type_index_; // Packages we have written out. Unordered_map(const Package*, int) packages_; // Hidden implementation-specific state. Export_impl* impl_; }; // An export streamer that puts the export stream in a named section. class Stream_to_section : public Export::Stream { public: Stream_to_section(Backend*); protected: void do_write(const char*, size_t); private: Backend* backend_; }; // An export streamer that puts the export stream in a string. class Stream_to_string : public Export::Stream { public: Stream_to_string() : string_() {} const std::string& string() const { return this->string_; } protected: void do_write(const char* s, size_t len) { this->string_.append(s, len); } private: std::string string_; }; // Class to manage exporting a function body. This is passed around // to Statements and Expressions. It builds up the export data for // the function. class Export_function_body : public String_dump { public: Export_function_body(Export* exp, int indent) : exp_(exp), body_(), type_context_(NULL), next_temporary_index_(0), temporary_indexes_(), next_label_index_(0), label_indexes_(), indent_(indent) { } // Write a character to the body. void write_char(char c) { this->body_.append(1, c); } // Write a NUL terminated string to the body. void write_c_string(const char* str) { this->body_.append(str); } // Write a string to the body. void write_string(const std::string& str) { this->body_.append(str); } // Write a type reference to the body. void write_type(const Type* type) { this->exp_->write_type_to(type, this); } // Return the current type context. Type* type_context() const { return this->type_context_; } // Set the current type context. void set_type_context(Type* type) { this->type_context_ = type; } // Append as many spaces as the current indentation level. void indent() { for (int i = this->indent_; i > 0; i--) this->write_char(' '); } // Increment the indentation level. void increment_indent() { ++this->indent_; } // Decrement the indentation level. void decrement_indent() { --this->indent_; } // Return the index of a package. int package_index(const Package* p) const { return this->exp_->package_index(p); } // Return the index of the "unsafe" package. int unsafe_package_index() const { return this->exp_->unsafe_package_index(); } // Record a temporary statement and return its index. unsigned int record_temporary(const Temporary_statement*); // Return the index of a temporary statement. unsigned int temporary_index(const Temporary_statement*); // Return the index of an unnamed label. If it doesn't already have // an index, give it one. unsigned int unnamed_label_index(const Unnamed_label*); // Return a reference to the completed body. const std::string& body() const { return this->body_; } private: // The overall export data. Export* exp_; // The body we are building. std::string body_; // Current type context. Used to avoid duplicate type conversions. Type* type_context_; // Index to give to next temporary statement. unsigned int next_temporary_index_; // Map temporary statements to indexes. Unordered_map(const Temporary_statement*, unsigned int) temporary_indexes_; // Index to give to the next unnamed label. unsigned int next_label_index_; // Map unnamed labels to indexes. Unordered_map(const Unnamed_label*, unsigned int) label_indexes_; // Current indentation level: the number of spaces before each statement. int indent_; }; #endif // !defined(GO_EXPORT_H)