scala.scalanative.nir.serialization.BinarySerializer.scala Maven / Gradle / Ivy
The newest version!
package scala.scalanative
package nir
package serialization
import java.nio.ByteBuffer
import java.nio.channels.{WritableByteChannel, Channels}
import java.io.{DataOutputStream, ByteArrayOutputStream, OutputStream}
import scala.collection.mutable
import java.nio.charset.StandardCharsets
import serialization.{Tags => T}
// scalafmt: { maxColumn = 120}
final class BinarySerializer(channel: WritableByteChannel) {
def serialize(defns: Seq[Defn]) = {
// Write to in-memory buffers
for (defn <- defns) {
val offset = Defns.position()
Defns.put(defn)
Offsets.put(defn.name, offset)
}
// Mark the end of offsets
Offsets.put(Global.None, -1)
// Fill header info with buffer positions
Header.put()
// Write prepared data to final output channel
val output = Channels.newOutputStream(channel)
sections.foreach(_.commit(output))
}
private val sections = Seq(Header, Offsets, Strings, Positions, Globals, Types, Defns, Vals, Insts)
private var hasEntryPoints: Boolean = false
private object Header extends NIRSectionWriter(Prelude.length) {
def put(): Unit = {
putInt(Versions.magic)
putInt(Versions.compat)
putInt(Versions.revision)
// All sections without Header (requires fixes size) and last section (Insts)
sections.tail
.foldLeft(Prelude.length) {
case (sectionStart, section) =>
putInt(sectionStart)
sectionStart + section.position()
}
putBool(hasEntryPoints)
}
}
private trait Common { self: NIRSectionWriter =>
def putVal(value: Val): Unit = putLebUnsignedInt(Vals.intern(value))
def putVals(values: Seq[Val]): Unit = putSeq(values)(putVal)
def putLocal(local: Local): Unit = putLebUnsignedLong(local.id)
def putScopeId(scopeId: ScopeId) = putLebUnsignedInt(scopeId.id)
def putGlobal(g: Global): Unit = putLebUnsignedInt(Globals.intern(g))
def putGlobals(gs: Seq[Global]): Unit = putSeq(gs)(putGlobal)
def putGlobalOpt(gopt: Option[Global]): Unit = putOpt(gopt)(putGlobal)
def putSig(sig: Sig): Unit = putString(sig.mangle)
def putType(ty: Type): Unit = putLebUnsignedInt(Types.intern(ty))
def putTypes(tys: Seq[Type]): Unit = putSeq(tys)(putType)
def putString(s: String): Unit = putLebUnsignedInt(Strings.intern(s))
def putPosition(pos: SourcePosition): Unit = putLebUnsignedInt(Positions.intern(pos))
}
private object Offsets extends NIRSectionWriter with Common {
def put(global: Global, defnOffset: Int): Unit = {
putGlobal(global)
putLebSignedInt(defnOffset) // signed due to -1 in the last offset
}
}
private object Strings extends InternedBinarySectionWriter[String] with Common {
override def internDeps(v: String): Unit = ()
override def put(v: String) = {
putSeq(v)(putLebChar)
}
}
private object Positions extends InternedBinarySectionWriter[nir.SourcePosition] with Common {
override def internDeps(pos: nir.SourcePosition): Unit = ()
override def put(pos: nir.SourcePosition): Unit = {
putString {
pos.source match { // interned
case nir.SourceFile.Virtual => ""
case nir.SourceFile.Relative(pathString) => pathString
}
}
putLebUnsignedInt(pos.line)
putLebUnsignedInt(pos.column)
}
}
private object Globals extends InternedBinarySectionWriter[Global] with Common {
override def internDeps(value: Global): Unit = value match {
case Global.Member(n, _) => intern(n)
case _ => ()
}
override def put(value: Global): Unit = value match {
case Global.Member(n, sig) => putTag(T.MemberGlobal); putGlobal(n); putSig(sig)
case Global.Top(id) => putTag(T.TopGlobal); putString(id)
case Global.None => putTag(T.NoneGlobal)
}
}
private object Types extends InternedBinarySectionWriter[Type] with Common {
override def internDeps(ty: Type): Unit = ty match {
case Type.Function(tys, ty) => tys.foreach(intern); intern(ty)
case Type.Array(ty, _) => intern(ty)
case Type.StructValue(tys) => tys.foreach(intern)
case Type.ArrayValue(ty, _) => intern(ty)
case Type.Var(ty) => intern(ty)
case _ => ()
}
override def put(ty: Type): Unit = ty match {
case Type.Function(args, ret) => putTag(T.FunctionType); putTypes(args); putType(ret)
case Type.Ref(n, exact, nullable) => putTag(T.RefType); putGlobal(n); putBool(exact); putBool(nullable)
case Type.Ptr => putTag(T.PtrType)
case Type.Unit => putTag(T.UnitType)
case Type.Array(ty, nullable) => putTag(T.ArrayType); putType(ty); putBool(nullable)
case Type.Bool => putTag(T.BoolType)
case Type.Char => putTag(T.CharType)
case Type.Byte => putTag(T.ByteType)
case Type.Short => putTag(T.ShortType)
case Type.Int => putTag(T.IntType)
case Type.Long => putTag(T.LongType)
case Type.Float => putTag(T.FloatType)
case Type.Double => putTag(T.DoubleType)
case Type.Size => putTag(T.SizeType)
case Type.Null => putTag(T.NullType)
case Type.Nothing => putTag(T.NothingType)
case Type.ArrayValue(ty, n) => putTag(T.ArrayValueType); putType(ty); putLebUnsignedInt(n)
case Type.StructValue(tys) => putTag(T.StructValueType); putTypes(tys)
case Type.Vararg => putTag(T.VarargType)
case Type.Var(ty) => putTag(T.VarType); putType(ty)
case Type.Virtual => putTag(T.VirtualType)
}
}
private object Vals extends InternedBinarySectionWriter[Val] with Common {
override def internDeps(value: Val): Unit = value match {
case Val.Const(v) => intern(v)
case Val.ArrayValue(_, vs) => vs.foreach(intern)
case Val.StructValue(vs) => vs.foreach(intern)
case _ => ()
}
override def put(value: Val): Unit = value match {
case Val.Local(n, ty) => putTag(T.LocalVal); putLocal(n); putType(ty)
case Val.Global(n, ty) => putTag(T.GlobalVal); putGlobal(n); putType(ty)
case Val.Unit => putTag(T.UnitVal)
case Val.Null => putTag(T.NullVal)
case Val.True => putTag(T.TrueVal)
case Val.False => putTag(T.FalseVal)
case Val.Byte(v) => putTag(T.ByteVal); put(v)
case Val.Char(v) => putTag(T.CharVal); putLebChar(v)
case Val.Short(v) => putTag(T.ShortVal); putLebSignedInt(v)
case Val.Int(v) => putTag(T.IntVal); putLebSignedInt(v)
case Val.Long(v) => putTag(T.LongVal); putLebSignedLong(v)
case Val.Float(v) => putTag(T.FloatVal); putFloat(v)
case Val.Double(v) => putTag(T.DoubleVal); putDouble(v)
case Val.String(v) => putTag(T.StringVal); putString(v)
case Val.ByteString(v) => putTag(T.ByteStringVal); putLebUnsignedInt(v.length); put(v)
case Val.Const(v) => putTag(T.ConstVal); putVal(v)
case Val.Size(v) => putTag(T.SizeVal); putLebUnsignedLong(v)
case Val.ClassOf(cls) => putTag(T.ClassOfVal); putGlobal(cls)
case Val.Zero(ty) => putTag(T.ZeroVal); putType(ty)
case Val.ArrayValue(ty, vs) => putTag(T.ArrayValueVal); putType(ty); putVals(vs)
case Val.StructValue(vs) => putTag(T.StructValueVal); putVals(vs)
case Val.Virtual(v) => putTag(T.VirtualVal); putLebUnsignedLong(v)
}
}
private object Defns extends NIRSectionWriter with Common {
private def putAttrs(attrs: Attrs) =
putSeq(attrs.toSeq)(putAttr)
private def putAttr(attr: Attr) = attr match {
case Attr.MayInline => putTag(T.MayInlineAttr)
case Attr.InlineHint => putTag(T.InlineHintAttr)
case Attr.NoInline => putTag(T.NoInlineAttr)
case Attr.AlwaysInline => putTag(T.AlwaysInlineAttr)
case Attr.MaySpecialize => putTag(T.MaySpecialize)
case Attr.NoSpecialize => putTag(T.NoSpecialize)
case Attr.UnOpt => putTag(T.UnOptAttr)
case Attr.NoOpt => putTag(T.NoOptAttr)
case Attr.DidOpt => putTag(T.DidOptAttr)
case Attr.BailOpt(msg) => putTag(T.BailOptAttr); putString(msg)
case Attr.Dyn => putTag(T.DynAttr)
case Attr.Stub => putTag(T.StubAttr)
case Attr.Extern(isBlocking) => putTag(T.ExternAttr); putBool(isBlocking)
case Attr.Link(s) => putTag(T.LinkAttr); putString(s)
case Attr.Define(n) => putTag(T.DefineAttr); putString(n)
case Attr.Abstract => putTag(T.AbstractAttr)
case Attr.Volatile => putTag(T.VolatileAttr)
case Attr.Final => putTag(T.FinalAttr)
case Attr.SafePublish => putTag(T.SafePublishAttr)
case Attr.LinktimeResolved => putTag(T.LinktimeResolvedAttr)
case Attr.UsesIntrinsic => putTag(T.UsesIntrinsicAttr)
case Attr.Alignment(size, group) =>
putTag(T.AlignAttr)
putLebSignedInt(size)
putOpt(group)(putString)
}
private def putInsts(insts: Seq[Inst]): Unit = {
putLebUnsignedInt(Insts.position())
Insts.put(insts)
}
private def putLocalNames(localNames: LocalNames): Unit = {
putLebUnsignedInt(localNames.size)
localNames.foreach {
case (local, localName) =>
putLocal(local)
putString(localName)
}
}
import nir.Defn.Define.DebugInfo
private def putLexicalScope(scope: DebugInfo.LexicalScope): Unit = {
val DebugInfo.LexicalScope(id, parent, srcPosition) = scope
putScopeId(id)
putScopeId(parent)
putPosition(srcPosition)
}
private def putDebugInfo(debugInfo: nir.Defn.Define.DebugInfo): Unit = {
val nir.Defn.Define.DebugInfo(localNames, lexicalScopes) = debugInfo
putLocalNames(localNames)
putSeq(lexicalScopes.sorted)(putLexicalScope)
}
def put(defn: Defn): Unit = {
def putHeader(tag: Byte): Unit = {
putTag(tag)
putGlobal(defn.name)
putAttrs(defn.attrs)
putPosition(defn.pos)
}
hasEntryPoints ||= defn.isEntryPoint
defn match {
case Defn.Define(_, _, ty, insts, debugInfo) =>
putHeader(T.DefineDefn)
putType(ty)
putInsts(insts)
putDebugInfo(debugInfo)
case defn: Defn.Var =>
putHeader(T.VarDefn)
putType(defn.ty)
putVal(defn.rhs)
case defn: Defn.Class =>
putHeader(T.ClassDefn)
putGlobalOpt(defn.parent)
putGlobals(defn.traits)
case defn: Defn.Trait =>
putHeader(T.TraitDefn)
putGlobals(defn.traits)
case defn: Defn.Module =>
putHeader(T.ModuleDefn)
putGlobalOpt(defn.parent)
putGlobals(defn.traits)
case defn: Defn.Declare =>
putHeader(T.DeclareDefn)
putType(defn.ty)
case defn: Defn.Const =>
putHeader(T.ConstDefn)
putType(defn.ty)
putVal(defn.rhs)
}
}
}
private object Insts extends NIRSectionWriter(1024 * 1024) with Common {
private def putBin(bin: Bin) = bin match {
case Bin.Iadd => putTag(T.IaddBin)
case Bin.Isub => putTag(T.IsubBin)
case Bin.Xor => putTag(T.XorBin)
case Bin.And => putTag(T.AndBin)
case Bin.Or => putTag(T.OrBin)
case Bin.Fadd => putTag(T.FaddBin)
case Bin.Fsub => putTag(T.FsubBin)
case Bin.Imul => putTag(T.ImulBin)
case Bin.Fmul => putTag(T.FmulBin)
case Bin.Sdiv => putTag(T.SdivBin)
case Bin.Udiv => putTag(T.UdivBin)
case Bin.Fdiv => putTag(T.FdivBin)
case Bin.Srem => putTag(T.SremBin)
case Bin.Urem => putTag(T.UremBin)
case Bin.Frem => putTag(T.FremBin)
case Bin.Shl => putTag(T.ShlBin)
case Bin.Lshr => putTag(T.LshrBin)
case Bin.Ashr => putTag(T.AshrBin)
}
private def putComp(comp: Comp) = comp match {
case Comp.Ieq => putTag(T.IeqComp)
case Comp.Ine => putTag(T.IneComp)
case Comp.Ugt => putTag(T.UgtComp)
case Comp.Uge => putTag(T.UgeComp)
case Comp.Ult => putTag(T.UltComp)
case Comp.Ule => putTag(T.UleComp)
case Comp.Sgt => putTag(T.SgtComp)
case Comp.Sge => putTag(T.SgeComp)
case Comp.Slt => putTag(T.SltComp)
case Comp.Sle => putTag(T.SleComp)
case Comp.Feq => putTag(T.FeqComp)
case Comp.Fne => putTag(T.FneComp)
case Comp.Fgt => putTag(T.FgtComp)
case Comp.Fge => putTag(T.FgeComp)
case Comp.Flt => putTag(T.FltComp)
case Comp.Fle => putTag(T.FleComp)
}
private def putConv(conv: Conv) = conv match {
case Conv.Bitcast => putTag(T.BitcastConv)
case Conv.SSizeCast => putTag(T.SSizeCastConv)
case Conv.ZSizeCast => putTag(T.ZSizeCastConv)
case Conv.Trunc => putTag(T.TruncConv)
case Conv.Zext => putTag(T.ZextConv)
case Conv.Sext => putTag(T.SextConv)
case Conv.Fptrunc => putTag(T.FptruncConv)
case Conv.Fpext => putTag(T.FpextConv)
case Conv.Fptoui => putTag(T.FptouiConv)
case Conv.Fptosi => putTag(T.FptosiConv)
case Conv.Uitofp => putTag(T.UitofpConv)
case Conv.Sitofp => putTag(T.SitofpConv)
case Conv.Ptrtoint => putTag(T.PtrtointConv)
case Conv.Inttoptr => putTag(T.InttoptrConv)
}
private def putNexts(nexts: Seq[Next]) =
putSeq(nexts)(putNext)
private def putNext(next: Next): Unit = next match {
case Next.Label(n, vs) => putTag(T.LabelNext); putLocal(n); putVals(vs)
case Next.Unwind(e, n) => putTag(T.UnwindNext); putParam(e); putNext(n)
case Next.Case(v, n) => putTag(T.CaseNext); putVal(v); putNext(n)
case Next.None => putTag(T.NoneNext)
}
private def putMemoryOrder(value: Option[MemoryOrder]): Unit = putOpt(value)(putMemoryOrder(_))
private def putMemoryOrder(value: MemoryOrder): Unit = value match {
case MemoryOrder.Unordered => putTag(T.Unordered)
case MemoryOrder.Monotonic => putTag(T.MonotonicOrder)
case MemoryOrder.Acquire => putTag(T.AcquireOrder)
case MemoryOrder.Release => putTag(T.ReleaseOrder)
case MemoryOrder.AcqRel => putTag(T.AcqRelOrder)
case MemoryOrder.SeqCst => putTag(T.SeqCstOrder)
}
private def putLinktimeCondition(cond: LinktimeCondition): Unit = cond match {
case LinktimeCondition.SimpleCondition(propertyName, comparison, value) =>
putTag(LinktimeCondition.Tag.SimpleCondition)
putString(propertyName)
putComp(comparison)
putVal(value)
putPosition(cond.position)
case LinktimeCondition.ComplexCondition(op, left, right) =>
putTag(LinktimeCondition.Tag.ComplexCondition)
putBin(op)
putLinktimeCondition(left)
putLinktimeCondition(right)
putPosition(cond.position)
}
private def putOp(op: Op) = op match {
case Op.Call(ty, v, args) =>
putTag(T.CallOp);
putType(ty);
putVal(v);
putVals(args);
case Op.Module(name) =>
putTag(T.ModuleOp)
putGlobal(name)
case Op.Classalloc(n, None) =>
putTag(T.ClassallocOp)
putGlobal(n)
case Op.Classalloc(n, Some(zone)) =>
putTag(T.ClassallocZoneOp)
putGlobal(n)
putVal(zone)
case Op.Field(v, name) =>
putTag(T.FieldOp)
putVal(v)
putGlobal(name)
case Op.Method(v, sig) =>
putTag(T.MethodOp)
putVal(v)
putSig(sig)
case Op.Comp(comp, ty, l, r) =>
putTag(T.CompOp)
putComp(comp)
putType(ty)
putVal(l)
putVal(r)
case Op.Conv(conv, ty, v) =>
putTag(T.ConvOp)
putConv(conv)
putType(ty)
putVal(v)
case Op.Bin(bin, ty, l, r) =>
putTag(T.BinOp)
putBin(bin)
putType(ty)
putVal(l)
putVal(r)
case Op.Load(ty, ptr, None) =>
putTag(T.LoadOp)
putType(ty)
putVal(ptr)
case Op.Load(ty, ptr, Some(memoryOrder)) =>
putTag(T.LoadAtomicOp)
putType(ty)
putVal(ptr)
putMemoryOrder(memoryOrder)
case Op.Store(ty, value, ptr, None) =>
putTag(T.StoreOp)
putType(ty)
putVal(value)
putVal(ptr)
case Op.Store(ty, value, ptr, Some(memoryOrder)) =>
putTag(T.StoreAtomicOp)
putType(ty)
putVal(value)
putVal(ptr)
putMemoryOrder(memoryOrder)
case Op.Box(ty, obj) =>
putTag(T.BoxOp)
putType(ty)
putVal(obj)
case Op.Unbox(ty, obj) =>
putTag(T.UnboxOp)
putType(ty)
putVal(obj)
case Op.Elem(ty, v, indexes) =>
putTag(T.ElemOp)
putType(ty)
putVal(v)
putVals(indexes)
case Op.Extract(v, indexes) =>
putTag(T.ExtractOp)
putVal(v)
putSeq(indexes)(putLebSignedInt)
case Op.Insert(v, value, indexes) =>
putTag(T.InsertOp)
putVal(v)
putVal(value)
putSeq(indexes)(putLebSignedInt)
case Op.Copy(v) =>
putTag(T.CopyOp)
putVal(v)
case Op.Stackalloc(ty, n) =>
putTag(T.StackallocOp)
putType(ty)
putVal(n)
case Op.Arrayalloc(ty, init, None) =>
putTag(T.ArrayallocOp)
putType(ty)
putVal(init)
case Op.Arrayalloc(ty, init, Some(zone)) =>
putTag(T.ArrayallocZoneOp)
putType(ty)
putVal(init)
putVal(zone)
case Op.Arrayload(ty, arr, idx) =>
putTag(T.ArrayloadOp)
putType(ty)
putVal(arr)
putVal(idx)
case Op.Arraystore(ty, arr, idx, value) =>
putTag(T.ArraystoreOp)
putType(ty)
putVal(arr)
putVal(idx)
putVal(value)
case Op.Arraylength(arr) =>
putTag(T.ArraylengthOp)
putVal(arr)
case Op.Fieldload(ty, obj, name) =>
putTag(T.FieldloadOp)
putType(ty)
putVal(obj)
putGlobal(name)
case Op.Fieldstore(ty, obj, name, value) =>
putTag(T.FieldstoreOp)
putType(ty)
putVal(obj)
putGlobal(name)
putVal(value)
case Op.Dynmethod(obj, sig) =>
putTag(T.DynmethodOp)
putVal(obj)
putSig(sig)
case Op.As(ty, v) =>
putTag(T.AsOp)
putType(ty)
putVal(v)
case Op.Is(ty, v) =>
putTag(T.IsOp)
putType(ty)
putVal(v)
case Op.Var(ty) =>
putTag(T.VarOp)
putType(ty)
case Op.Varload(slot) =>
putTag(T.VarloadOp)
putVal(slot)
case Op.Varstore(slot, value) =>
putTag(T.VarstoreOp)
putVal(slot)
putVal(value)
case Op.SizeOf(ty) =>
putTag(T.SizeOfOp)
putType(ty)
case Op.AlignmentOf(ty) =>
putTag(T.AlignmentOfOp)
putType(ty)
case Op.Fence(memoryOrder) =>
putTag(T.FenceOp)
putMemoryOrder(memoryOrder)
}
private def putParams(params: Seq[Val.Local]) = putSeq(params)(putParam)
private def putParam(param: Val.Local) = {
putLebUnsignedLong(param.id.id)
putType(param.ty)
}
private def putInst(cf: Inst) = {
def putTagAndPosition(tag: Byte) = {
putTag(tag)
putPosition(cf.pos)
}
cf match {
case Inst.Label(name, params) =>
putTagAndPosition(T.LabelInst)
putLocal(name)
putParams(params)
case let @ Inst.Let(id, op, Next.None) =>
putTagAndPosition(T.LetInst)
putLocal(id)
putOp(op)
putScopeId(let.scopeId)
case let @ Inst.Let(id, op, unwind) =>
putTagAndPosition(T.LetUnwindInst)
putLocal(id)
putOp(op)
putNext(unwind)
putScopeId(let.scopeId)
case Inst.Ret(v) =>
putTagAndPosition(T.RetInst)
putVal(v)
case Inst.Jump(next) =>
putTagAndPosition(T.JumpInst)
putNext(next)
case Inst.If(v, thenp, elsep) =>
putTagAndPosition(T.IfInst)
putVal(v)
putNext(thenp)
putNext(elsep)
case Inst.LinktimeIf(v, thenp, elsep) =>
putTagAndPosition(T.LinktimeIfInst)
putLinktimeCondition(v)
putNext(thenp)
putNext(elsep)
case Inst.Switch(v, default, cases) =>
putTagAndPosition(T.SwitchInst)
putVal(v)
putNext(default)
putNexts(cases)
case Inst.Throw(v, unwind) =>
putTagAndPosition(T.ThrowInst)
putVal(v)
putNext(unwind)
case Inst.Unreachable(unwind) =>
putTagAndPosition(T.UnreachableInst)
putNext(unwind)
}
}
def put(insts: Seq[Inst]) = putSeq(insts)(putInst)
}
}
sealed abstract class NIRSectionWriter(initialBufferSize: Int = 64 * 1024) {
private val baos = new ByteArrayOutputStream(initialBufferSize)
private val output = new DataOutputStream(baos)
final def position(): Int = output.size()
final def put(values: Array[Byte]): Unit = output.write(values)
final def put(value: Byte): Unit = output.write(value)
final def putShort(value: Short): Unit = output.writeShort(value)
final def putInt(value: Int): Unit = output.writeInt(value)
final def putFloat(value: Float): Unit = output.writeFloat(value)
final def putDouble(value: Double): Unit = output.writeDouble(value)
final def putBool(v: Boolean) = put((if (v) 1 else 0).toByte)
// Leb128 encoders
final def putLebShort(value: Short): Unit = putLebSignedInt(value)
final def putLebChar(value: Char): Unit = putLebUnsignedInt(value)
final def putLebUnsignedInt(v: Int): Unit = {
require(v >= 0, s"Unsigned integer expected, got $v")
var remaining = v
while ({
val byte = (remaining & 0x7f).toByte
remaining >>= 7
val hasMore = remaining != 0
put(if (hasMore) (byte | 0x80).toByte else byte)
hasMore
}) ()
}
final def putLebUnsignedLong(v: Long): Unit = {
require(v >= 0L, s"Unsigned integer expected, got $v")
var remaining = v
while ({
val byte = (remaining & 0x7f).toByte
remaining >>= 7
val hasMore = remaining != 0
put(if (hasMore) (byte | 0x80).toByte else byte)
hasMore
}) ()
}
final def putLebSignedInt(v: Int): Unit = {
var value = v
var remaining = value >> 7
var hasMore = true
val end = if ((value & java.lang.Integer.MIN_VALUE) == 0) 0 else -1
while (hasMore) {
hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1))
put(((value & 0x7f) | (if (hasMore) 0x80 else 0)).toByte)
value = remaining
remaining >>= 7
}
}
final def putLebSignedLong(v: Long): Unit = {
var value = v
var remaining = value >> 7
var hasMore = true
val end = if ((value & java.lang.Long.MIN_VALUE) == 0) 0L else -1L
while (hasMore) {
hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1))
put(((value & 0x7f) | (if (hasMore) 0x80 else 0)).toByte)
value = remaining
remaining >>= 7
}
}
final def putSeq[T](seq: Seq[T])(putT: T => Unit): Unit = {
putLebUnsignedInt(seq.length)
seq.foreach(putT)
}
final def putOpt[T](opt: Option[T])(putT: T => Unit): Unit = opt match {
case None => put(0.toByte)
case Some(t) => put(1.toByte); putT(t)
}
final def putTag(value: Byte): Unit = put(value)
final def commit(output: OutputStream): Unit = {
baos.writeTo(output)
output.flush()
}
}
sealed abstract class InternedBinarySectionWriter[T] extends NIRSectionWriter {
protected val entries = mutable.Map.empty[T, Int]
def put(value: T): Unit
def internDeps(value: T): Unit
def intern(value: T): Int =
entries
.get(value)
.getOrElse {
internDeps(value)
val offset = position()
entries(value) = offset
put(value)
offset
}
}