mirror of
https://github.com/golang/go
synced 2024-11-14 14:30:23 -07:00
839a68469b
TBR=r OCL=23121 CL=23127
295 lines
5.4 KiB
Go
Executable File
295 lines
5.4 KiB
Go
Executable File
// 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 Exporter
|
|
|
|
import Platform "platform"
|
|
import Utils "utils"
|
|
import Globals "globals"
|
|
import Object "object"
|
|
import Type "type"
|
|
import Universe "universe"
|
|
|
|
|
|
type Exporter struct {
|
|
comp *Globals.Compilation;
|
|
debug bool;
|
|
buf [4*1024] byte;
|
|
buf_pos int;
|
|
pkg_ref int;
|
|
type_ref int;
|
|
};
|
|
|
|
|
|
func (E *Exporter) WriteObject(obj *Globals.Object);
|
|
|
|
|
|
func (E *Exporter) WriteByte(x byte) {
|
|
E.buf[E.buf_pos] = x;
|
|
E.buf_pos++;
|
|
/*
|
|
if E.debug {
|
|
print(" ", x);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteInt(x int) {
|
|
x0 := x;
|
|
for x < -64 || x >= 64 {
|
|
E.WriteByte(byte(x & 127));
|
|
x = int(uint(x >> 7)); // arithmetic shift
|
|
}
|
|
// -64 <= x && x < 64
|
|
E.WriteByte(byte(x + 192));
|
|
/*
|
|
if E.debug {
|
|
print(" #", x0);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteString(s string) {
|
|
n := len(s);
|
|
E.WriteInt(n);
|
|
for i := 0; i < n; i++ {
|
|
E.WriteByte(s[i]);
|
|
}
|
|
if E.debug {
|
|
print(` "`, s, `"`);
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WritePackageTag(tag int) {
|
|
E.WriteInt(tag);
|
|
if E.debug {
|
|
if tag >= 0 {
|
|
print(" [P", tag, "]"); // package ref
|
|
} else {
|
|
print("\nP", E.pkg_ref, ":");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteTypeTag(tag int) {
|
|
E.WriteInt(tag);
|
|
if E.debug {
|
|
if tag >= 0 {
|
|
print(" [T", tag, "]"); // type ref
|
|
} else {
|
|
print("\nT", E.type_ref, ": ", Type.FormStr(-tag));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteObjectTag(tag int) {
|
|
if tag < 0 {
|
|
panic("tag < 0");
|
|
}
|
|
E.WriteInt(tag);
|
|
if E.debug {
|
|
print("\n", Object.KindStr(tag));
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WritePackage(pkg *Globals.Package) {
|
|
if E.comp.pkg_list[pkg.obj.pnolev] != pkg {
|
|
panic("inconsistent package object");
|
|
}
|
|
|
|
if pkg.ref >= 0 {
|
|
E.WritePackageTag(pkg.ref); // package already exported
|
|
return;
|
|
}
|
|
|
|
E.WritePackageTag(-1);
|
|
pkg.ref = E.pkg_ref;
|
|
E.pkg_ref++;
|
|
|
|
E.WriteString(pkg.obj.ident);
|
|
E.WriteString(pkg.file_name);
|
|
E.WriteString(pkg.key);
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteScope(scope *Globals.Scope) {
|
|
if E.debug {
|
|
print(" {");
|
|
}
|
|
|
|
for p := scope.entries.first; p != nil; p = p.next {
|
|
if p.obj.exported {
|
|
E.WriteObject(p.obj);
|
|
}
|
|
}
|
|
E.WriteObject(nil);
|
|
|
|
if E.debug {
|
|
print(" }");
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteType(typ *Globals.Type) {
|
|
if typ.ref >= 0 {
|
|
E.WriteTypeTag(typ.ref); // type already exported
|
|
return;
|
|
}
|
|
|
|
if -typ.form >= 0 {
|
|
panic("conflict with ref numbers");
|
|
}
|
|
E.WriteTypeTag(-typ.form);
|
|
typ.ref = E.type_ref;
|
|
E.type_ref++;
|
|
|
|
// if we have a named type, export the type identifier and package
|
|
ident := "";
|
|
if typ.obj != nil {
|
|
// named type
|
|
if typ.obj.typ != typ {
|
|
panic("inconsistent named type");
|
|
}
|
|
ident = typ.obj.ident;
|
|
if !typ.obj.exported {
|
|
// the type is invisible (it's identifier is not exported)
|
|
// prepend "." to the identifier to make it an illegal
|
|
// identifier for importing packages and thus inaccessible
|
|
// from those package's source code
|
|
ident = "." + ident;
|
|
}
|
|
}
|
|
|
|
E.WriteString(ident);
|
|
if len(ident) > 0 {
|
|
// named type
|
|
E.WritePackage(E.comp.pkg_list[typ.obj.pnolev]);
|
|
}
|
|
|
|
switch typ.form {
|
|
case Type.VOID:
|
|
// for now until we have enough of the front-end working.
|
|
|
|
case Type.FORWARD:
|
|
// corresponding package must be forward-declared too
|
|
if typ.obj == nil || E.comp.pkg_list[typ.obj.pnolev].key != "" {
|
|
panic("inconsistency in package.type forward declaration");
|
|
}
|
|
|
|
case Type.ALIAS, Type.MAP:
|
|
E.WriteType(typ.key);
|
|
E.WriteType(typ.elt);
|
|
|
|
case Type.TUPLE:
|
|
E.WriteType(typ.elt);
|
|
|
|
case Type.ARRAY:
|
|
E.WriteInt(typ.len);
|
|
E.WriteType(typ.elt);
|
|
|
|
case Type.CHANNEL:
|
|
E.WriteInt(typ.aux);
|
|
E.WriteType(typ.elt);
|
|
|
|
case Type.FUNCTION, Type.METHOD:
|
|
E.WriteInt(typ.len);
|
|
E.WriteType(typ.elt);
|
|
E.WriteScope(typ.scope);
|
|
|
|
case Type.STRUCT, Type.INTERFACE:
|
|
E.WriteScope(typ.scope);
|
|
|
|
case Type.POINTER:
|
|
E.WriteType(typ.elt);
|
|
|
|
default:
|
|
panic("UNREACHABLE");
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) WriteObject(obj *Globals.Object) {
|
|
if obj == nil {
|
|
E.WriteObjectTag(Object.END);
|
|
return;
|
|
}
|
|
E.WriteObjectTag(obj.kind);
|
|
|
|
if obj.kind == Object.TYPE {
|
|
// named types are handled entirely by WriteType()
|
|
if obj.typ.obj != obj {
|
|
panic("inconsistent named type");
|
|
}
|
|
E.WriteType(obj.typ);
|
|
return;
|
|
}
|
|
|
|
E.WriteString(obj.ident);
|
|
E.WriteType(obj.typ);
|
|
|
|
switch obj.kind {
|
|
case Object.CONST:
|
|
E.WriteInt(0); // should be the correct value
|
|
|
|
case Object.VAR, Object.FIELD:
|
|
E.WriteInt(0); // should be the correct address/offset
|
|
|
|
case Object.FUNC:
|
|
E.WriteInt(0); // should be the correct address/offset
|
|
|
|
default:
|
|
panic("UNREACHABLE");
|
|
}
|
|
}
|
|
|
|
|
|
func (E *Exporter) Export(comp* Globals.Compilation) string {
|
|
E.comp = comp;
|
|
E.debug = comp.flags.debug;
|
|
E.buf_pos = 0;
|
|
E.pkg_ref = 0;
|
|
E.type_ref = 0;
|
|
|
|
// write magic bits
|
|
magic := Platform.MAGIC_obj_file; // TODO remove once len(constant) works
|
|
for i := 0; i < len(magic); i++ {
|
|
E.WriteByte(magic[i]);
|
|
}
|
|
|
|
// Predeclared types are "pre-exported".
|
|
// TODO run the loop below only in debug mode
|
|
{ i := 0;
|
|
for p := Universe.types.first; p != nil; p = p.next {
|
|
if p.typ.ref != i {
|
|
panic("incorrect ref for predeclared type");
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
E.type_ref = Universe.types.len;
|
|
|
|
// export package 0
|
|
pkg := comp.pkg_list[0];
|
|
E.WritePackage(pkg);
|
|
E.WriteScope(pkg.scope);
|
|
|
|
if E.debug {
|
|
print("\n(", E.buf_pos, " bytes)\n");
|
|
}
|
|
|
|
return string(E.buf)[0 : E.buf_pos];
|
|
}
|
|
|
|
|
|
func Export(comp* Globals.Compilation) string {
|
|
var E Exporter;
|
|
return (&E).Export(comp);
|
|
}
|