MicroVM.scala 5.53 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 11
import uvm.ir.irbuilder.IRBuilder
import uvm.ir.irbuilder.IRNode
Kunshan Wang's avatar
Kunshan Wang committed
12
import uvm.ir.textinput.UIRTextReader
Kunshan Wang's avatar
Kunshan Wang committed
13
import uvm.ir.textoutput.BundleSerializer
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 18 19
import uvm.refimpl.itpr._
import uvm.refimpl.mem._
import uvm.refimpl.mem.TypeSizes.Word
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 25

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

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

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

Kunshan Wang's avatar
Kunshan Wang committed
42
class MicroVM(val vmConf: VMConf) {
43 44
  // implicitly injected resources
  private implicit val microVM = this
45

46
  val globalBundle = new GlobalBundle()
47
  val constantPool = new ConstantPool()
Kunshan Wang's avatar
Kunshan Wang committed
48
  val memoryManager = new MemoryManager(vmConf)
Kunshan Wang's avatar
Kunshan Wang committed
49 50

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

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

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

56
  val threadStackManager = new ThreadStackManager()
57

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

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

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

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

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

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

  /**
   * Add things from a bundle to the Micro VM.
   */
93
  def addBundle(bundle: TrantientBundle) {
94 95 96
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
97

98 99 100 101 102
    globalBundle.merge(bundle);

    for (gc <- bundle.globalCellNs.all) {
      memoryManager.globalMemory.addGlobalCell(gc)
    }
103
    for (ef <- bundle.expFuncNs.all) {
104
      nativeCallHelper.exposeFuncStatic(ef)
105 106
    }
    // Must allocate the memory and expose the functions before making constants.
107 108 109 110
    for (g <- bundle.globalVarNs.all) {
      constantPool.addGlobalVar(g)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
111 112

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

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

134 135 136
  /**
   * Given an ID, get the name of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
137
  def nameOf(id: Int): String = globalBundle.allNs(id).name.get
Kunshan Wang's avatar
Kunshan Wang committed
138

Kunshan Wang's avatar
Kunshan Wang committed
139 140 141 142 143 144
  /**
   * Set the trap handler.
   */
  def setTrapHandler(trapHandler: TrapHandler): Unit = {
    trapManager.trapHandler = trapHandler
  }
Kunshan Wang's avatar
Kunshan Wang committed
145

Kunshan Wang's avatar
Kunshan Wang committed
146 147 148 149
  /**
   * Make boot image.
   */
  def makeBootImage(whiteList: Seq[Int], outputFile: String): Unit = {
150 151 152 153 154
    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
155 156
          "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))
157 158
      }
    }
Kunshan Wang's avatar
Kunshan Wang committed
159

160
    bootImageBuilder.makeBootImage(whiteListObjs, outputFile)
Kunshan Wang's avatar
Kunshan Wang committed
161
  }
Kunshan Wang's avatar
Kunshan Wang committed
162

Kunshan Wang's avatar
Kunshan Wang committed
163
  /**
Kunshan Wang's avatar
Kunshan Wang committed
164
   * Print the global bundle to the writer w.
Kunshan Wang's avatar
Kunshan Wang committed
165 166
   */
  def debugPrintGlobalBundle(w: Writer): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
167
    val bs = new BundleSerializer(globalBundle, globalBundle.allTopLevels().toSet)
Kunshan Wang's avatar
Kunshan Wang committed
168 169
    bs.writeUIR(w)
  }
Kunshan Wang's avatar
Kunshan Wang committed
170 171 172 173 174 175 176 177

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

Kunshan Wang's avatar
Kunshan Wang committed
178 179 180 181 182 183 184
  /**
   * Load from a boot image.
   */
  def loadBootImage(file: String): Unit = {
    val bil = new BootImageLoader(file)
    bil.load()
  }
Kunshan Wang's avatar
Kunshan Wang committed
185

Kunshan Wang's avatar
Kunshan Wang committed
186 187 188 189 190 191
  /**
   * Execute. This is the external pusher of the execution.
   */
  def execute(): Unit = {
    threadStackManager.execute()
  }
Kunshan Wang's avatar
Kunshan Wang committed
192 193 194 195 196 197 198

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