GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

MicroVM.scala 7.64 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
import uvm.refimpl.cmdline.NativeArgv
29 30

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

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

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

43
  def apply(confStr: String): MicroVM = {
Kunshan Wang's avatar
Kunshan Wang committed
44
    val vmConf = VMConf(confStr)
45
    MicroVM(vmConf)
Kunshan Wang's avatar
Kunshan Wang committed
46 47
  }

Kunshan Wang's avatar
Kunshan Wang committed
48
  def apply(confStr: String, allArgs: Seq[String]): MicroVM = {
Kunshan Wang's avatar
Kunshan Wang committed
49
    val vmConf = VMConf(confStr)
Kunshan Wang's avatar
Kunshan Wang committed
50
    MicroVM(vmConf, allArgs)
Kunshan Wang's avatar
Kunshan Wang committed
51 52 53 54 55 56
  }
  
  def apply(vmConf: VMConf): MicroVM = {
    new MicroVM(vmConf, None)
  }
  
Kunshan Wang's avatar
Kunshan Wang committed
57 58
  def apply(vmConf: VMConf, allArgs: Seq[String]): MicroVM = {
    new MicroVM(vmConf, Some(allArgs))
59 60
  }
}
Kunshan Wang's avatar
Kunshan Wang committed
61

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

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

71
  /// Initialise the global bundle and constant pool with (private) pre-loaded stuff
72
  {
Kunshan Wang's avatar
Kunshan Wang committed
73 74
    // 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.
75
    // So the GC must know about this type because the GC looks up the globalBundle for types.
Kunshan Wang's avatar
Kunshan Wang committed
76 77 78 79 80 81 82 83 84

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

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

91
    // Some types required by the RunMu class
92

93 94 95
    for (ty <- Seq(C_INT, C_CHAR, C_CHARP, C_CHARPP)) {
      globalBundle.typeNs.add(ty)
    }
96 97
  }
  
98 99 100 101 102 103 104 105 106 107 108 109
  /**
   * A hack that allows general reference types to be accessed by pointers.
   * <p>
   * By default (true), memory locations of general reference types can only be accessed via iref.
   * This enforcement can be disabled as a workaround for the current mu-client-pypy project.
   */
  val enforceRefTypeNoPointerAccess = !vmConf.uPtrHack
  
  if (!enforceRefTypeNoPointerAccess) {
    MicroVM.logger.warn("Allowing memory locations of general reference types to be accessed by uptr.")
  }
  
110 111 112 113 114 115 116
  val memoryManager = new MemoryManager(vmConf)

  private implicit val memorySupport = memoryManager.memorySupport

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

  implicit val nativeCallHelper = new NativeCallHelper()
117 118
  
  var maybeNativeArgv: Option[NativeArgv] = None
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135

  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
136
    val irBuilder = new IRBuilder(irBuilderRegistry.newID(), globalBundle, idFactory, Some(this))
137 138 139 140 141
    irBuilderRegistry.put(irBuilder)
    irBuilder
  }
  
  override def onBundleLoad(irBuilder: IRBuilder, bundle: TrantientBundle): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
142 143
    addBundle(bundle)
    irBuilderRegistry.remove(irBuilder)
144 145 146
  }
  
  override def onBundleAbort(irBuilder: IRBuilder): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
147
    irBuilderRegistry.remove(irBuilder)
148
  }
149 150 151 152

  /**
   * Add things from a bundle to the Micro VM.
   */
153
  def addBundle(bundle: TrantientBundle) {
154 155 156 157 158
    if (vmConf.dumpBundle) {
      val dbs = new DebugBundleSerializer(bundle)
      dbs.writeUIR(new OutputStreamWriter(System.err))
    }

159 160 161
    if (vmConf.staticCheck) {
      staticAnalyzer.checkBundle(bundle, Some(globalBundle))
    }
162

163 164 165 166 167
    globalBundle.merge(bundle);

    for (gc <- bundle.globalCellNs.all) {
      memoryManager.globalMemory.addGlobalCell(gc)
    }
168
    for (ef <- bundle.expFuncNs.all) {
169
      nativeCallHelper.exposeFuncStatic(ef)
170 171
    }
    // Must allocate the memory and expose the functions before making constants.
172 173 174 175
    for (g <- bundle.globalVarNs.all) {
      constantPool.addGlobalVar(g)
    }
  }
