MicroVM.scala 6.48 KB
Newer Older
1 2
package uvm.refimpl

Kunshan Wang's avatar
Kunshan Wang committed
3
import java.io.OutputStreamWriter
Kunshan Wang's avatar
Kunshan Wang committed
4 5
import java.io.Writer

Kunshan Wang's avatar
Kunshan Wang committed
6 7
import scala.collection.mutable.HashSet

8
import uvm._
Kunshan Wang's avatar
Kunshan Wang committed
9
import uvm.ir.irbuilder.IRBuilder
10
import uvm.ir.irbuilder.IRBuilderListener
Kunshan Wang's avatar
Kunshan Wang committed
11
import uvm.ir.textinput.UIRTextReader
Kunshan Wang's avatar
Kunshan Wang committed
12
import uvm.ir.textoutput.BundleSerializer
Kunshan Wang's avatar
Kunshan Wang committed
13
import uvm.ir.textoutput.DebugBundleSerializer
Kunshan Wang's avatar
Kunshan Wang committed
14
import uvm.refimpl.bootimg.BootImageBuilder
Kunshan Wang's avatar
Kunshan Wang committed
15
import uvm.refimpl.bootimg.BootImageLoader
Kunshan Wang's avatar
Kunshan Wang committed
16
import uvm.refimpl.hail.HailScriptLoader
17
import uvm.refimpl.integerize.IDObjectKeeper
18 19
import uvm.refimpl.itpr._
import uvm.refimpl.mem._
Kunshan Wang's avatar
Kunshan Wang committed
20
import uvm.refimpl.nat.NativeCallHelper
Kunshan Wang's avatar
Kunshan Wang committed
21
import uvm.refimpl.nat.NativeLibraryHolder
22
import uvm.staticanalysis.StaticAnalyzer
23
import uvm.utils.IDFactory
24
import uvm.utils.WithUtils.tryWithResource
25 26

object MicroVM {
27 28
  val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
  val DEFAULT_LOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
29 30
  val DEFAULT_GLOBAL_SIZE: Word = 1L * 1024L * 1024L; // 1MiB
  val DEFAULT_STACK_SIZE: Word = 63L * 1024L; // 60KiB per stack
31 32

  def apply(): MicroVM = {
Kunshan Wang's avatar
Kunshan Wang committed
33 34
    val vmConf = new VMConf()
    new MicroVM(vmConf)
35
  }
Kunshan Wang's avatar
Kunshan Wang committed
36

37
  def apply(confStr: String): MicroVM = {
Kunshan Wang's avatar
Kunshan Wang committed
38 39
    val vmConf = VMConf(confStr)
    new MicroVM(vmConf)
40 41
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
42

43
class MicroVM(val vmConf: VMConf) extends IRBuilderListener {
44 45
  // implicitly injected resources
  private implicit val microVM = this
46

47
  val globalBundle = new GlobalBundle()
48
  val constantPool = new ConstantPool()
Kunshan Wang's avatar
Kunshan Wang committed
49

50
  /// Initialise the global bundle and constant pool with (private) pre-loaded stuff
51
  {
Kunshan Wang's avatar
Kunshan Wang committed
52 53
    // VOID, BYTE, BYTE_ARRAY: The micro VM allocates stacks on the heap in the large object space.
    // It is represented as a big chunk of byte array.
54
    // So the GC must know about this type because the GC looks up the globalBundle for types.
Kunshan Wang's avatar
Kunshan Wang committed
55 56 57 58 59 60 61 62 63

    // BYTES, BYTES_R, REFS, REFS_R: Types for the @uvm.meta.* common instructions.

    import InternalTypes._
    for (ty <- Seq(VOID, BYTE, BYTE_ARRAY, BYTES, BYTES_R, REFS, REFS_R)) {
      globalBundle.typeNs.add(ty)
    }

    // Some internal constants needed by the HAIL loader
64

Kunshan Wang's avatar
Kunshan Wang committed
65 66 67 68
    for (c <- Seq(NULL_REF_VOID, NULL_IREF_VOID, NULL_FUNCREF_VV, NULL_THREADREF, NULL_STACKREF)) {
      globalBundle.constantNs.add(c)
      constantPool.addGlobalVar(c)
    }
69

70
    // Some types required by the RunMu class
71

72 73 74
    for (ty <- Seq(C_INT, C_CHAR, C_CHARP, C_CHARPP)) {
      globalBundle.typeNs.add(ty)
    }
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
  }
  
  val memoryManager = new MemoryManager(vmConf)

  private implicit val memorySupport = memoryManager.memorySupport

  val nativeLibraryHolder = NativeLibraryHolder(vmConf.extraLibs: _*)

  implicit val nativeCallHelper = new NativeCallHelper()

  val threadStackManager = new ThreadStackManager()

  val trapManager = new TrapManager()
  val contexts = new HashSet[MuCtx]()

  val idFactory = IDFactory.newClientIDFactory()
  val irBuilderRegistry = new IDObjectKeeper[IRBuilder]("IR builder")
  val irReader = new UIRTextReader(idFactory, recordSourceInfo = vmConf.sourceInfo)
  val hailScriptLoader = new HailScriptLoader(recordSourceInfo = vmConf.sourceInfo)
  val staticAnalyzer = new StaticAnalyzer()

  val bootImageBuilder = new BootImageBuilder()
  
  /// Bundle building stuff
  
  def newIRBuilder(): IRBuilder = {
Kunshan Wang's avatar
Kunshan Wang committed
101
    val irBuilder = new IRBuilder(irBuilderRegistry.newID(), globalBundle, idFactory, Some(this))
102 103 104 105 106
    irBuilderRegistry.put(irBuilder)
    irBuilder
  }
  
  override def onBundleLoad(irBuilder: IRBuilder, bundle: TrantientBundle): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
107 108
    addBundle(bundle)
    irBuilderRegistry.remove(irBuilder)
109 110 111
  }
  
  override def onBundleAbort(irBuilder: IRBuilder): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
112
    irBuilderRegistry.remove(irBuilder)
113
  }
114 115 116 117

