Skip to content
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

Sharing GenBcode backend between scalac and dotty #4136

Closed
wants to merge 46 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
3d66b0d
Factoring out methods used in backend. No direct usages of global any…
DarkDimius Nov 14, 2014
7537cb6
Reduced number of methods used in backend.
DarkDimius Nov 14, 2014
f15d62a
Factoring out definitions used in backend.
DarkDimius Nov 14, 2014
e081724
Starting to implement interfaces for scalac
DarkDimius Nov 14, 2014
61fac46
Organise members of SymbolHelpers.
DarkDimius Nov 17, 2014
31e1c55
Use name-based pattern matching in backend
DarkDimius Nov 18, 2014
78acb5a
Make sure genIcode and genASM compile.
DarkDimius Nov 18, 2014
c93b3b4
Use name-based pattern matching for deconstructors, using same instan…
DarkDimius Nov 18, 2014
7131476
Implement BackendInterface for scalac
DarkDimius Nov 18, 2014
284915c
Start using ScalacBackendInterface.
DarkDimius Nov 18, 2014
3c89b52
Fix initialization order problem.
DarkDimius Nov 18, 2014
4c66397
ScalacBackend should now be functional.
DarkDimius Nov 18, 2014
6783bec
Avoid initialization order problem
retronym Nov 18, 2014
de1efa9
Fixing bugs introduced while porting.
DarkDimius Nov 20, 2014
b1d096f
Adapt unit tests to use ScalacBackendInterface
DarkDimius Nov 20, 2014
9986e7d
Scala requires compilation unit to generate fresh symbol
DarkDimius Nov 20, 2014
d37adac
It seems that for tests order of definitions inside Definitions matters.
DarkDimius Nov 20, 2014
82d137f
Move in shared implementation between dotty and scalac.
DarkDimius Nov 24, 2014
9300268
Workaround name-based pattern matching creating tuples for ValDefs.
DarkDimius Nov 24, 2014
2d0104d
Fix error in BCodeBodyBuilder.
DarkDimius Nov 24, 2014
20b3c04
Get rid of most of allocations in ScalacBackendInterface
DarkDimius Nov 26, 2014
0b2e0c5
Fix several bugs introduced by capturing a sub pattern instead of per…
DarkDimius Nov 26, 2014
fa98eea
Make reading of source easier by giving a bit more structure.
DarkDimius Nov 26, 2014
fa67f6c
There's no support for early initialisers in dotty. Make initialisati…
DarkDimius Nov 27, 2014
f9b3cf1
Handle Dotty Idents
DarkDimius Nov 27, 2014
0e1fec4
Handle dotty typeApply.
DarkDimius Nov 27, 2014
084cc06
Refactor genArrayValue, so that array creation from elements could be…
DarkDimius Nov 27, 2014
5b1ef8c
Minimal set of modifications to allow to support both dotty <label> D…
DarkDimius Dec 1, 2014
b8d14a1
A bit more abstraction on what are primitives and operations on them.
DarkDimius Dec 1, 2014
2d22839
Remove allocations of Options also for Product1 extractors.
DarkDimius Dec 2, 2014
e6c183a
Handle Dotty Closures. Generate InvokeDynamic for them. Give a basis …
DarkDimius Dec 2, 2014
77f2fad
Give types and positions to all symbols that backend creates.
DarkDimius Dec 3, 2014
d62f7bf
Address reviewers comments: less casts needed.
DarkDimius Dec 3, 2014
0581a7c
Make difference between java private flag and scala private flag.
DarkDimius Dec 3, 2014
61fb9a5
Use 2.11.5-SNAPSHOT for star until 2.11.5 is released.
DarkDimius Dec 3, 2014
57274f8
Dotty specific: handle lading of This in types.
DarkDimius Dec 4, 2014
1439f45
Uniform handling of scalac ArrayValue and JavaSeqLiteral in dotty.
DarkDimius Dec 4, 2014
5215341
Handle Selects inside closures.
DarkDimius Dec 4, 2014
0bbab5c
Initial generation of default methods.
DarkDimius Dec 4, 2014
8628f92
snapshot scala
lrytz Dec 5, 2014
2712a22
Merge pull request #1 from lrytz/sharedBackend
DarkDimius Dec 5, 2014
658e2f6
Merge branch 'sharing-backend' of github.com:DarkDimius/scala into sh…
DarkDimius Dec 5, 2014
9392c81
Handle dotty Idents by desugaring them into selects.
DarkDimius Dec 5, 2014
3ec6c6f
SI-9003 Eagerly capture more potentially mutable binders
retronym Nov 26, 2014
cdaf6dc
Even more handling of primitives by trees.
DarkDimius Dec 5, 2014
beaa78b
Merge branch 'sharing-backend' of github.com:DarkDimius/scala into sh…
DarkDimius Dec 12, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.xml
Expand Up @@ -304,6 +304,7 @@ TODO:
</artifact:dependencies>

