diff options
Diffstat (limited to 'compiler/src/main/scala/scala/scalajs/compiler/ClassInfos.scala')
-rw-r--r-- | compiler/src/main/scala/scala/scalajs/compiler/ClassInfos.scala | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/compiler/src/main/scala/scala/scalajs/compiler/ClassInfos.scala b/compiler/src/main/scala/scala/scalajs/compiler/ClassInfos.scala new file mode 100644 index 0000000..026d664 --- /dev/null +++ b/compiler/src/main/scala/scala/scalajs/compiler/ClassInfos.scala @@ -0,0 +1,143 @@ +/* Scala.js compiler + * Copyright 2013 LAMP/EPFL + * @author Sébastien Doeraene + */ + +package scala.scalajs.compiler + +import scala.language.implicitConversions + +import scala.collection.mutable +import scala.tools.nsc._ + +import java.io.{ File, PrintWriter, BufferedOutputStream, FileOutputStream } + +import scala.scalajs.ir +import ir.{Trees => js, Types => jstpe, ClassKind} +import ir.Infos._ + +trait ClassInfos extends SubComponent { self: GenJSCode => + import global._ + import jsAddons._ + + /** Class data that are never eliminated by dce, so we don't need to + * record them. + */ + private val AlwaysPresentClassData = { + import ir.Definitions._ + Set("V", "Z", "C", "B", "S", "I", "J", "F", "D", + ObjectClass, StringClass) + } + + class ClassInfoBuilder(val symbol: ClassSymbol) { + val name = classNameOf(symbol) + val encodedName = encodeClassFullName(symbol) + var isExported: Boolean = false + val ancestorCount = symbol.ancestors.count(!_.isInterface) + val kind = { + if (isStaticModule(symbol)) ClassKind.ModuleClass + else if (symbol.isInterface) ClassKind.Interface + else if (isRawJSType(symbol.tpe)) ClassKind.RawJSType + else if (isHijackedBoxedClass(symbol)) ClassKind.HijackedClass + else if (symbol.isImplClass) ClassKind.TraitImpl + else ClassKind.Class + } + val superClass = + if (kind.isClass || kind == ClassKind.HijackedClass) + encodeClassFullName(symbol.superClass) + else + "" + val ancestors = (symbol :: symbol.ancestors) map encodeClassFullName + + var optimizerHints: OptimizerHints = OptimizerHints.empty + + val methodInfos = mutable.ListBuffer.empty[MethodInfoBuilder] + + def addMethod(encodedName: String, isAbstract: Boolean = false, + isExported: Boolean = false): MethodInfoBuilder = { + val b = new MethodInfoBuilder(encodedName, isAbstract, isExported) + methodInfos += b + b + } + + def result(): ClassInfo = { + ClassInfo(name, encodedName, isExported, ancestorCount, kind, + superClass, ancestors, optimizerHints, + methodInfos.map(_.result()).result()) + } + } + + class MethodInfoBuilder(val encodedName: String, + val isAbstract: Boolean = false, + val isExported: Boolean = false) { + + val calledMethods = mutable.Set.empty[(String, String)] // (tpe, method) + val calledMethodsStatic = mutable.Set.empty[(String, String)] // (class, method) + val instantiatedClasses = mutable.Set.empty[String] + val accessedModules = mutable.Set.empty[String] + val accessedClassData = mutable.Set.empty[String] + var optimizerHints: OptimizerHints = OptimizerHints.empty + + def callsMethod(ownerIdent: js.Ident, method: js.Ident): Unit = + calledMethods += ((patchClassName(ownerIdent.name), method.name)) + + def callsMethod(owner: Symbol, method: js.Ident): Unit = + calledMethods += ((patchClassName(encodeClassFullName(owner)), method.name)) + + def callsMethodStatic(ownerIdent: js.Ident, method: js.Ident): Unit = + calledMethodsStatic += ((patchClassName(ownerIdent.name), method.name)) + + def instantiatesClass(classSym: Symbol): Unit = + instantiatedClasses += patchClassName(encodeClassFullName(classSym)) + + def accessesModule(moduleClassSym: Symbol): Unit = + accessedModules += patchModuleName(encodeModuleFullName(moduleClassSym)) + + def accessesClassData(refType: jstpe.ReferenceType): Unit = { + val className = refType match { + case jstpe.ClassType(name) => name + case jstpe.ArrayType(base, _) => base + } + if (!AlwaysPresentClassData.contains(className)) + accessedClassData += className + } + + def createsAnonFunction(funInfo: ClassInfoBuilder): Unit = { + for (methodInfo <- funInfo.methodInfos) { + calledMethods ++= methodInfo.calledMethods + calledMethodsStatic ++= methodInfo.calledMethodsStatic + instantiatedClasses ++= methodInfo.instantiatedClasses + accessedModules ++= methodInfo.accessedModules + accessedClassData ++= methodInfo.accessedClassData + } + } + + private def patchClassName(name: String): String = name match { + case "jl_String$" => "sjsr_RuntimeString$" + case _ => name + } + + private def patchModuleName(name: String): String = name match { + case "jl_String" => "sjsr_RuntimeString" + case _ => name + } + + def result(): MethodInfo = { + MethodInfo( + encodedName, + isAbstract, + isExported, + calledMethods.toList.groupBy(_._1).mapValues(_.map(_._2)), + calledMethodsStatic.toList.groupBy(_._1).mapValues(_.map(_._2)), + instantiatedClasses.toList, + accessedModules.result.toList, + accessedClassData.result.toList, + optimizerHints + ) + } + } + + private def classNameOf(sym: Symbol): String = + if (needsModuleClassSuffix(sym)) sym.fullName + nme.MODULE_SUFFIX_STRING + else sym.fullName +} |