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

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

Kunshan Wang's avatar
Kunshan Wang committed
5 6
import java.io.Writer

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

9
import uvm._
Kunshan Wang's avatar
Kunshan Wang committed
10
import uvm.ir.irbuilder.IRBuilder
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.refimpl.bootimg.BootImageBuilder
Kunshan Wang's avatar
Kunshan Wang committed
14
import uvm.refimpl.bootimg.BootImageLoader
Kunshan Wang's avatar
Kunshan Wang committed
15
import uvm.refimpl.hail.HailScriptLoader
16 17 18
import uvm.refimpl.itpr._
import uvm.refimpl.mem._
import uvm.refimpl.mem.TypeSizes.Word
Kunshan Wang's avatar
Kunshan Wang committed
19
import uvm.refimpl.nat.NativeCallHelper
Kunshan Wang's avatar
Kunshan Wang committed
20
import uvm.refimpl.nat.NativeLibraryHolder
21
import uvm.staticanalysis.StaticAnalyzer
22
import uvm.utils.IDFactory
23
import uvm.utils.WithUtils.tryWithResource
24
import uvm.ir.textoutput.DebugBundleSerializer
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

Kunshan Wang's avatar
Kunshan Wang committed
43
class MicroVM(val vmConf: VMConf) {
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
  val memoryManager = new MemoryManager(vmConf)
Kunshan Wang's avatar
Kunshan Wang committed
50 51

  private implicit val memorySupport = memoryManager.memorySupport
Kunshan Wang's avatar
Kunshan Wang committed
52

Kunshan Wang's avatar
Kunshan Wang committed
53
  val nativeLibraryHolder = NativeLibraryHolder(vmConf.extraLibs: _*)
Kunshan Wang's avatar
Kunshan Wang committed
54

55
  implicit val nativeCallHelper = new NativeCallHelper()
Kunshan Wang's avatar
Kunshan Wang committed
56

57
  val threadStackManager = new ThreadStackManager()
58

59
  val trapManager = new TrapManager()
Kunshan Wang's avatar
Kunshan Wang committed
60
  val contexts = new HashSet[MuCtx]()
Kunshan Wang's avatar
Kunshan Wang committed
61

Kunshan Wang's avatar
Kunshan Wang committed
62
  val idFactory = IDFactory.newClientIDFactory()
63
  val irBuilder = new IRBuilder(globalBundle, idFactory)
64
  val irNodeRegistry = new SequentialObjectKeeper[IRNode]()
Kunshan Wang's avatar
Kunshan Wang committed
65 66
  val irReader = new UIRTextReader(idFactory, recordSourceInfo = vmConf.sourceInfo)
  val hailScriptLoader = new HailScriptLoader(recordSourceInfo = vmConf.sourceInfo)
67
  val staticAnalyzer = new StaticAnalyzer()
Kunshan Wang's avatar
Kunshan Wang committed
68

69
  val bootImageBuilder = new BootImageBuilder()
Kunshan Wang's avatar
Kunshan Wang committed
70

71
  {
Kunshan Wang's avatar
Kunshan Wang committed
72 73
    // 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.
74
    // So the GC must know about this type because the GC looks up the globalBundle for types.
Kunshan Wang's avatar
Kunshan Wang committed
75 76 77 78 79 80 81 82 83

    // 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
84

Kunshan Wang's avatar
Kunshan Wang committed
85 86 87 88
    for (c <- Seq(NULL_REF_VOID, NULL_IREF_VOID, NULL_FUNCREF_VV, NULL_THREADREF, NULL_STACKREF)) {
      globalBundle.constantNs.add(c)
      constantPool.addGlobalVar(c)
    }
89
  }
90 91 92 93

  /**
   * Add things from a bundle to the Micro VM.
   */
94
  def addBundle(bundle: TrantientBundle) {
95 96 97 98 99
    if (vmConf.dumpBundle) {
      val dbs = new DebugBundleSerializer(bundle)
      dbs.writeUIR(new OutputStreamWriter(System.err))
    }

100 101 102
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
103

104 105 106 107 108
    globalBundle.merge(bundle);

    for (gc <- bundle.globalCellNs.all) {
      memoryManager.globalMemory.addGlobalCell(gc)
    }
109
    for (ef <- bundle.expFuncNs.all) {
110
      nativeCallHelper.exposeFuncStatic(ef)
111 112
    }
    // Must allocate the memory and expose the functions before making constants.
113 114 115 116
    for (g <- bundle.globalVarNs.all) {
      constantPool.addGlobalVar(g)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
117 118

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

120
  /**
Kunshan Wang's avatar
Kunshan Wang committed
121
   * Create a new MuCtx. Part of the API.
122
   */
123 124 125 126 127 128 129 130 131
  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
132
    contexts.add(ca)
Kunshan Wang's avatar
Kunshan Wang committed
133 134
    ca
  }
135 136 137
  /**
   * Given a name, get the ID of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
138
  def idOf(name: String): Int = globalBundle.allNs(name).id
Kunshan Wang's avatar
Kunshan Wang committed
139

140 141 142
  /**
   * Given an ID, get the name of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
143
  def nameOf(id: Int): String = globalBundle.allNs(id).name.get
Kunshan Wang's avatar
Kunshan Wang committed
144

Kunshan Wang's avatar
Kunshan Wang committed
145 146 147 148 149 150
  /**
   * Set the trap handler.
   */
  def setTrapHandler(trapHandler: TrapHandler): Unit = {
    trapManager.trapHandler = trapHandler
  }
Kunshan Wang's avatar
Kunshan Wang committed
151

Kunshan Wang's avatar
Kunshan Wang committed
152 153 154 155
  /**
   * Make boot image.
   */
  def makeBootImage(whiteList: Seq[Int], outputFile: String): Unit = {
156 157 158 159 160
    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
161 162
          "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))
163 164
      }
    }
Kunshan Wang's avatar
Kunshan Wang committed
165

166
    bootImageBuilder.makeBootImage(whiteListObjs, outputFile)
Kunshan Wang's avatar
Kunshan Wang committed
167
  }
Kunshan Wang's avatar
Kunshan Wang committed
168

Kunshan Wang's avatar
Kunshan Wang committed
169
  /**
Kunshan Wang's avatar
Kunshan Wang committed
170
   * Print the global bundle to the writer w.
Kunshan Wang's avatar
Kunshan Wang committed
171 172
   */
  def debugPrintGlobalBundle(w: Writer): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
173
    val bs = new BundleSerializer(globalBundle, globalBundle.allTopLevels().toSet)
Kunshan Wang's avatar
Kunshan Wang committed
174 175
    bs.writeUIR(w)
  }
Kunshan Wang's avatar
Kunshan Wang committed
176 177 178 179 180 181 182 183

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

Kunshan Wang's avatar
Kunshan Wang committed
184 185 186 187
  /**
   * Load from a boot image.
   */
  def loadBootImage(file: String): Unit = {
188 189 190
    tryWithResource(new BootImageLoader(file)) { bil =>
      bil.load()
    }
Kunshan Wang's avatar
Kunshan Wang committed
191
  }
Kunshan Wang's avatar
Kunshan Wang committed
192

Kunshan Wang's avatar
Kunshan Wang committed
193 194 195 196 197 198
  /**
   * Execute. This is the external pusher of the execution.
   */
  def execute(): Unit = {
    threadStackManager.execute()
  }
Kunshan Wang's avatar
Kunshan Wang committed
199 200 201 202 203 204 205

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