MicroVM.scala 5.6 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
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

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
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
98

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

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

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

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

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

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

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

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

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

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

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

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

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