Skip to content

adding GenBCode to dotc #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Feb 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/Compiler.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import reporting.ConsoleReporter

class Compiler {

def phases = List(new FrontEnd)
def phases = List(new FrontEnd, new backend.jvm.GenBCode.BCodePhase)

def rootContext(implicit ctx: Context): Context = {
ctx.definitions.init()
Expand Down
117 changes: 102 additions & 15 deletions src/dotty/tools/dotc/backend/jvm/BCodeBodyBuilder.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
*/


package scala
package tools.nsc
package dotty.tools
package dotc
package backend
package jvm

Expand All @@ -14,23 +14,31 @@ import scala.annotation.switch

import scala.tools.asm

import dotc.ast.Trees._
import core.Types.Type
import core.StdNames
import core.Symbols.{Symbol, NoSymbol}
import core.Constants.Constant

/*
*
* @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/
* @version 1.0
*
*/
abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
import global._
import definitions._

import ast.tpd._

/*
* Functionality to build the body of ASM MethodNode, except for `synchronized` and `try` expressions.
*/
abstract class PlainBodyBuilder(cunit: CompilationUnit) extends PlainSkelBuilder(cunit) {
abstract class PlainBodyBuilder(cunit: CompilationUnit,
implicit val ctx: dotc.core.Contexts.Context) extends PlainSkelBuilder(cunit) {

import icodes.TestOp
import icodes.opcodes.InvokeStyle
import StdNames.nme

/* If the selector type has a member with the right name,
* it is the host class; otherwise the symbol's owner.
Expand Down Expand Up @@ -218,10 +226,83 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
resKind
}

/**
* Return the primitive code of the given operation. If the
* operation is an array get/set, we inspect the type of the receiver
* to demux the operation.
*
* @param fun The method symbol
* @param tpe The type of the receiver object. It is used only for array
* operations
*/
def getPrimitive(fun: Symbol, tpe: Type): Int = {
val code = scalaPrimitives.getPrimitive(fun)

def elementType = enteringTyper {
val arrayParent = tpe :: tpe.parents collectFirst {
case dotc.core.Types.TypeRef(_, ArrayClass, elem :: Nil) => elem
}
arrayParent getOrElse sys.error(fun.fullName + " : " + (tpe :: tpe.baseTypeSeq.toList).mkString(", "))
}

import scalaPrimitives._

code match {

case APPLY =>
toTypeKind(elementType) match {
case BType.BOOLEAN_TYPE => ZARRAY_GET
case BType.BYTE_TYPE => BARRAY_GET
case BType.SHORT_TYPE => SARRAY_GET
case BType.CHAR_TYPE => CARRAY_GET
case BType.INT_TYPE => IARRAY_GET
case BType.LONG_TYPE => LARRAY_GET
case BType.FLOAT_TYPE => FARRAY_GET
case BType.DOUBLE_TYPE => DARRAY_GET
case r =>
assert(r.isRefOrArrayType)
OARRAY_GET
}

case UPDATE =>
toTypeKind(elementType) match {
case BType.BOOLEAN_TYPE => ZARRAY_SET
case BType.BYTE_TYPE => BARRAY_SET
case BType.SHORT_TYPE => SARRAY_SET
case BType.CHAR_TYPE => CARRAY_SET
case BType.INT_TYPE => IARRAY_SET
case BType.LONG_TYPE => LARRAY_SET
case BType.FLOAT_TYPE => FARRAY_SET
case BType.DOUBLE_TYPE => DARRAY_SET
case r =>
assert(r.isRefOrArrayType)
OARRAY_SET
}

case LENGTH =>
toTypeKind(elementType) match {
case BType.BOOLEAN_TYPE => ZARRAY_LENGTH
case BType.BYTE_TYPE => BARRAY_LENGTH
case BType.SHORT_TYPE => SARRAY_LENGTH
case BType.CHAR_TYPE => CARRAY_LENGTH
case BType.INT_TYPE => IARRAY_LENGTH
case BType.LONG_TYPE => LARRAY_LENGTH
case BType.FLOAT_TYPE => FARRAY_LENGTH
case BType.DOUBLE_TYPE => DARRAY_LENGTH
case r =>
assert(r.isRefOrArrayType)
OARRAY_LENGTH
}

case _ =>
code
}
}

def genPrimitiveOp(tree: Apply, expectedType: BType): BType = {
val sym = tree.symbol
val Apply(fun @ Select(receiver, _), _) = tree
val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
val code = getPrimitive(sym, receiver.tpe)

import scalaPrimitives.{isArithmeticOp, isArrayOp, isLogicalOp, isComparisonOp}

Expand Down Expand Up @@ -306,7 +387,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case app : Apply =>
generatedType = genApply(app, expectedType)

case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.")
// case ApplyDynamic(qual, args) => sys.error("No invokedynamic support yet.")

case This(qual) =>
val symIsModuleClass = tree.symbol.isModuleClass
Expand Down Expand Up @@ -359,10 +440,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {

case Literal(value) =>
if (value.tag != UnitTag) (value.tag, expectedType) match {
case (IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG
case (FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE
case (NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL
case _ => genConstant(value); generatedType = tpeTK(tree)
case (dotc.core.Constants.IntTag, LONG ) => bc.lconst(value.longValue); generatedType = LONG
case (dotc.core.Constants.FloatTag, DOUBLE) => bc.dconst(value.doubleValue); generatedType = DOUBLE
case (dotc.core.Constants.NullTag, _ ) => bc.emit(asm.Opcodes.ACONST_NULL); generatedType = RT_NULL
case _ => genConstant(value); generatedType = tpeTK(tree)
}

case blck : Block => genBlock(blck, expectedType)
Expand Down Expand Up @@ -434,6 +515,9 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
* Otherwise it's safe to call from multiple threads.
*/
def genConstant(const: Constant) {

import dotc.core.Constants._

(const.tag: @switch) match {

case BooleanTag => bc.boolconst(const.booleanValue)
Expand Down Expand Up @@ -825,7 +909,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
}

/* Generate code that loads args into label parameters. */
def genLoadLabelArguments(args: List[Tree], lblDef: LabelDef, gotoPos: Position) {
def genLoadLabelArguments(args: List[Tree], lblDef: LabelDef, gotoPos: dotc.util.Positions.Position) {

val aps = {
val params: List[Symbol] = lblDef.params.map(_.symbol)
Expand Down Expand Up @@ -936,7 +1020,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
StringReference
}

def genCallMethod(method: Symbol, style: InvokeStyle, hostClass0: Symbol = null, pos: Position = NoPosition) {
def genCallMethod(method: Symbol,
style: InvokeStyle,
hostClass0: Symbol = null,
pos: dotc.util.Positions.Position = dotc.util.Positions.NoPosition) {

val siteSymbol = claszSymbol
val hostSymbol = if (hostClass0 == null) method.owner else hostClass0;
Expand Down Expand Up @@ -1118,7 +1205,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
tree match {

case Apply(fun, args) if isPrimitive(fun.symbol) =>
import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ, getPrimitive }
import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ }

// lhs and rhs of test
lazy val Select(lhs, _) = fun
Expand All @@ -1135,7 +1222,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
genCond(rhs, success, failure)
}

getPrimitive(fun.symbol) match {
scalaPrimitives.getPrimitive(fun.symbol) match {
case ZNOT => genCond(lhs, failure, success)
case ZAND => genZandOrZor(and = true)
case ZOR => genZandOrZor(and = false)
Expand Down
27 changes: 15 additions & 12 deletions src/dotty/tools/dotc/backend/jvm/BCodeGlue.scala
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,31 @@
* @author Martin Odersky
*/

package scala
package tools.nsc
package dotty.tools
package dotc
package backend.jvm

import scala.tools.asm
import scala.annotation.switch
import scala.collection.{ immutable, mutable }

import dotc.ast.Trees.Tree
import dotc.core.Types.Type
import dotc.core.Symbols.{Symbol, NoSymbol}

/*
* Immutable representations of bytecode-level types.
*
* @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded
* @version 1.0
*
*/
abstract class BCodeGlue extends SubComponent {

import global._
abstract class BCodeGlue {

object BType {

import global.chrs
import core.Names
import Names.chrs

// ------------- sorts -------------

Expand Down Expand Up @@ -124,7 +127,7 @@ abstract class BCodeGlue extends SubComponent {
* must-single-thread
*/
def getMethodType(methodDescriptor: String): BType = {
val n = global.newTypeName(methodDescriptor)
val n = Names.typeName(methodDescriptor)
new BType(BType.METHOD, n.start, n.length) // TODO assert isValidMethodDescriptor
}

Expand All @@ -138,7 +141,7 @@ abstract class BCodeGlue extends SubComponent {
* must-single-thread
*/
def getMethodType(returnType: BType, argumentTypes: Array[BType]): BType = {
val n = global.newTypeName(getMethodDescriptor(returnType, argumentTypes))
val n = Names.typeName(getMethodDescriptor(returnType, argumentTypes))
new BType(BType.METHOD, n.start, n.length)
}

Expand Down Expand Up @@ -206,7 +209,7 @@ abstract class BCodeGlue extends SubComponent {
* must-single-thread
*/
def getReturnType(methodDescriptor: String): BType = {
val n = global.newTypeName(methodDescriptor)
val n = Names.typeName(methodDescriptor)
val delta = n.pos(')') // `delta` is relative to the Name's zero-based start position, not a valid index into chrs.
assert(delta < n.length, s"not a valid method descriptor: $methodDescriptor")
getType(n.start + delta + 1)
Expand Down Expand Up @@ -248,7 +251,7 @@ abstract class BCodeGlue extends SubComponent {
*/
final class BType(val sort: Int, val off: Int, val len: Int) {

import global.chrs
import core.Names.chrs

/*
* can-multi-thread
Expand Down Expand Up @@ -619,15 +622,15 @@ abstract class BCodeGlue extends SubComponent {
*
* must-single-thread
*/
def brefType(iname: String): BType = { brefType(newTypeName(iname.toCharArray(), 0, iname.length())) }
def brefType(iname: String): BType = { brefType(dotc.core.Names.typeName(iname.toCharArray(), 0, iname.length())) }

/*
* Creates a BType token for the TypeName received as argument.
* This method does not add to `innerClassBufferASM`, use `internalName()` or `asmType()` or `toTypeKind()` for that.
*
* can-multi-thread
*/
def brefType(iname: TypeName): BType = { BType.getObjectType(iname.start, iname.length) }
def brefType(iname: core.Names.TypeName): BType = { BType.getObjectType(iname.start, iname.length) }

// due to keyboard economy only
val UNIT = BType.VOID_TYPE
Expand Down
Loading