  /**
   * Add things from a bundle to the Micro VM.
   */
118
  def addBundle(bundle: TrantientBundle) {
119 120 121 122 123
    if (vmConf.dumpBundle) {
      val dbs = new DebugBundleSerializer(bundle)
      dbs.writeUIR(new OutputStreamWriter(System.err))
    }

124 125 126
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
127

128 129 130 131 132
    globalBundle.merge(bundle);

    for (gc <- bundle.globalCellNs.all) {
      memoryManager.globalMemory.addGlobalCell(gc)
    }
133
    for (ef <- bundle.expFuncNs.all) {
134
      nativeCallHelper.exposeFuncStatic(ef)
135 136
    }
    // Must allocate the memory and expose the functions before making constants.
137 138 139 140
    for (g <- bundle.globalVarNs.all) {
      constantPool.addGlobalVar(g)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
141 142

  private val contextIDFactory = IDFactory.newOneBasedIDFactory()
Kunshan Wang's avatar
Kunshan Wang committed
143

144
  /**
Kunshan Wang's avatar
Kunshan Wang committed
145
   * Create a new MuCtx. Part of the API.
146
   */
147 148 149 150 151 152 153 154 155
  def newContext(): MuCtx = newContext("user")

  /**
   * Create a new MuCtx. Extended to add a name for debugging.
   */
  def newContext(name: String): MuCtx = {
    val id = contextIDFactory.getID()
    val mutator = microVM.memoryManager.heap.makeMutator("MuCtx-%d-%s".format(id, name)) // This may trigger GC
    val ca = new MuCtx(id, mutator)
Kunshan Wang's avatar
Kunshan Wang committed
156
    contexts.add(ca)
Kunshan Wang's avatar
Kunshan Wang committed
157 158
    ca
  }
159 160 161
  /**
   * Given a name, get the ID of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
162
  def idOf(name: MuName): MuID = globalBundle.allNs(name).id
Kunshan Wang's avatar
Kunshan Wang committed
163

164 165 166
  /**
   * Given an ID, get the name of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
167
  def nameOf(id: MuID): MuName = globalBundle.allNs(id).name.get
Kunshan Wang's avatar
Kunshan Wang committed
168

Kunshan Wang's avatar
Kunshan Wang committed
169 170 171 172 173 174
  /**
   * Set the trap handler.
   */
  def setTrapHandler(trapHandler: TrapHandler): Unit = {
    trapManager.trapHandler = trapHandler
  }
Kunshan Wang's avatar
Kunshan Wang committed
175

Kunshan Wang's avatar
Kunshan Wang committed
176 177 178
  /**
   * Make boot image.
   */
Kunshan Wang's avatar
Kunshan Wang committed
179
  def makeBootImage(whiteList: Seq[MuID], outputFile: String): Unit = {
180 181 182 183 184
    val whiteListObjs = whiteList.map { id =>
      val obj = globalBundle.allNs(id)
      obj match {
        case tl: TopLevel => tl
        case _ => throw new UvmRuntimeException(
Kunshan Wang's avatar
Kunshan Wang committed
185 186
          "White list may only contain top-level definitions. Entity ID %d%s is a %s".format(
            obj.id, obj.name.map(n => s" (${n})").getOrElse(""), obj.getClass.getName))
187 188
      }
    }
Kunshan Wang's avatar
Kunshan Wang committed
189

190
    bootImageBuilder.makeBootImage(whiteListObjs, outputFile)
Kunshan Wang's avatar
Kunshan Wang committed
191
  }
Kunshan Wang's avatar
Kunshan Wang committed
192

Kunshan Wang's avatar
Kunshan Wang committed
193
  /**
Kunshan Wang's avatar
Kunshan Wang committed
194
   * Print the global bundle to the writer w.
Kunshan Wang's avatar
Kunshan Wang committed
195 196
   */
  def debugPrintGlobalBundle(w: Writer): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
197
    val bs = new BundleSerializer(globalBundle, globalBundle.allTopLevels().toSet)
Kunshan Wang's avatar
Kunshan Wang committed
198 199
    bs.writeUIR(w)
  }
Kunshan Wang's avatar
Kunshan Wang committed
200 201 202 203 204 205 206 207

  /**
   * Print the global bundle to stderr.
   */
  def debugPrintGlobalBundle(): Unit = {
    debugPrintGlobalBundle(new OutputStreamWriter(System.err))
  }

Kunshan Wang's avatar
Kunshan Wang committed
208 209 210 211
  /**
   * Load from a boot image.
   */
  def loadBootImage(file: String): Unit = {
212 213 214
    tryWithResource(new BootImageLoader(file)) { bil =>
      bil.load()
    }
Kunshan Wang's avatar
Kunshan Wang committed
215
  }
Kunshan Wang's avatar
Kunshan Wang committed
216

Kunshan Wang's avatar
Kunshan Wang committed
217 218 219 220 221 222
  /**
   * Execute. This is the external pusher of the execution.
   */
  def execute(): Unit = {
    threadStackManager.execute()
  }
Kunshan Wang's avatar
Kunshan Wang committed
223 224 225 226 227 228 229

  // Automatically load the boot image if provided
  {
    vmConf.bootImg foreach { fileName =>
      loadBootImage(fileName)
    }
  }
230
}