<artifact:remoteRepository id="sonatype-release" url="https://oss.sonatype.org/content/repositories/releases"/>
<artifact:remoteRepository id="sonatype-snapshot" url="https://oss.sonatype.org/content/repositories/snapshots"/>
<artifact:remoteRepository id="extra-repo" url="${extra.repo.url}"/>

<!-- prepare, for each of the names below, the property "@{name}.cross", set to the
Expand Down Expand Up @@ -375,6 +376,7 @@ TODO:

<echo message="Using Scala ${starr.version} for STARR."/>
<artifact:dependencies pathId="starr.compiler.path" filesetId="starr.fileset">
<artifact:remoteRepository refid="sonatype-snapshot"/>
<artifact:remoteRepository refid="extra-repo"/>
<dependency groupId="org.scala-lang" artifactId="scala-library" version="${starr.version}"/>
<dependency groupId="org.scala-lang" artifactId="scala-reflect" version="${starr.version}"/>
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/scala/tools/nsc/Global.scala
Expand Up @@ -28,8 +28,7 @@ import transform.patmat.PatternMatching
import transform._
import backend.icode.{ ICodes, GenICode, ICodeCheckers }
import backend.{ ScalaPrimitives, JavaPlatform }
import backend.jvm.GenBCode
import backend.jvm.GenASM
import scala.tools.nsc.backend.jvm.{ScalacBackendInterface, GenBCode, GenASM}
import backend.opt.{ Inliners, InlineExceptionHandlers, ConstantOptimization, ClosureElimination, DeadCodeElimination }
import backend.icode.analysis._
import scala.language.postfixOps
Expand Down Expand Up @@ -632,7 +631,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter)
val global: Global.this.type = Global.this
val runsAfter = List("dce")
val runsRightAfter = None
} with GenBCode
} with GenBCode {
lazy val int = new ScalacBackendInterface[global.type](global)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when looking through the entire diff of this PR, there's 4 instances of new ScalacBackendInterface - one ought to be enough, no?

}

