1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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
}
|