Commit 4c11b17c authored by Adam R. Nelson's avatar Adam R. Nelson

Merge branch 'master' of https://github.com/microvm/microvm-refimpl2 into client-uir-writer

parents 2608dee4 607995f8
......@@ -9,3 +9,4 @@ target
.tmpBin
.d8_history
hs_err_pid*.log
/bin/
......@@ -2,11 +2,13 @@ Mu Reference Implementation version 2
=====================================
This project is the current reference implementation of Mu, the micro virtual
machine designed by [The Micro Virtual Machine Project](http://microvm.org). It
implements the [Mu Specification version
2](https://github.com/microvm/microvm-spec/wiki)
machine designed by [The Micro Virtual Machine Project](http://microvm.org).
This project is based on the
Version 2.1.x implements the [master branch of the Mu
Specification](https://github.com/microvm/microvm-spec/tree/goto-with-values)
which uses the goto-with-values form.
This project is based on the previous works of
[simplest-microvm-project](https://github.com/microvm/simplest-microvm-project).
[microvm-refimpl](https://github.com/microvm-project/microvm-refimpl) is the
previous reference implementation.
......@@ -21,7 +23,7 @@ How to compile
`brew install scala`.
* Install [sbt](http://www.scala-sbt.org/) 0.13. If you use Mac and Homebrew,
`brew install sbt`.
* Install [Scala IDE](http://scala-ide.org/) 4.0 (Eclipse with pre-installed
* Install [Scala IDE](http://scala-ide.org/) 4.x (Eclipse with pre-installed
plugins for Scala).
* Clone this repository:
......@@ -32,9 +34,7 @@ git clone git@github.com:microvm/microvm-refimpl2.git
* In the directory `microvm-refimpl2`, do the following:
```bash
sbt update
sbt antlr4:antlr4Generate
sbt eclipse
sbt update genSrc eclipse
```
* Open Scala IDE and import the generated project as "existing project into
......@@ -50,15 +50,16 @@ yum, pacman, etc. for GNU/Linux distributions and Homebrew for Mac OS X).
To download all dependencies from the Maven central repository, invoke `sbt
update`.
To generate the Mu IR parser from its Antlr grammar, invoke `sbt
antlr4:antlr4Generate`. The generated sources will be in
`target/scala-2.11/src_managed`. Make sure your IDE can see those generated
sources.
To compile, invoke `sbt compile` or do this in your favourite IDE.
To generate the Mu IR parser from the Antlr grammar, invoke `sbt genSrc`. The
generated sources will be in the `target/scala-2.11/src_managed` directory.
To generate an Eclipse project, install the [sbt-eclipse
plugin](https://github.com/typesafehub/sbteclipse) and invoke `sbt eclipse`.
Make sure you generate the parser before creating the Eclipse project, so that
the generated sources will be on the Eclipse build path.
To compile, invoke `sbt compile`. This will also generate the Mu IR parser using
Antlr.
IntelliJ IDEA has plugins for Scala and SBT. Make sure you don't commit `.idea`
or generated project files into the repository.
......
organization := "org.microvm"
name := "microvm-refimpl2"
lazy val genSrc = taskKey[List[File]]("generate sources")
description := "The second reference implementation of Mu, the micro virtual machine"
genSrc <<= (sourceGenerators in Compile) { _.join.map(_.flatten.toList) }
licenses := Seq("CC BY-SA 4.0" -> url("https://creativecommons.org/licenses/by-sa/4.0/legalcode"))
lazy val root = (project in file(".")).settings(
organization := "org.microvm",
scalaVersion := "2.11.7"
name := "microvm-refimpl2",
version := "2.1.0",
libraryDependencies := Seq(
"org.antlr" % "antlr4" % "4.5.1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.1.0",
"ch.qos.logback" % "logback-classic" % "1.1.2",
"com.github.jnr" % "jnr-ffi" % "2.0.3",
"com.github.jnr" % "jffi" % "1.2.9",
"com.github.jnr" % "jnr-posix" % "3.0.17",
"org.scalatest" %% "scalatest" % "2.2.0" % "test",
"junit" % "junit" % "4.12" % "test"
)
antlr4Settings
description := "The second reference implementation of Mu, the micro virtual machine",
antlr4PackageName in Antlr4 := Some("uvm.ir.textinput.gen")
licenses := Seq("CC BY-SA 4.0" -> url("https://creativecommons.org/licenses/by-sa/4.0/legalcode")),
antlr4GenListener in Antlr4 := false
scalaVersion := "2.11.7",
libraryDependencies ++= Seq(
"org.antlr" % "antlr4" % "4.5.1-1",
"com.typesafe.scala-logging" %% "scala-logging" % "3.1.0",
"ch.qos.logback" % "logback-classic" % "1.1.3",
"com.github.jnr" % "jnr-ffi" % "2.0.7",
"com.github.jnr" % "jffi" % "1.2.10",
"com.github.jnr" % "jnr-posix" % "3.0.23",
"org.scalatest" %% "scalatest" % "2.2.4" % "test",
"junit" % "junit" % "4.12" % "test"
),
testOptions in Test += Tests.Argument("-oF"), // print full stack trace when testing
antlr4Settings,
antlr4PackageName in Antlr4 := Some("uvm.ir.textinput.gen"),
antlr4GenListener in Antlr4 := false,
antlr4GenVisitor in Antlr4 := false
)
antlr4GenVisitor in Antlr4 := false
EclipseKeys.createSrc := EclipseCreateSrc.Default + EclipseCreateSrc.Resource + EclipseCreateSrc.Managed
This diff is collapsed.
FN=$1
if [ x$SED == x ]; then
SED=sed
fi
$SED -i 's/newClientAgent/newContext/g' $FN
$SED -i 's/ClientAgent/MuCtx/g' $FN
$SED -i 's/deleteHandle/deleteValue/g' $FN
$SED -i 's/\bca\b/ctx/g' $FN
$SED -i 's/ctx\.close()/ctx.closeContext()/g' $FN
$SED -i 's/Handle/MuValue/g' $FN
$SED -i 's/putInt("@i32",/handleFromInt32(/g' $FN
$SED -i 's/putInt("@i64",/handleFromInt64(/g' $FN
$SED -i 's/putInt("@i\(\d\+\)"\s*,\s*\([^)]*\))/handleFromInt(\2, \1)/g' $FN
$SED -i 's/putFloat("@float",/handleFromFloat(/g' $FN
$SED -i 's/putDouble("@double",/handleFromDouble(/g' $FN
$SED -i 's/putConstant/handleFromConst/g' $FN
$SED -i 's/putGlobal/handleFromGlobal/g' $FN
$SED -i 's/putFunction/handleFromFunc/g' $FN
$SED -i 's/putExpFunc/handleFromExpose/g' $FN
$SED -i 's/toInt(\(\w\+\),\s*\(signExt\s*=\s*\)\?true)/handleToSInt(\1.asInstanceOf[MuIntValue])/g' $FN
$SED -i 's/toInt(\(\w\+\))/handleToUInt(\1.asInstanceOf[MuIntValue])/g' $FN
$SED -i 's/toFloat/handleToFloat/g' $FN
$SED -i 's/toDouble/handleToDouble/g' $FN
$SED -i 's/toPointer/handleToPtr/g' $FN
$SED -i 's/refCast/refcast/g' $FN
$SED -i 's/currentInstruction/curInst/g' $FN
$SED -i 's/TrapRebindPassVoid/returnFromTrap/g' $FN
$SED -i 's/TrapRebindPassValue(\(\w\+\),\s*\(\w\+\)\s*)/Rebind(\1, PassValues(Seq(\2)))/g' $FN
FN=$1
if [ x$SED == x ]; then
SED=sed
fi
$SED -i 's/\(%\w\+\)\s*=\s*TRAP/[\1] TRAP/g' $FN
$SED -i 's/NEWSTACK\s*<\(@[0-9a-zA-Z._-]\+\)>\s*\(@\w\+\)/COMMINST @uvm.new_stack <[\1]> (\2)/g' $FN
$SED -i 's/COMMINST\s*@uvm\.new_thread\s*(\([@%]\w\+\))/NEWTHREAD \1 PASS_VALUES /g' $FN
$SED -i 's/TRAP\s*<@void>/TRAP <>/g' $FN
$SED -i 's/noparamsnoret/v_v/g' $FN
$SED -i 's/@funcdumb/@frv_v/g' $FN
$SED -i '/\.funcsig/ {s/@void\s*(\([^)]*\))/(\1) -> ()/g}' $FN
$SED -i '/\.funcsig/ {s/=\s*\(@\w\+\)\s*(\([^)]*\))/= (\2) -> (\1)/}' $FN
$SED -i 's/@i_ii/@ii_i/g' $FN
$SED -i 's/RET @VOID/RET ()/g' $FN
$SED -i 's/hybrid\s*<@void\s*/hybrid</g' $FN
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.5.0")
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")
grammar HAIL;
hail
: topLevelDef*
;
topLevelDef
: fixedAlloc
| hybridAlloc
| memInit
;
fixedAlloc
: '.new' nam=HAIL_NAME '<' ty=type '>'
;
hybridAlloc
: '.newhybrid' nam=HAIL_NAME '<' ty=type '>' len=intExpr
;
memInit
: '.init' lv=lValue '=' rv=rValue
;
lValue
: nam=name (indices+=index)*
;
rValue
: GLOBAL_NAME # RVGlobal
| intLiteral # RVInt
| floatLiteral # RVFloat
| doubleLiteral # RVDouble
| 'NULL' # RVNull
| HAIL_NAME # RVHailRef
| '&' lValue # RVIRefOf
| '*' lValue # RVValueOf
| list # RVList
;
list
: '{' rv+=rValue* '}'
;
index
: '[' intExpr ']'
;
intExpr
: intLiteral # IntLit
| GLOBAL_NAME # IntGlobal
;
type
: GLOBAL_NAME
;
name
: GLOBAL_NAME
| HAIL_NAME
;
intLiteral
: INT_DEC
| INT_OCT
| INT_HEX
;
floatLiteral
: FP_NUM 'f' # FloatNumber
| INF 'f' # FloatInf
| NAN 'f' # FloatNan
| 'bitsf' '(' intLiteral ')' # FloatBits
;
doubleLiteral
: FP_NUM 'd' # DoubleNumber
| INF 'd' # DoubleInf
| NAN 'd' # DoubleNan
| 'bitsd' '(' intLiteral ')' # DoubleBits
;
// LEXER
INT_DEC
: ('+'|'-')? DIGIT_NON_ZERO DIGIT*
;
INT_OCT
: ('+'|'-')? '0' OCT_DIGIT*
;
INT_HEX
: ('+'|'-')? '0x' HEX_DIGIT+
;
FP_NUM
: ('+'|'-')? DIGIT+ '.' DIGIT+ ('e' ('+'|'-')? DIGIT+)?
;
INF
: ('+'|'-') 'inf'
;
NAN
: 'nan'
;
GLOBAL_NAME
: GLOBAL_NAME_PREFIX IDCHAR+
;
HAIL_NAME
: HAIL_NAME_PREFIX IDCHAR+
;
fragment
DIGIT
: [0-9]
;
fragment
DIGIT_NON_ZERO
: [1-9]
;
fragment
OCT_DIGIT
: [0-7]
;
fragment
HEX_DIGIT
: [0-9a-fA-F]
;
fragment
GLOBAL_NAME_PREFIX: '@';
fragment
HAIL_NAME_PREFIX: '$';
fragment
IDCHAR
: [a-z]
| [A-Z]
| [0-9]
| '-'
| '_'
| '.'
;
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
LINE_COMMENT
: '//' ~[\r\n]* -> skip
;
This diff is collapsed.
......@@ -2,12 +2,13 @@ package uvm
import uvm.types._
import uvm.ssavariables._
import scala.collection.mutable.HashMap
class Bundle {
abstract class Bundle {
/*
* There is a hierarchy of namespaces. A subnode is a subset of the parent.
*
* + allNs // All Identified entities
* + allNs // All globally Identified entities
* + typeNs // All types
* + funcSigNs // All function signatures
* + funcVerNs // All function versions
......@@ -17,90 +18,107 @@ class Bundle {
* + globalCellNs // Global cells
* + funcNs // Functions
* + expFuncNs // Exposed functions
* + localVarNs // Local variables (per function version)
* + localVarNs // Local variables (per basic block)
* + bbNs // Basic blocks (per function version)
* + instNs // All instructions
* + localInstNs // Instructions in a basic block (per basic block)
*
* TODO: Should there be a global "basic block ns for all function versions"?
* bbNs and localVarNs are part of particular FuncVers and BBs.
*/
val allNs = new SimpleNamespace[Identified]()
val allNs = new NestedNamespace[Identified](None)
val typeNs = new SimpleNamespace[Type]()
val funcSigNs = new SimpleNamespace[FuncSig]()
val funcVerNs = new SimpleNamespace[FuncVer]()
val typeNs = allNs.makeSubSpace[Type]()
val funcSigNs = allNs.makeSubSpace[FuncSig]()
val funcVerNs = allNs.makeSubSpace[FuncVer]()
val varNs = allNs.makeSubSpace[SSAVariable]()
val varNs = new SimpleNamespace[SSAVariable]()
val globalVarNs = new SimpleNamespace[GlobalVariable]()
val constantNs = new SimpleNamespace[Constant]()
val globalCellNs = new SimpleNamespace[GlobalCell]()
val funcNs = new SimpleNamespace[Function]()
val expFuncNs = new SimpleNamespace[ExposedFunc]()
val globalVarNs = varNs.makeSubSpace[GlobalVariable]()
val constantNs = globalVarNs.makeSubSpace[Constant]()
val globalCellNs = globalVarNs.makeSubSpace[GlobalCell]()
val funcNs = globalVarNs.makeSubSpace[Function]()
val expFuncNs = globalVarNs.makeSubSpace[ExposedFunc]()
val instNs = allNs.makeSubSpace[Instruction]()
}
/**
* This kind of bundle is generated when parsing a .UIR file.
* <p>
* In this kind of bundle, a Function does not have a FuncVer as its version.
* The funcNs only contains new functions declared in this bundle, not existing
* functions declared previously. When this bundle is merged with the global bundle,
* both funcNs and funcVerNs are simply merged, and new FuncVer objects become the
* newest version of the Function, whether the Function is newly declared or not.
*/
class TrantientBundle extends Bundle {
/**
* Add an identified entity to its appropriate global namespaces.
* All functions (declared here or previously) that are defined in this bundle.
* <p>
* Mainly for debugging purpose.
*/
def add(obj: Identified): Unit = {
allNs.add(obj)
if (obj.isInstanceOf[Type]) typeNs.add(obj.asInstanceOf[Type])
if (obj.isInstanceOf[FuncSig]) funcSigNs.add(obj.asInstanceOf[FuncSig])
if (obj.isInstanceOf[FuncVer]) funcVerNs.add(obj.asInstanceOf[FuncVer])
if (obj.isInstanceOf[SSAVariable]) varNs.add(obj.asInstanceOf[SSAVariable])
if (obj.isInstanceOf[GlobalVariable]) globalVarNs.add(obj.asInstanceOf[GlobalVariable])
if (obj.isInstanceOf[Constant]) constantNs.add(obj.asInstanceOf[Constant])
if (obj.isInstanceOf[GlobalCell]) globalCellNs.add(obj.asInstanceOf[GlobalCell])
if (obj.isInstanceOf[Function]) funcNs.add(obj.asInstanceOf[Function])
if (obj.isInstanceOf[ExposedFunc]) expFuncNs.add(obj.asInstanceOf[ExposedFunc])
}
//val defFuncNs = new SimpleNamespace[Function]
}
/**
* This kind of bundle holds the global state. Functions and versions are fully merged.
*/
class GlobalBundle extends Bundle {
private def simpleMerge[T <: Identified](oldNs: Namespace[T], newNs: Namespace[T]) {
for (cand <- newNs.all) {
if (!cand.isInstanceOf[Function] || oldNs.get(cand.id) == None) {
// Function merging happens separately. Only add a function if it does not redefine an old one.
try {
oldNs.add(cand)
} catch {
case e: NameConflictException =>
throw new IllegalRedefinitionException(
"Redefinition of type, function signature, constant or" +
" global cell is not allowed", e);
}
try {
oldNs.add(cand)
// def assertPresent[T <: Identified](ns: NestedNamespace[T], obj: T): Unit = {
// assert(ns.get(obj.id) == Some(obj))
// if (obj.id == 65731) {
// printf("Obj[65731] found in ns " + ns)
// }
// ns.maybeParent match {
// case None =>
// case Some(ns2) =>
// assertPresent(ns2, obj)
// }
// }
// assertPresent(oldNs.asInstanceOf[NestedNamespace[T]], cand)
} catch {
case e: NameConflictException =>
throw new IllegalRedefinitionException(
"Redefinition of type, function signature, constant or" +
" global cell is not allowed: %s".format(cand.repr), e);
}
}
}
private def mergeFunc(oldNs: Namespace[Function], newNs: Namespace[Function]) {
for (cand <- newNs.all) {
val id = cand.id
oldNs.get(id) match {
case None => oldNs.add(cand)
case Some(oldObj) =>
oldObj.versions = cand.versions.head :: oldObj.versions
cand.versions.head.func = oldObj
}
private def redefineFunctions(newNs: Namespace[FuncVer]) {
for (fv <- newNs.all) {
fv.func.versions = fv :: fv.func.versions
}
}
private def fixExpFuncs(oldNs: Namespace[Function], newNs: Namespace[ExposedFunc]) {
for (expFunc <- newNs.all) {
val funcID = expFunc.func.id
oldNs.get(funcID) match {
case None =>
case Some(oldFunc) => expFunc.func = oldFunc
private def mergeLocalNamespaces(newBundle: TrantientBundle) {
for (fv <- newBundle.funcVerNs.all) {
fv.bbNs.reparent(allNs)
for (bb <- fv.bbs) {
bb.localVarNs.reparent(allNs)
bb.localInstNs.reparent(allNs)
}
}
}
def merge(newBundle: Bundle) {
simpleMerge(allNs, newBundle.allNs)
def merge(newBundle: TrantientBundle) {
// Only merge leaves
simpleMerge(typeNs, newBundle.typeNs)
simpleMerge(funcSigNs, newBundle.funcSigNs)
simpleMerge(funcVerNs, newBundle.funcVerNs)
simpleMerge(varNs, newBundle.varNs)
simpleMerge(globalVarNs, newBundle.globalVarNs)
simpleMerge(constantNs, newBundle.constantNs)
simpleMerge(globalCellNs, newBundle.globalCellNs)
mergeFunc(funcNs, newBundle.funcNs)
simpleMerge(funcNs, newBundle.funcNs)
simpleMerge(expFuncNs, newBundle.expFuncNs)
fixExpFuncs(funcNs, newBundle.expFuncNs)
simpleMerge(instNs, newBundle.instNs)
redefineFunctions(newBundle.funcVerNs)
mergeLocalNamespaces(newBundle)
}
}
}
\ No newline at end of file
......@@ -5,9 +5,31 @@ trait Identified {
def name: Option[String]
def repr: String = "[%d:%s]".format(id, name.getOrElse("_"))
// Identified objects should use reference equality rather than structural equality. (case classes use the latter)
override def hashCode(): Int = if (id != 0) id else System.identityHashCode(this)
override def equals(that: Any): Boolean = that match {
case v: AnyRef => this eq v
case _ => false
}
override def toString = "%s%s".format(this.getClass.getSimpleName, this.repr)
}
trait IdentifiedSettable extends Identified {
var id: Int = 0
var name: Option[String] = None
}
\ No newline at end of file
}
object RichIdentifiedSettable {
implicit class RichIdentifiedSettable[T <: IdentifiedSettable](val is: T) extends AnyVal {
def :=(p: Int): T = {
is.id = p
is
}
def :=(p: (Int, String)): T = {
is.id = p._1
is.name = Some(p._2)
is
}
}
}
......@@ -11,7 +11,7 @@ object CommInsts extends SimpleNamespace[CommInst] {
add(ci)
}
commInst(0x201, "@uvm.new_thread")
commInst(0x201, "@uvm.new_stack")
commInst(0x202, "@uvm.kill_stack")
commInst(0x203, "@uvm.thread_exit")
commInst(0x204, "@uvm.current_stack")
......@@ -39,4 +39,28 @@ object CommInsts extends SimpleNamespace[CommInst] {
commInst(0x242, "@uvm.native.expose")
commInst(0x243, "@uvm.native.unexpose")
commInst(0x244, "@uvm.native.get_cookie")
commInst(0x250, "@uvm.meta.id_of")
commInst(0x251, "@uvm.meta.name_of")
commInst(0x252, "@uvm.meta.load_bundle")
commInst(0x253, "@uvm.meta.load_hail")
commInst(0x254, "@uvm.meta.new_cursor")
commInst(0x255, "@uvm.meta.next_frame")
commInst(0x256, "@uvm.meta.copy_cursor")
commInst(0x257, "@uvm.meta.close_cursor")
commInst(0x258, "@uvm.meta.cur_func")
commInst(0x259, "@uvm.meta.cur_func_ver")
commInst(0x25a, "@uvm.meta.cur_inst")
commInst(0x25b, "@uvm.meta.dump_keepalives")
commInst(0x25c, "@uvm.meta.pop_frames_to")
commInst(0x25d, "@uvm.meta.push_frame")
commInst(0x25e, "@uvm.meta.enable_watchpoint")
commInst(0x25f, "@uvm.meta.disable_watchpoint")
commInst(0x260, "@uvm.meta.set_trap_handler")
}
\ No newline at end of file
......@@ -3,11 +3,15 @@ package uvm
import uvm.types._
import uvm.ssavariables._
case class FuncSig(var retTy: Type, var paramTy: Seq[Type]) extends IdentifiedSettable
case class FuncSig(var paramTys: Seq[Type], var retTys: Seq[Type]) extends IdentifiedSettable {
override final def toString: String = FuncSig.prettyPrint(this)
}
object FuncSig {
def prettyPrint(sig: FuncSig): String =
"%s (%s)".format(sig.retTy.repr, sig.paramTy.map(_.repr).mkString(" "))
def prettyPrint(sig: FuncSig): String = {
def mkReprList(is: Seq[Identified]): String = is.map(_.repr).mkString(" ")
"(%s) -> (%s)".format(mkReprList(sig.paramTys), mkReprList(sig.retTys))
}
}
class Function extends GlobalVariable {
......@@ -22,14 +26,17 @@ class FuncVer extends IdentifiedSettable {
var func: Function = null
var bbs: Seq[BasicBlock] = null
var entry: BasicBlock = null
var params: Seq[Parameter] = null
val bbNs: Namespace[BasicBlock] = new SimpleNamespace[BasicBlock]()
val localVarNs: Namespace[LocalVariable] = new SimpleNamespace[LocalVariable]()
def sig: FuncSig = func.sig
var bbNs: NestedNamespace[BasicBlock] = null // sub-namespace of allNs
}
class BasicBlock extends IdentifiedSettable {
var norParams: Seq[NorParam] = null
var excParam: Option[ExcParam] = null
var insts: Seq[Instruction] = null
var localVarNs: NestedNamespace[LocalVariable] = null // sub-namespace of allNs
var localInstNs: NestedNamespace[Instruction] = null // sub-namespace of allNs
}
package uvm.hail
import scala.collection.mutable.ArrayBuffer
import uvm.IdentifiedSettable
import uvm.types.Type
import uvm.ssavariables.GlobalVariable
import uvm.types.TypeHybrid
trait Locatable {
val line: Int
val col: Int
val span: Int
}
class HailScript {
val defs = new ArrayBuffer[HailDef]()
}
abstract class HailDef
abstract class HailAlloc extends HailDef with IdentifiedSettable
case class NewFixed(ty: Type) extends HailAlloc
case class NewHybrid(ty: TypeHybrid, len: Long) extends HailAlloc
case class Init(lv: LValue, rv: RValue) extends HailDef
case class LValue(base: Base, indices: Seq[Long])
abstract class Base
case class BaseGlobal(gv: GlobalVariable)
case class BaseHail(ha: HailAlloc)
abstract class RValue
case class RVGlobal(gv: GlobalVariable) extends RValue
case class RVInt(num: Long) extends RValue
case class RVFloat(num: Float) extends RValue
case class RVDouble(num: Double) extends RValue
case class RVNull() extends RValue
case class RVHailRef(ha: HailAlloc) extends RValue
case class RVIRefOf(lv: LValue) extends RValue
case class RVList(rvs: Seq[RValue]) extends RValue