MicroVM.scala 6.88 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
Kunshan Wang's avatar
Kunshan Wang committed
25
import uvm.refimpl.bootimg.PrimordialInfo
Kunshan Wang's avatar
Kunshan Wang committed
26 27
import com.typesafe.scalalogging.Logger
import org.slf4j.LoggerFactory
28 29

object MicroVM {
Kunshan Wang's avatar
Kunshan Wang committed
30 31
  val logger = Logger(LoggerFactory.getLogger(getClass.getName))

32 33
  val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
  val DEFAULT_LOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
34 35
  val DEFAULT_GLOBAL_SIZE: Word = 1L * 1024L * 1024L; // 1MiB
  val DEFAULT_STACK_SIZE: Word = 63L * 1024L; // 60KiB per stack
36 37

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

42
  def apply(confStr: String): MicroVM = {
Kunshan Wang's avatar
Kunshan Wang committed
43
    val vmConf = VMConf(confStr)
44
    MicroVM(vmConf)
Kunshan Wang's avatar
Kunshan Wang committed
45 46 47 48 49 50 51 52 53 54 55 56 57
  }

  def apply(confStr: String, appArgs: Seq[String]): MicroVM = {
    val vmConf = VMConf(confStr)
    MicroVM(vmConf, appArgs)
  }
  
  def apply(vmConf: VMConf): MicroVM = {
    new MicroVM(vmConf, None)
  }
  
  def apply(vmConf: VMConf, appArgs: Seq[String]): MicroVM = {
    new MicroVM(vmConf, Some(appArgs))
58 59
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
60

Kunshan Wang's avatar
Kunshan Wang committed
61
class MicroVM private (val vmConf: VMConf, val appArgs: Option[Seq[String]]) extends IRBuilderListener {
62 63
  // implicitly injected resources
  private implicit val microVM = this
Kunshan Wang's avatar
Kunshan Wang committed
64 65
  
  val stats = new VMStats()
66

67
  val globalBundle = new GlobalBundle()
68
  val constantPool = new ConstantPool()
Kunshan Wang's avatar
Kunshan Wang committed
69

70
  /// Initialise the global bundle and constant pool with (private) pre-loaded stuff
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
    // Some types required by the RunMu class
91

92 93 94
    for (ty <- Seq(C_INT, C_CHAR, C_CHARP, C_CHARPP)) {
      globalBundle.typeNs.add(ty)
    }
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
  }
  
  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
121
    val irBuilder = new IRBuilder(irBuilderRegistry.newID(), globalBundle, idFactory, Some(this))
122 123 124 125 126
    irBuilderRegistry.put(irBuilder)
    irBuilder
  }
  
  override def onBundleLoad(irBuilder: IRBuilder, bundle: TrantientBundle): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
127 128
    addBundle(bundle)
    irBuilderRegistry.remove(irBuilder)
129 130 131
  }
  
  override def onBundleAbort(irBuilder: IRBuilder): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
132
    irBuilderRegistry.remove(irBuilder)
133
  }
134 135 136 137

  /**
   * Add things from a bundle to the Micro VM.
   */
138
  def addBundle(bundle: TrantientBundle) {
139 140 141 142 143
    if (vmConf.dumpBundle) {
      val dbs = new DebugBundleSerializer(bundle)
      dbs.writeUIR(new OutputStreamWriter(System.err))
    }

144 145 146
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
147

148 149 150 151 152
    globalBundle.merge(bundle);

    for (gc <- bundle.globalCellNs.all) {
      memoryManager.globalMemory.addGlobalCell(gc)
    }
153
    for (ef <- bundle.expFuncNs.all) {
154
      nativeCallHelper.exposeFuncStatic(ef)
155 156
    }
    // Must allocate the memory and expose the functions before making constants.
157 158 159 160
    for (g <- bundle.globalVarNs.all) {
      constantPool.addGlobalVar(g)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
161 162

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

164
  /**
Kunshan Wang's avatar
Kunshan Wang committed
165
   * Create a new MuCtx. Part of the API.
166
   */
167 168 169 170 171 172 173 174 175
  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
176
    contexts.add(ca)
Kunshan Wang's avatar
Kunshan Wang committed
177 178
    ca
  }
179 180 181
  /**
   * Given a name, get the ID of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
182
  def idOf(name: MuName): MuID = globalBundle.allNs(name).id
Kunshan Wang's avatar
Kunshan Wang committed
183

184 185 186
  /**
   * Given an ID, get the name of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
187
  def nameOf(id: MuID): MuName = globalBundle.allNs(id).name.get
Kunshan Wang's avatar
Kunshan Wang committed
188

Kunshan Wang's avatar
Kunshan Wang committed
189 190 191 192 193 194
  /**
   * Set the trap handler.
   */
  def setTrapHandler(trapHandler: TrapHandler): Unit = {
    trapManager.trapHandler = trapHandler
  }
Kunshan Wang's avatar
Kunshan Wang committed
195

Kunshan Wang's avatar
Kunshan Wang committed
196 197 198
  /**
   * Make boot image.
   */
Kunshan Wang's avatar
Kunshan Wang committed
199
  def makeBootImage(whiteList: Seq[MuID], outputFile: String): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
200
    val whiteListObjs = whiteList.map(globalBundle.topLevelNs.apply)
Kunshan Wang's avatar
Kunshan Wang committed
201

Kunshan Wang's avatar
Kunshan Wang committed
202
    bootImageBuilder.makeBootImage(whiteListObjs, PrimordialInfo.NO_PRIMORDIAL, Seq(), Seq(), outputFile)
Kunshan Wang's avatar
Kunshan Wang committed
203
  }
Kunshan Wang's avatar
Kunshan Wang committed
204

Kunshan Wang's avatar
Kunshan Wang committed
205
  /**
Kunshan Wang's avatar
Kunshan Wang committed
206
   * Print the global bundle to the writer w.
Kunshan Wang's avatar
Kunshan Wang committed
207 208
   */
  def debugPrintGlobalBundle(w: Writer): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
209
    val bs = new BundleSerializer(globalBundle, globalBundle.allTopLevels().toSet)
Kunshan Wang's avatar
Kunshan Wang committed
210 211
    bs.writeUIR(w)
  }
Kunshan Wang's avatar
Kunshan Wang committed
212 213 214 215 216 217 218 219

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

Kunshan Wang's avatar
Kunshan Wang committed
220 221 222 223
  /**
   * Load from a boot image.
   */
  def loadBootImage(file: String): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
224
    tryWithResource(new BootImageLoader(file, appArgs)) { bil =>
225 226
      bil.load()
    }
Kunshan Wang's avatar
Kunshan Wang committed
227
  }
Kunshan Wang's avatar
Kunshan Wang committed
228

Kunshan Wang's avatar
Kunshan Wang committed
229 230 231 232 233
  /**
   * Execute. This is the external pusher of the execution.
   */
  def execute(): Unit = {
    threadStackManager.execute()
Kunshan Wang's avatar
Kunshan Wang committed
234 235 236
    
    MicroVM.logger.info("Execution statistics:")
    MicroVM.logger.info(stats.getStatesString())
Kunshan Wang's avatar
Kunshan Wang committed
237
  }
Kunshan Wang's avatar
Kunshan Wang committed
238 239 240 241 242 243 244

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