Source file src/cmd/compile/internal/noder/encoder.go

     1  // UNREVIEWED
     2  
     3  // Copyright 2021 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package noder
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/binary"
    12  	"fmt"
    13  	"go/constant"
    14  	"io"
    15  	"math/big"
    16  	"runtime"
    17  
    18  	"cmd/compile/internal/base"
    19  )
    20  
    21  type pkgEncoder struct {
    22  	elems [numRelocs][]string
    23  
    24  	stringsIdx map[string]int
    25  }
    26  
    27  func newPkgEncoder() pkgEncoder {
    28  	return pkgEncoder{
    29  		stringsIdx: make(map[string]int),
    30  	}
    31  }
    32  
    33  func (pw *pkgEncoder) dump(out io.Writer) {
    34  	writeUint32 := func(x uint32) {
    35  		assert(binary.Write(out, binary.LittleEndian, x) == nil)
    36  	}
    37  
    38  	var sum uint32
    39  	for _, elems := range &pw.elems {
    40  		sum += uint32(len(elems))
    41  		writeUint32(sum)
    42  	}
    43  
    44  	sum = 0
    45  	for _, elems := range &pw.elems {
    46  		for _, elem := range elems {
    47  			sum += uint32(len(elem))
    48  			writeUint32(sum)
    49  		}
    50  	}
    51  
    52  	for _, elems := range &pw.elems {
    53  		for _, elem := range elems {
    54  			_, err := io.WriteString(out, elem)
    55  			assert(err == nil)
    56  		}
    57  	}
    58  }
    59  
    60  func (pw *pkgEncoder) stringIdx(s string) int {
    61  	if idx, ok := pw.stringsIdx[s]; ok {
    62  		assert(pw.elems[relocString][idx] == s)
    63  		return idx
    64  	}
    65  
    66  	idx := len(pw.elems[relocString])
    67  	pw.elems[relocString] = append(pw.elems[relocString], s)
    68  	pw.stringsIdx[s] = idx
    69  	return idx
    70  }
    71  
    72  func (pw *pkgEncoder) newEncoder(k reloc, marker syncMarker) encoder {
    73  	e := pw.newEncoderRaw(k)
    74  	e.sync(marker)
    75  	return e
    76  }
    77  
    78  func (pw *pkgEncoder) newEncoderRaw(k reloc) encoder {
    79  	idx := len(pw.elems[k])
    80  	pw.elems[k] = append(pw.elems[k], "") // placeholder
    81  
    82  	return encoder{
    83  		p:   pw,
    84  		k:   k,
    85  		idx: idx,
    86  	}
    87  }
    88  
    89  // Encoders
    90  
    91  type encoder struct {
    92  	p *pkgEncoder
    93  
    94  	relocs []relocEnt
    95  	data   bytes.Buffer
    96  
    97  	encodingRelocHeader bool
    98  
    99  	k   reloc
   100  	idx int
   101  }
   102  
   103  func (w *encoder) flush() int {
   104  	var sb bytes.Buffer // TODO(mdempsky): strings.Builder after #44505 is resolved
   105  
   106  	// Backup the data so we write the relocations at the front.
   107  	var tmp bytes.Buffer
   108  	io.Copy(&tmp, &w.data)
   109  
   110  	// TODO(mdempsky): Consider writing these out separately so they're
   111  	// easier to strip, along with function bodies, so that we can prune
   112  	// down to just the data that's relevant to go/types.
   113  	if w.encodingRelocHeader {
   114  		base.Fatalf("encodingRelocHeader already true; recursive flush?")
   115  	}
   116  	w.encodingRelocHeader = true
   117  	w.sync(syncRelocs)
   118  	w.len(len(w.relocs))
   119  	for _, rent := range w.relocs {
   120  		w.sync(syncReloc)
   121  		w.len(int(rent.kind))
   122  		w.len(rent.idx)
   123  	}
   124  
   125  	io.Copy(&sb, &w.data)
   126  	io.Copy(&sb, &tmp)
   127  	w.p.elems[w.k][w.idx] = sb.String()
   128  
   129  	return w.idx
   130  }
   131  
   132  func (w *encoder) checkErr(err error) {
   133  	if err != nil {
   134  		base.Fatalf("unexpected error: %v", err)
   135  	}
   136  }
   137  
   138  func (w *encoder) rawUvarint(x uint64) {
   139  	var buf [binary.MaxVarintLen64]byte
   140  	n := binary.PutUvarint(buf[:], x)
   141  	_, err := w.data.Write(buf[:n])
   142  	w.checkErr(err)
   143  }
   144  
   145  func (w *encoder) rawVarint(x int64) {
   146  	// Zig-zag encode.
   147  	ux := uint64(x) << 1
   148  	if x < 0 {
   149  		ux = ^ux
   150  	}
   151  
   152  	w.rawUvarint(ux)
   153  }
   154  
   155  func (w *encoder) rawReloc(r reloc, idx int) int {
   156  	// TODO(mdempsky): Use map for lookup.
   157  	for i, rent := range w.relocs {
   158  		if rent.kind == r && rent.idx == idx {
   159  			return i
   160  		}
   161  	}
   162  
   163  	i := len(w.relocs)
   164  	w.relocs = append(w.relocs, relocEnt{r, idx})
   165  	return i
   166  }
   167  
   168  func (w *encoder) sync(m syncMarker) {
   169  	if !enableSync {
   170  		return
   171  	}
   172  
   173  	// Writing out stack frame string references requires working
   174  	// relocations, but writing out the relocations themselves involves
   175  	// sync markers. To prevent infinite recursion, we simply trim the
   176  	// stack frame for sync markers within the relocation header.
   177  	var frames []string
   178  	if !w.encodingRelocHeader && base.Debug.SyncFrames > 0 {
   179  		pcs := make([]uintptr, base.Debug.SyncFrames)
   180  		n := runtime.Callers(2, pcs)
   181  		frames = fmtFrames(pcs[:n]...)
   182  	}
   183  
   184  	// TODO(mdempsky): Save space by writing out stack frames as a
   185  	// linked list so we can share common stack frames.
   186  	w.rawUvarint(uint64(m))
   187  	w.rawUvarint(uint64(len(frames)))
   188  	for _, frame := range frames {
   189  		w.rawUvarint(uint64(w.rawReloc(relocString, w.p.stringIdx(frame))))
   190  	}
   191  }
   192  
   193  func (w *encoder) bool(b bool) bool {
   194  	w.sync(syncBool)
   195  	var x byte
   196  	if b {
   197  		x = 1
   198  	}
   199  	err := w.data.WriteByte(x)
   200  	w.checkErr(err)
   201  	return b
   202  }
   203  
   204  func (w *encoder) int64(x int64) {
   205  	w.sync(syncInt64)
   206  	w.rawVarint(x)
   207  }
   208  
   209  func (w *encoder) uint64(x uint64) {
   210  	w.sync(syncUint64)
   211  	w.rawUvarint(x)
   212  }
   213  
   214  func (w *encoder) len(x int)   { assert(x >= 0); w.uint64(uint64(x)) }
   215  func (w *encoder) int(x int)   { w.int64(int64(x)) }
   216  func (w *encoder) uint(x uint) { w.uint64(uint64(x)) }
   217  
   218  func (w *encoder) reloc(r reloc, idx int) {
   219  	w.sync(syncUseReloc)
   220  	w.len(w.rawReloc(r, idx))
   221  }
   222  
   223  func (w *encoder) code(c code) {
   224  	w.sync(c.marker())
   225  	w.len(c.value())
   226  }
   227  
   228  func (w *encoder) string(s string) {
   229  	w.sync(syncString)
   230  	w.reloc(relocString, w.p.stringIdx(s))
   231  }
   232  
   233  func (w *encoder) strings(ss []string) {
   234  	w.len(len(ss))
   235  	for _, s := range ss {
   236  		w.string(s)
   237  	}
   238  }
   239  
   240  func (w *encoder) value(val constant.Value) {
   241  	w.sync(syncValue)
   242  	if w.bool(val.Kind() == constant.Complex) {
   243  		w.scalar(constant.Real(val))
   244  		w.scalar(constant.Imag(val))
   245  	} else {
   246  		w.scalar(val)
   247  	}
   248  }
   249  
   250  func (w *encoder) scalar(val constant.Value) {
   251  	switch v := constant.Val(val).(type) {
   252  	default:
   253  		panic(fmt.Sprintf("unhandled %v (%v)", val, val.Kind()))
   254  	case bool:
   255  		w.code(valBool)
   256  		w.bool(v)
   257  	case string:
   258  		w.code(valString)
   259  		w.string(v)
   260  	case int64:
   261  		w.code(valInt64)
   262  		w.int64(v)
   263  	case *big.Int:
   264  		w.code(valBigInt)
   265  		w.bigInt(v)
   266  	case *big.Rat:
   267  		w.code(valBigRat)
   268  		w.bigInt(v.Num())
   269  		w.bigInt(v.Denom())
   270  	case *big.Float:
   271  		w.code(valBigFloat)
   272  		w.bigFloat(v)
   273  	}
   274  }
   275  
   276  func (w *encoder) bigInt(v *big.Int) {
   277  	b := v.Bytes()
   278  	w.string(string(b)) // TODO: More efficient encoding.
   279  	w.bool(v.Sign() < 0)
   280  }
   281  
   282  func (w *encoder) bigFloat(v *big.Float) {
   283  	b := v.Append(nil, 'p', -1)
   284  	w.string(string(b)) // TODO: More efficient encoding.
   285  }
   286  

View as plain text