Skip to content

Commit 566efbe

Browse files
committed
Implement isAssignableFrom in JS instead of exposing getFakeInstance.
Creating a fake instance and using it as an argument of `isInstance` is a huge hack. It's OK to do it internally in `scalajsenv.js`, as long as fake instances do not leak. But exposing fake instances to the Scala.js code is extremely dangerous, as it means leaking implementation-specific details at the IR level, which could be (mis-)processed by the optimizer. Since `getFakeInstance` was used only for `isAssignableFrom` anyway, it is much cleaner to directly implement `isAssignableFrom` in `scalajsenv.js`, and not expose `getFakeInstance` at all.
1 parent 508a70b commit 566efbe

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ private trait ScalaJSClassData[A] extends js.Object {
1111
val isRawJSType: scala.Boolean = js.native
1212

1313
def isInstance(obj: Object): scala.Boolean = js.native
14-
def getFakeInstance(): Object = js.native
14+
def isAssignableFrom(that: ScalaJSClassData[_]): scala.Boolean = js.native
1515

1616
def getSuperclass(): Class[_ >: A] = js.native
1717
def getComponentType(): Class[_] = js.native
1818

1919
def newArrayOfThisClass(dimensions: js.Array[Int]): AnyRef = js.native
2020
}
2121

22-
final class Class[A] private (data: ScalaJSClassData[A]) extends Object {
22+
final class Class[A] private (private val data: ScalaJSClassData[A])
23+
extends Object {
2324

2425
override def toString(): String = {
2526
(if (isInterface()) "interface " else
@@ -30,11 +31,7 @@ final class Class[A] private (data: ScalaJSClassData[A]) extends Object {
3031
data.isInstance(obj)
3132

3233
def isAssignableFrom(that: Class[_]): scala.Boolean =
33-
if (this.isPrimitive || that.isPrimitive) this eq that
34-
else this.isInstance(that.getFakeInstance())
35-
36-
private def getFakeInstance(): Object =
37-
data.getFakeInstance()
34+
this.data.isAssignableFrom(that.data)
3835

3936
def isInterface(): scala.Boolean =
4037
data.isInterface

tools/scalajsenv.js

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -963,26 +963,32 @@ getArrayOf() {
963963
// java.lang.Class support
964964

965965
//!if outputMode != ECMAScript6
966-
$TypeData.prototype["getFakeInstance"] = function() {
966+
$TypeData.prototype["isAssignableFrom"] = function(that) {
967967
//!else
968-
"getFakeInstance"() {
968+
"isAssignableFrom"(that) {
969969
//!endif
970-
if (this === $d_T)
971-
return "some string";
972-
else if (this === $d_jl_Boolean)
973-
return false;
974-
else if (this === $d_jl_Byte ||
975-
this === $d_jl_Short ||
976-
this === $d_jl_Integer ||
977-
this === $d_jl_Float ||
978-
this === $d_jl_Double)
979-
return 0;
980-
else if (this === $d_jl_Long)
981-
return $L0;
982-
else if (this === $d_sr_BoxedUnit)
983-
return void 0;
984-
else
985-
return {$classData: this};
970+
if (this["isPrimitive"] || that["isPrimitive"]) {
971+
return this === that;
972+
} else {
973+
let thatFakeInstance;
974+
if (that === $d_T)
975+
thatFakeInstance = "some string";
976+
else if (that === $d_jl_Boolean)
977+
thatFakeInstance = false;
978+
else if (that === $d_jl_Byte ||
979+
that === $d_jl_Short ||
980+
that === $d_jl_Integer ||
981+
that === $d_jl_Float ||
982+
that === $d_jl_Double)
983+
thatFakeInstance = 0;
984+
else if (that === $d_jl_Long)
985+
thatFakeInstance = $L0;
986+
else if (that === $d_sr_BoxedUnit)
987+
thatFakeInstance = void 0;
988+
else
989+
thatFakeInstance = {$classData: that};
990+
return this["isInstance"](thatFakeInstance);
991+
}
986992
};
987993

988994
//!if outputMode != ECMAScript6

0 commit comments

Comments
 (0)