aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/pickling/TreeBuffer.scala
blob: 5a445124d3ce1280adac3b7c89003156ce4d6f31 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package dotty.tools
package dotc
package core
package pickling

import util.Util.{bestFit, dble}
import TastyBuffer.{Addr, AddrWidth}

class TreeBuffer extends TastyBuffer(1000000) {

  private final val ItemsOverOffsets = 2
    
  private val initialOffsetSize = bytes.length / (AddrWidth * ItemsOverOffsets)
  private var offsets = new Array[Int](initialOffsetSize)
  private var isRelative = new Array[Boolean](initialOffsetSize)
  private var delta: Array[Int] = _
  private var numOffsets = 0
            
  private def offset(i: Int): Addr = new Addr(offsets(i))

  private def keepOffset(relative: Boolean): Unit = {
    if (numOffsets == offsets.length) {
      offsets = dble(offsets)
      isRelative = dble(isRelative)
    }
    offsets(numOffsets) = length
    isRelative(numOffsets) = relative
    numOffsets += 1
  }
       
  def reserveRef(relative: Boolean): Addr = {
    val addr = currentAddr
    keepOffset(relative)
    reserveAddr()
    addr
  }

  def writeRef(target: Addr) = {
    keepOffset(relative = false)
    writeNat(target.index)
  }
  
  def fillRef(at: Addr, target: Addr, relative: Boolean) = {
    val addr = if (relative) target.relativeTo(at) else target
    fillAddr(at, addr)
  }
    
  def adjusted(x: Addr): Addr = {
    val idx = bestFit(offsets, x.index - 1)
    if (idx < 0) x else x - delta(idx)
  }

  private def computeDeltas() = {
    delta = new Array[Int](numOffsets)
    var lastDelta = 0
    var i = 0
    while (i < numOffsets) {
      val off = offset(i)
      val skippedOff = skipZeroes(off)
      val skippedCount = skippedOff.index - off.index
      assert(skippedCount < AddrWidth, s"unset field at position $off")
      lastDelta += skippedCount
      delta(i) = lastDelta 
      i += 1
    }
  }
  
  private def adjustedOffset(at: Addr, isRelative: Boolean): Addr = {
    val original = getAddr(at)
    if (isRelative) {
      val start = skipNat(at).index
      adjusted(original + start) - start
    } else adjusted(original)
  }
  
  private def adjustOffsets(): Unit = {
    for (i <- 0 until numOffsets) {
      val off = offset(i)
      val original = getAddr(off)
      val corrected = adjustedOffset(off, isRelative(i))
      fillAddr(off, corrected)
    }
  }
    
  private def adjustDeltas(): Int = {
    val delta1 = new Array[Int](delta.length)
    var lastDelta = 0
    var i = 0
    while (i < numOffsets) {
      val corrected = adjustedOffset(offset(i), isRelative(i))
      lastDelta += AddrWidth - TastyBuffer.natSize(corrected.index)
      delta1(i) = lastDelta
      i += 1
    }
    val saved = 
      if (numOffsets == 0) 0
      else delta1(numOffsets - 1) - delta(numOffsets - 1)
    delta = delta1
    saved
  }
    
  private def compress(): Int = {
    var lastDelta = 0
    var start = 0
    var i = 0
    var wasted = 0
    while (i < numOffsets) {
      val next = offsets(i)
      Array.copy(bytes, start, bytes, start - lastDelta, next - start)
      start = next + delta(i) - lastDelta
      val pastZeroes = skipZeroes(new Addr(next)).index
      assert(pastZeroes >= start, s"something's wrong: eliminated non-zero")
      wasted += (pastZeroes - start)
      lastDelta = delta(i)
      i += 1
    }
    length -= lastDelta
    wasted
  }
  
  override def assemble(): Unit = {
    val origLength = length
    computeDeltas()
    adjustOffsets()
    if (false) {
      var saved = 0
      do saved = adjustDeltas()
      while (saved > 0 && length / saved < 100)
    }
    val wasted = compress()
    println(s"original length: $origLength, compressed to: $length, wasted: $wasted")
  }
}