Skip to content

Commit 6d4c849

Browse files
authored
Merge pull request scala-js#3717 from sjrd/independent-javalanglib
Make the IR of the javalanglib independent of the Scala library.
2 parents 3794e82 + e270316 commit 6d4c849

25 files changed

+1100
-485
lines changed

ir/src/main/scala/org/scalajs/ir/Definitions.scala

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,25 @@ object Definitions {
138138
private val decompressedPrefixes: Seq[(String, String)] =
139139
compressedPrefixes map { case (a, b) => (b, a) }
140140

141+
/** Encodes a method name from its full signature. */
142+
def encodeMethodName(baseName: String, paramTypes: List[TypeRef],
143+
resultType: Option[TypeRef]): String = {
144+
145+
val paramTypesString = paramTypes.map(encodeTypeRef).mkString("__")
146+
147+
if (baseName == "<clinit>") {
148+
assert(paramTypes.isEmpty && resultType.isEmpty)
149+
StaticInitializerName
150+
} else if (baseName == "<init>") {
151+
assert(resultType.isEmpty)
152+
paramTypes.map(encodeTypeRef).mkString("init___", "__", "")
153+
} else {
154+
val resultTypeString = resultType.fold("")(encodeTypeRef)
155+
(paramTypes.map(encodeTypeRef) :+ resultTypeString).mkString(
156+
baseName + "__", "__", "")
157+
}
158+
}
159+
141160
/** Decodes a method name into its full signature. */
142161
def decodeMethodName(
143162
encodedName: String): (String, List[TypeRef], Option[TypeRef]) = {
@@ -154,11 +173,7 @@ object Definitions {
154173
}
155174

156175
// -1 preserves trailing empty strings
157-
val parts = privateAndSigString.split("__", -1).toSeq
158-
val paramsAndResultStrings =
159-
if (parts.headOption.exists(_.startsWith("p"))) parts.tail
160-
else parts
161-
176+
val paramsAndResultStrings = privateAndSigString.split("__", -1).toSeq
162177
val paramStrings :+ resultString = paramsAndResultStrings
163178

164179
val paramTypes = paramStrings.map(decodeTypeRef).toList
@@ -169,6 +184,18 @@ object Definitions {
169184
(simpleName, paramTypes, resultType)
170185
}
171186

187+
/** Encodes a [[Types.TypeRef]] to be used for example in an encoded method
188+
* signature.
189+
*/
190+
def encodeTypeRef(typeRef: TypeRef): String = {
191+
typeRef match {
192+
case ClassRef(className) =>
193+
className
194+
case ArrayTypeRef(baseClassName, dimensions) =>
195+
"A" * dimensions + baseClassName
196+
}
197+
}
198+
172199
/** Decodes a [[Types.TypeRef]], such as in an encoded method signature.
173200
*/
174201
def decodeTypeRef(encodedName: String): TypeRef = {

javalanglib/src/main/scala/java/lang/Byte.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ object Byte {
7676
def parseByte(s: String, radix: Int): scala.Byte = {
7777
val r = Integer.parseInt(s, radix)
7878
if (r < MIN_VALUE || r > MAX_VALUE)
79-
throw new NumberFormatException(s"""For input string: "$s"""")
79+
throw new NumberFormatException("For input string: \"" + s + "\"")
8080
else
8181
r.toByte
8282
}

javalanglib/src/main/scala/java/lang/Class.scala

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,11 @@ final class Class[A] private (data0: Object) extends Object {
8484

8585
@inline // optimize for the Unchecked case, where this becomes identity()
8686
def cast(obj: Object): A = {
87-
scala.scalajs.runtime.SemanticsUtils.asInstanceOfCheck(
88-
(obj != null && !isJSType && !isInstance(obj)),
89-
new ClassCastException("" + obj + " is not an instance of " + getName))
87+
SemanticsUtils.asInstanceOfCheck({ () =>
88+
(obj != null && !isJSType && !isInstance(obj))
89+
}, { () =>
90+
new ClassCastException("" + obj + " is not an instance of " + getName)
91+
})
9092
obj.asInstanceOf[A]
9193
}
9294

javalanglib/src/main/scala/java/lang/Double.scala

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ object Double {
112112

113113
def parseDouble(s: String): scala.Double = {
114114
def fail(): Nothing =
115-
throw new NumberFormatException(s"""For input string: "$s"""")
115+
throw new NumberFormatException("For input string: \"" + s + "\"")
116116

117117
// (Very) slow path for hexadecimal notation
118118
def parseHexDoubleImpl(match2: js.RegExp.ExecResult): scala.Double = {
@@ -184,12 +184,16 @@ object Double {
184184
* `binaryExp` (see below) did not stray too far from that range itself.
185185
*/
186186

187-
val mantissa =
188-
js.Dynamic.global.parseInt(truncatedMantissaStr, 16).asInstanceOf[scala.Double]
187+
@inline def nativeParseInt(s: String, radix: Int): scala.Double = {
188+
js.Dynamic.global
189+
.parseInt(s.asInstanceOf[js.Any], radix.asInstanceOf[js.Any])
190+
.asInstanceOf[scala.Double]
191+
}
192+
193+
val mantissa = nativeParseInt(truncatedMantissaStr, 16)
189194
// Assert: mantissa != 0.0 && mantissa != scala.Double.PositiveInfinity
190195

191-
val binaryExpDouble =
192-
js.Dynamic.global.parseInt(binaryExpStr, 10).asInstanceOf[scala.Double]
196+
val binaryExpDouble = nativeParseInt(binaryExpStr, 10)
193197
val binaryExp = binaryExpDouble.toInt // caps to [MinValue, MaxValue]
194198

195199
val binExpAndCorrection = binaryExp + fullCorrection
@@ -221,7 +225,7 @@ object Double {
221225

222226
val match1 = doubleStrPat.exec(s)
223227
if (match1 != null) {
224-
js.Dynamic.global.parseFloat(match1(1)).asInstanceOf[scala.Double]
228+
js.Dynamic.global.parseFloat(match1(1).asInstanceOf[js.Any]).asInstanceOf[scala.Double]
225229
} else {
226230
val match2 = doubleStrHexPat.exec(s)
227231
if (match2 != null)

javalanglib/src/main/scala/java/lang/FloatingPointBits.scala

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ import js.typedarray
1919
/** Manipulating the bits of floating point numbers. */
2020
private[lang] object FloatingPointBits {
2121

22-
import scala.scalajs.LinkingInfo.assumingES6
22+
import scala.scalajs.runtime.linkingInfo
2323

2424
private[this] val _areTypedArraysSupported = {
2525
// Here we use `assumingES6` to dce the 4 subsequent tests
26-
assumingES6 || {
26+
linkingInfo.assumingES6 || {
2727
js.typeOf(global.ArrayBuffer) != "undefined" &&
2828
js.typeOf(global.Int32Array) != "undefined" &&
2929
js.typeOf(global.Float32Array) != "undefined" &&
@@ -41,7 +41,7 @@ private[lang] object FloatingPointBits {
4141
* * If we emit ES5, replace `areTypedArraysSupported` by
4242
* `_areTypedArraysSupported` so we do not calculate it multiple times.
4343
*/
44-
assumingES6 || _areTypedArraysSupported
44+
linkingInfo.assumingES6 || _areTypedArraysSupported
4545
}
4646

4747
private val arrayBuffer =
@@ -153,18 +153,16 @@ private[lang] object FloatingPointBits {
153153
private def floatToIntBitsPolyfill(value: scala.Double): Int = {
154154
val ebits = 8
155155
val fbits = 23
156-
val (s, e, f) = encodeIEEE754(ebits, fbits, value)
157-
(if (s) 0x80000000 else 0) | (e << fbits) | rawToInt(f)
156+
val sef = encodeIEEE754(ebits, fbits, value)
157+
(if (sef.s) 0x80000000 else 0) | (sef.e << fbits) | rawToInt(sef.f)
158158
}
159159

160160
private def longBitsToDoublePolyfill(bits: scala.Long): scala.Double = {
161-
import js.JSNumberOps._
162-
163161
val ebits = 11
164162
val fbits = 52
165163
val hifbits = fbits-32
166164
val hi = (bits >>> 32).toInt
167-
val lo = bits.toInt.toUint
165+
val lo = Utils.toUint(bits.toInt)
168166
val s = hi < 0
169167
val e = (hi >> hifbits) & ((1 << ebits) - 1)
170168
val f = (hi & ((1 << hifbits) - 1)).toDouble * 0x100000000L.toDouble + lo
@@ -175,10 +173,10 @@ private[lang] object FloatingPointBits {
175173
val ebits = 11
176174
val fbits = 52
177175
val hifbits = fbits-32
178-
val (s, e, f) = encodeIEEE754(ebits, fbits, value)
179-
val hif = rawToInt(f / 0x100000000L.toDouble)
180-
val hi = (if (s) 0x80000000 else 0) | (e << hifbits) | hif
181-
val lo = rawToInt(f)
176+
val sef = encodeIEEE754(ebits, fbits, value)
177+
val hif = rawToInt(sef.f / 0x100000000L.toDouble)
178+
val hi = (if (sef.s) 0x80000000 else 0) | (sef.e << hifbits) | hif
179+
val lo = rawToInt(sef.f)
182180
(hi.toLong << 32) | (lo.toLong & 0xffffffffL)
183181
}
184182

@@ -209,19 +207,19 @@ private[lang] object FloatingPointBits {
209207
}
210208

211209
@inline private def encodeIEEE754(ebits: Int, fbits: Int,
212-
v: scala.Double): (scala.Boolean, Int, scala.Double) = {
210+
v: scala.Double): EncodeIEEE754Result = {
213211

214-
import Math._
212+
import js.Math.{floor, log, pow}
215213

216214
val bias = (1 << (ebits-1)) - 1 // constant
217215

218216
if (Double.isNaN(v)) {
219217
// http://dev.w3.org/2006/webapi/WebIDL/#es-type-mapping
220-
(false, (1 << ebits) - 1, pow(2, fbits-1))
218+
new EncodeIEEE754Result(false, (1 << ebits) - 1, pow(2, fbits-1))
221219
} else if (Double.isInfinite(v)) {
222-
(v < 0, (1 << ebits) - 1, 0.0)
220+
new EncodeIEEE754Result(v < 0, (1 << ebits) - 1, 0.0)
223221
} else if (v == 0.0) {
224-
(1 / v == scala.Double.NegativeInfinity, 0, 0.0)
222+
new EncodeIEEE754Result(1 / v == scala.Double.NegativeInfinity, 0, 0.0)
225223
} else {
226224
val LN2 = 0.6931471805599453
227225

@@ -231,7 +229,9 @@ private[lang] object FloatingPointBits {
231229
if (av >= pow(2, 1-bias)) {
232230
val twoPowFbits = pow(2, fbits)
233231

234-
var e = min(rawToInt(floor(log(av) / LN2)), 1023)
232+
var e = rawToInt(floor(log(av) / LN2))
233+
if (e > 1023)
234+
e = 1023
235235
var twoPowE = pow(2, e)
236236

237237
/* #2911: When av is very close under a power of 2 (e.g.,
@@ -259,10 +259,10 @@ private[lang] object FloatingPointBits {
259259
e = e + bias
260260
f = f - twoPowFbits
261261
}
262-
(s, e, f)
262+
new EncodeIEEE754Result(s, e, f)
263263
} else {
264264
// Subnormal
265-
(s, 0, roundToEven(av / pow(2, 1-bias-fbits)))
265+
new EncodeIEEE754Result(s, 0, roundToEven(av / pow(2, 1-bias-fbits)))
266266
}
267267
}
268268
}
@@ -271,12 +271,17 @@ private[lang] object FloatingPointBits {
271271
(x.asInstanceOf[js.Dynamic] | 0.asInstanceOf[js.Dynamic]).asInstanceOf[Int]
272272

273273
@inline private def roundToEven(n: scala.Double): scala.Double = {
274-
val w = Math.floor(n)
274+
val w = js.Math.floor(n)
275275
val f = n - w
276276
if (f < 0.5) w
277277
else if (f > 0.5) w + 1
278278
else if (w % 2 != 0) w + 1
279279
else w
280280
}
281281

282+
// Cannot use tuples in the javalanglib
283+
@inline
284+
private final class EncodeIEEE754Result(val s: scala.Boolean, val e: Int,
285+
val f: scala.Double)
286+
282287
}

javalanglib/src/main/scala/java/lang/Integer.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ object Integer {
7777
signed: scala.Boolean): scala.Int = {
7878

7979
def fail(): Nothing =
80-
throw new NumberFormatException(s"""For input string: "$s"""")
80+
throw new NumberFormatException("For input string: \"" + s + "\"")
8181

8282
val len = if (s == null) 0 else s.length
8383

@@ -123,9 +123,9 @@ object Integer {
123123
if (x == y) 0 else if (x < y) -1 else 1
124124

125125
@inline def compareUnsigned(x: scala.Int, y: scala.Int): scala.Int = {
126-
import js.JSNumberOps._
126+
import Utils.toUint
127127
if (x == y) 0
128-
else if (x.toUint > y.toUint) 1
128+
else if (toUint(x) > toUint(y)) 1
129129
else -1
130130
}
131131

@@ -235,7 +235,7 @@ object Integer {
235235
if (radix == 10 || radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
236236
Integer.toString(i)
237237
} else {
238-
import js.JSNumberOps.enableJSNumberOps
238+
import Utils.Implicits.enableJSNumberOps
239239
i.toString(radix)
240240
}
241241
}

javalanglib/src/main/scala/java/lang/Long.scala

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object Long {
7171
var radix = 0
7272

7373
while (radix < Character.MIN_RADIX) {
74-
r += null
74+
r.push(null)
7575
radix += 1
7676
}
7777

@@ -96,8 +96,8 @@ object Long {
9696
}
9797
val radixPowLengthLong = radixPowLength.toLong
9898
val overflowBarrier = Long.divideUnsigned(-1L, radixPowLengthLong)
99-
r += new StringRadixInfo(chunkLength, radixPowLengthLong,
100-
paddingZeros, overflowBarrier)
99+
r.push(new StringRadixInfo(chunkLength, radixPowLengthLong,
100+
paddingZeros, overflowBarrier))
101101
radix += 1
102102
}
103103

@@ -138,7 +138,7 @@ object Long {
138138
val hi = (i >>> 32).toInt
139139
if (lo >> 31 == hi) {
140140
// It's a signed int32
141-
import js.JSNumberOps.enableJSNumberOps
141+
import Utils.Implicits.enableJSNumberOps
142142
lo.toString(radix)
143143
} else if (hi < 0) {
144144
"-" + toUnsignedStringInternalLarge(-i, radix)
@@ -151,17 +151,16 @@ object Long {
151151
private def toUnsignedStringImpl(i: scala.Long, radix: Int): String = {
152152
if ((i >>> 32).toInt == 0) {
153153
// It's an unsigned int32
154-
import js.JSNumberOps._
155-
i.toInt.toUint.toString(radix)
154+
import Utils.Implicits.enableJSNumberOps
155+
Utils.toUint(i.toInt).toString(radix)
156156
} else {
157157
toUnsignedStringInternalLarge(i, radix)
158158
}
159159
}
160160

161161
// Must be called only with valid radix
162162
private def toUnsignedStringInternalLarge(i: scala.Long, radix: Int): String = {
163-
import js.JSNumberOps._
164-
import js.JSStringOps._
163+
import Utils.Implicits._
165164

166165
val radixInfo = StringRadixInfos(radix)
167166
val divisor = radixInfo.radixPowLength
@@ -312,7 +311,7 @@ object Long {
312311
}
313312

314313
private def parseLongError(s: String): Nothing =
315-
throw new NumberFormatException(s"""For input string: "$s"""")
314+
throw new NumberFormatException("For input string: \"" + s + "\"")
316315

317316
@inline def `new`(value: scala.Long): Long = valueOf(value)
318317

0 commit comments

Comments
 (0)