Kunshan Wang's avatar
Kunshan Wang committed
176 177

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

179
  /**
Kunshan Wang's avatar
Kunshan Wang committed
180
   * Create a new MuCtx. Part of the API.
181
   */
182 183 184 185 186 187 188 189 190
  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
191
    contexts.add(ca)
Kunshan Wang's avatar
Kunshan Wang committed
192 193
    ca
  }
194 195 196
  /**
   * Given a name, get the ID of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
197
  def idOf(name: MuName): MuID = globalBundle.allNs(name).id
Kunshan Wang's avatar
Kunshan Wang committed
198

199 200 201
  /**
   * Given an ID, get the name of an identified entity.
   */
Kunshan Wang's avatar
Kunshan Wang committed
202
  def nameOf(id: MuID): MuName = globalBundle.allNs(id).name.get
Kunshan Wang's avatar
Kunshan Wang committed
203

Kunshan Wang's avatar
Kunshan Wang committed
204 205 206 207 208 209
  /**
   * Set the trap handler.
   */
  def setTrapHandler(trapHandler: TrapHandler): Unit = {
    trapManager.trapHandler = trapHandler
  }
Kunshan Wang's avatar
Kunshan Wang committed
210

Kunshan Wang's avatar
Kunshan Wang committed
211 212 213
  /**
   * Make boot image.
   */
Kunshan Wang's avatar
Kunshan Wang committed
214
  def makeBootImage(whiteList: Seq[MuID], outputFile: String): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
215
    val whiteListObjs = whiteList.map(globalBundle.topLevelNs.apply)
Kunshan Wang's avatar
Kunshan Wang committed
216

Kunshan Wang's avatar
Kunshan Wang committed
217
    bootImageBuilder.makeBootImage(whiteListObjs, PrimordialInfo.NO_PRIMORDIAL, Seq(), Seq(), outputFile)
Kunshan Wang's avatar
Kunshan Wang committed
218
  }
Kunshan Wang's avatar
Kunshan Wang committed
219

Kunshan Wang's avatar
Kunshan Wang committed
220
  /**
Kunshan Wang's avatar
Kunshan Wang committed
221
   * Print the global bundle to the writer w.
Kunshan Wang's avatar
Kunshan Wang committed
222 223
   */
  def debugPrintGlobalBundle(w: Writer): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
224
    val bs = new BundleSerializer(globalBundle, globalBundle.allTopLevels().toSet)
Kunshan Wang's avatar
Kunshan Wang committed
225 226
    bs.writeUIR(w)
  }
Kunshan Wang's avatar
Kunshan Wang committed
227 228 229 230 231 232 233 234

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

Kunshan Wang's avatar
Kunshan Wang committed
235 236 237 238
  /**
   * Load from a boot image.
   */
  def loadBootImage(file: String): Unit = {
Kunshan Wang's avatar
Kunshan Wang committed
239
    tryWithResource(new BootImageLoader(file, allArgs)) { bil =>
240 241
      bil.load()
    }
Kunshan Wang's avatar
Kunshan Wang committed
242
  }
Kunshan Wang's avatar
Kunshan Wang committed
243

Kunshan Wang's avatar
Kunshan Wang committed
244 245 246 247 248
  /**
   * Execute. This is the external pusher of the execution.
   */
  def execute(): Unit = {
    threadStackManager.execute()
Kunshan Wang's avatar
Kunshan Wang committed
249 250
    
    MicroVM.logger.info("Execution statistics:")
251
    MicroVM.logger.info(stats.getStatsString(0))
Kunshan Wang's avatar
Kunshan Wang committed
252
  }
Kunshan Wang's avatar
Kunshan Wang committed
253 254 255 256 257 258 259

  // Automatically load the boot image if provided
  {
    vmConf.bootImg foreach { fileName =>
      loadBootImage(fileName)
    }
  }
260 261 262 263 264 265 266
  
  override def close(): Unit = {
    maybeNativeArgv.foreach(_.close())
    threadStackManager.close()
    nativeLibraryHolder.close()
    memoryManager.close()
  }
267
}