// phaseName = "terminal"
object terminal extends {
Expand Down
478 changes: 243 additions & 235 deletions src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala

Large diffs are not rendered by default.

76 changes: 41 additions & 35 deletions src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
Expand Up @@ -11,6 +11,7 @@ package icode

import scala.collection.{ mutable, immutable }
import scala.collection.mutable.{ ListBuffer, Buffer }
import scala.tools.nsc.backend.jvm.ScalacBackendInterface
import scala.tools.nsc.symtab._
import scala.annotation.switch

Expand All @@ -21,15 +22,17 @@ import scala.annotation.switch
abstract class GenICode extends SubComponent {
import global._
import icodes._
import Primitives._
import icodes.opcodes._
import Opcodes._
import definitions._
import scalaPrimitives.{
import ScalaPrimitives.{
isArrayOp, isComparisonOp, isLogicalOp,
isUniversalEqualityOp, isReferenceEqualityOp
}
import platform.isMaybeBoxed

private val bCodeICodeCommon: jvm.BCodeICodeCommon[global.type] = new jvm.BCodeICodeCommon(global)
private lazy val int: ScalacBackendInterface[global.type] = new ScalacBackendInterface[global.type](global)
private lazy val bCodeICodeCommon: jvm.BCodeICodeCommon[int.type] = new jvm.BCodeICodeCommon(int)
import bCodeICodeCommon._

val phaseName = "icode"
Expand Down Expand Up @@ -212,11 +215,11 @@ abstract class GenICode extends SubComponent {
case Nil =>
ctx1 = genLoad(larg, ctx1, resKind)
code match {
case scalaPrimitives.POS =>
case ScalaPrimitives.POS =>
() // nothing
case scalaPrimitives.NEG =>
case ScalaPrimitives.NEG =>
ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), larg.pos)
case scalaPrimitives.NOT =>
case ScalaPrimitives.NOT =>
ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), larg.pos)
case _ =>
abort("Unknown unary operation: " + fun.symbol.fullName +
Expand All @@ -226,27 +229,27 @@ abstract class GenICode extends SubComponent {
// binary operation
case rarg :: Nil =>
resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil)
if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
if (ScalaPrimitives.isShiftOp(code) || ScalaPrimitives.isBitwiseOp(code))
assert(resKind.isIntegralType | resKind == BOOL,
resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1)

ctx1 = genLoad(larg, ctx1, resKind)
ctx1 = genLoad(rarg,
ctx1, // check .NET size of shift arguments!
if (scalaPrimitives.isShiftOp(code)) INT else resKind)
if (ScalaPrimitives.isShiftOp(code)) INT else resKind)

val primitiveOp = code match {
case scalaPrimitives.ADD => Arithmetic(ADD, resKind)
case scalaPrimitives.SUB => Arithmetic(SUB, resKind)
case scalaPrimitives.MUL => Arithmetic(MUL, resKind)
case scalaPrimitives.DIV => Arithmetic(DIV, resKind)
case scalaPrimitives.MOD => Arithmetic(REM, resKind)
case scalaPrimitives.OR => Logical(OR, resKind)
case scalaPrimitives.XOR => Logical(XOR, resKind)
case scalaPrimitives.AND => Logical(AND, resKind)
case scalaPrimitives.LSL => Shift(LSL, resKind)
case scalaPrimitives.LSR => Shift(LSR, resKind)
case scalaPrimitives.ASR => Shift(ASR, resKind)
case ScalaPrimitives.ADD => Arithmetic(ADD, resKind)
case ScalaPrimitives.SUB => Arithmetic(SUB, resKind)
case ScalaPrimitives.MUL => Arithmetic(MUL, resKind)
case ScalaPrimitives.DIV => Arithmetic(DIV, resKind)
case ScalaPrimitives.MOD => Arithmetic(REM, resKind)
case ScalaPrimitives.OR => Logical(OR, resKind)
case ScalaPrimitives.XOR => Logical(XOR, resKind)
case ScalaPrimitives.AND => Logical(AND, resKind)
case ScalaPrimitives.LSL => Shift(LSL, resKind)
case ScalaPrimitives.LSR => Shift(LSR, resKind)
case ScalaPrimitives.ASR => Shift(ASR, resKind)
case _ => abort("Unknown primitive: " + fun.symbol + "[" + code + "]")
}
ctx1.bb.emit(CALL_PRIMITIVE(primitiveOp), tree.pos)
Expand All @@ -269,7 +272,7 @@ abstract class GenICode extends SubComponent {

var generatedType = expectedType

if (scalaPrimitives.isArrayGet(code)) {
if (ScalaPrimitives.isArrayGet(code)) {
// load argument on stack
debugassert(args.length == 1,
"Too many arguments for array get operation: " + tree)
Expand All @@ -282,7 +285,7 @@ abstract class GenICode extends SubComponent {
// probably isn't common enough to figure out an optimization
adaptNullRef(generatedType, expectedType, ctx1, tree.pos)
}
else if (scalaPrimitives.isArraySet(code)) {
else if (ScalaPrimitives.isArraySet(code)) {
debugassert(args.length == 2,
"Too many arguments for array set operation: " + tree)
ctx1 = genLoad(args.head, ctx1, INT)
Expand Down Expand Up @@ -428,11 +431,11 @@ abstract class GenICode extends SubComponent {
val Apply(fun @ Select(receiver, _), _) = tree
val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)

if (scalaPrimitives.isArithmeticOp(code))
if (ScalaPrimitives.isArithmeticOp(code))
genArithmeticOp(tree, ctx, code)
else if (code == scalaPrimitives.CONCAT)
else if (code == ScalaPrimitives.CONCAT)
(genStringConcat(tree, ctx), StringReference)
else if (code == scalaPrimitives.HASH)
else if (code == ScalaPrimitives.HASH)
(genScalaHash(receiver, ctx), INT)
else if (isArrayOp(code))
genArrayOp(tree, ctx, code, expectedType)
Expand All @@ -450,9 +453,9 @@ abstract class GenICode extends SubComponent {
)
(afterCtx, BOOL)
}
else if (code == scalaPrimitives.SYNCHRONIZED)
else if (code == ScalaPrimitives.SYNCHRONIZED)
genSynchronized(tree, ctx, expectedType)
else if (scalaPrimitives.isCoercion(code)) {
else if (ScalaPrimitives.isCoercion(code)) {
val ctx1 = genLoad(receiver, ctx, toTypeKind(receiver.tpe))
genCoercion(tree, ctx1, code)
(ctx1, scalaPrimitives.generatedKind(code))
Expand Down Expand Up @@ -646,7 +649,7 @@ abstract class GenICode extends SubComponent {
case Apply(fun @ Select(Super(_, mix), _), args) =>
def genLoadApply2 = {
debuglog("Call to super: " + tree)
val invokeStyle = SuperCall(mix)
val invokeStyle = SuperCall(mix.toString)
// if (fun.symbol.isConstructor) Static(true) else SuperCall(mix);

ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
Expand Down Expand Up @@ -1186,6 +1189,8 @@ abstract class GenICode extends SubComponent {
*/
def genCoercion(tree: Tree, ctx: Context, code: Int) = {
import scalaPrimitives._
import ScalaPrimitives._
import Primitives._
(code: @switch) match {
case B2B => ()
case B2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, CHAR)), tree.pos)
Expand Down Expand Up @@ -1320,7 +1325,7 @@ abstract class GenICode extends SubComponent {
def liftStringConcat(tree: Tree): List[Tree] = tree match {
case Apply(fun @ Select(larg, method), rarg) =>
if (isPrimitive(fun.symbol) &&
scalaPrimitives.getPrimitive(fun.symbol) == scalaPrimitives.CONCAT)
scalaPrimitives.getPrimitive(fun.symbol) == ScalaPrimitives.CONCAT)
liftStringConcat(larg) ::: rarg
else
List(tree)
Expand Down Expand Up @@ -1369,12 +1374,12 @@ abstract class GenICode extends SubComponent {
*/
def genComparisonOp(l: Tree, r: Tree, code: Int): Boolean = {
val op: TestOp = code match {
case scalaPrimitives.LT => LT
case scalaPrimitives.LE => LE
case scalaPrimitives.GT => GT
case scalaPrimitives.GE => GE
case scalaPrimitives.ID | scalaPrimitives.EQ => EQ
case scalaPrimitives.NI | scalaPrimitives.NE => NE
case ScalaPrimitives.LT => LT
case ScalaPrimitives.LE => LE
case ScalaPrimitives.GT => GT
case ScalaPrimitives.GE => GE
case ScalaPrimitives.ID | ScalaPrimitives.EQ => EQ
case ScalaPrimitives.NI | ScalaPrimitives.NE => NE

case _ => abort("Unknown comparison primitive: " + code)
}
Expand Down Expand Up @@ -1415,7 +1420,8 @@ abstract class GenICode extends SubComponent {
tree match {
// The comparison symbol is in ScalaPrimitives's "primitives" map
case Apply(fun, args) if isPrimitive(fun.symbol) =>
import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ, getPrimitive }
import ScalaPrimitives.{ ZNOT, ZAND, ZOR, EQ}
import scalaPrimitives.getPrimitive

// lhs and rhs of test
lazy val Select(lhs, _) = fun
Expand Down
20 changes: 11 additions & 9 deletions src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala
Expand Up @@ -13,6 +13,8 @@ import scala.collection.mutable.ListBuffer
abstract class ICodeCheckers {
val global: Global
import global._
import Primitives._
import Opcodes._

/** <p>
* This class performs a set of checks similar to what the bytecode
Expand Down Expand Up @@ -520,49 +522,49 @@ abstract class ICodeCheckers {
case CALL_PRIMITIVE(primitive) =>
checkStack(instr.consumed)
primitive match {
case Negation(kind) =>
case Negation(kind: TypeKind) =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need those type annotations?

checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE)
checkType(popStack, kind)
pushStack(kind)

case Test(op, kind, zero) =>
case Test(op, kind: TypeKind, zero) =>
if (zero) checkType(popStack, kind)
else checkBinop(kind)

pushStack(BOOL)

case Comparison(op, kind) =>
case Comparison(op, kind: TypeKind) =>
checkNumeric(kind)
checkBinop(kind)
pushStack(INT)

case Arithmetic(op, kind) =>
case Arithmetic(op, kind: TypeKind) =>
checkNumeric(kind)
if (op == NOT)
checkType(popStack, kind)
else
checkBinop(kind)
pushStack(kind)

case Logical(op, kind) =>
case Logical(op, kind: TypeKind) =>
checkType(kind, BOOL, BYTE, CHAR, SHORT, INT, LONG)
checkBinop(kind)
pushStack(kind)

case Shift(op, kind) =>
case Shift(op, kind: TypeKind) =>
checkType(kind, BYTE, CHAR, SHORT, INT, LONG)
val (a, b) = popStack2
checkType(a, INT)
checkType(b, kind)
pushStack(kind)

case Conversion(src, dst) =>
case Conversion(src: TypeKind, dst: TypeKind) =>
checkNumeric(src)
checkNumeric(dst)
checkType(popStack, src)
pushStack(dst)

case ArrayLength(kind) =>
case ArrayLength(kind: TypeKind) =>
popStack match {
case ARRAY(elem) => checkType(elem, kind)
case arr => icodeError(" array reference expected, but " + arr + " found")
Expand All @@ -576,7 +578,7 @@ abstract class ICodeCheckers {
checkType(popStack, ConcatClass)
pushStack(StringReference)

case StringConcat(el) =>
case StringConcat(el: TypeKind) =>
checkType(popStack, el)
checkType(popStack, ConcatClass)
pushStack(ConcatClass)
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/backend/icode/ICodes.scala
Expand Up @@ -22,14 +22,15 @@ abstract class ICodes extends AnyRef
with Opcodes
with TypeStacks
with TypeKinds
with ExceptionHandlers
with Primitives
with ExceptionHandlers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason for this change?

with Linearizers
with Printers
with Repository
{
val global: Global
import global.{ log, definitions, settings, perRunCaches, devWarning }
import Primitives._

/** The ICode representation of classes */
val classes = perRunCaches.newMap[global.Symbol, IClass]()
Expand Down