@@ -690,6 +690,9 @@ object HelperFunctions {
690
690
*
691
691
* Since computing `jsValueType` is somewhat expensive, we first test
692
692
* whether `specialInstanceTypes != 0` before calling `jsValueType`.
693
+ *
694
+ * There is a more elaborated concrete example of this algorithm in
695
+ * `genInstanceTest`.
693
696
*/
694
697
instrs += LOCAL_GET (typeDataParam)
695
698
instrs += STRUCT_GET (WasmStructTypeName .typeData, specialInstanceTypesIdx)
@@ -1636,6 +1639,8 @@ object HelperFunctions {
1636
1639
def genInstanceTest (clazz : LinkedClass )(implicit ctx : WasmContext ): Unit = {
1637
1640
assert(clazz.kind == ClassKind .Interface )
1638
1641
1642
+ val classInfo = ctx.getClassInfo(clazz.className)
1643
+
1639
1644
val fctx = WasmFunctionContext (
1640
1645
Names .WasmFunctionName .instanceTest(clazz.name.name),
1641
1646
List (" expr" -> WasmRefType .anyref),
@@ -1645,9 +1650,9 @@ object HelperFunctions {
1645
1650
1646
1651
import fctx .instrs
1647
1652
1648
- val itables = fctx.addSyntheticLocal(
1649
- Types . WasmRefType .nullable( WasmArrayType .itables.name )
1650
- )
1653
+ val itables = fctx.addLocal( " itables " , WasmRefType .nullable( WasmArrayType .itables.name))
1654
+ val exprNonNullLocal = fctx.addLocal( " exprNonNull " , WasmRefType .any )
1655
+
1651
1656
val itableIdx = ctx.getItableIdx(clazz.name.name)
1652
1657
fctx.block(WasmRefType .anyref) { testFail =>
1653
1658
// if expr is not an instance of Object, return false
@@ -1677,8 +1682,48 @@ object HelperFunctions {
1677
1682
instrs += I32_CONST (1 )
1678
1683
instrs += RETURN
1679
1684
} // test fail
1680
- instrs += DROP
1681
- instrs += I32_CONST (0 ) // false
1685
+
1686
+ if (classInfo.isAncestorOfHijackedClass) {
1687
+ /* It could be a hijacked class instance that implements this interface.
1688
+ * Test whether `jsValueType(expr)` is in the `specialInstanceTypes` bitset.
1689
+ * In other words, return `((1 << jsValueType(expr)) & specialInstanceTypes) != 0`.
1690
+ *
1691
+ * For example, if this class is `Comparable`,
1692
+ * `specialInstanceTypes == 0b00001111`, since `jl.Boolean`, `jl.String`
1693
+ * and `jl.Double` implement `Comparable`, but `jl.Void` does not.
1694
+ * If `expr` is a `number`, `jsValueType(expr) == 3`. We then test whether
1695
+ * `(1 << 3) & 0b00001111 != 0`, which is true because `(1 << 3) == 0b00001000`.
1696
+ * If `expr` is `undefined`, it would be `(1 << 4) == 0b00010000`, which
1697
+ * would give `false`.
1698
+ */
1699
+ val anyRefToVoidSig =
1700
+ WasmFunctionSignature (List (WasmRefType .anyref), Nil )
1701
+
1702
+ fctx.block(anyRefToVoidSig) { isNullLabel =>
1703
+ // exprNonNull := expr; branch to isNullLabel if it is null
1704
+ instrs += BR_ON_NULL (isNullLabel)
1705
+ instrs += LOCAL_SET (exprNonNullLocal)
1706
+
1707
+ // Load 1 << jsValueType(expr)
1708
+ instrs += I32_CONST (1 )
1709
+ instrs += LOCAL_GET (exprNonNullLocal)
1710
+ instrs += CALL (WasmFunctionName .jsValueType)
1711
+ instrs += I32_SHL
1712
+
1713
+ // return (... & specialInstanceTypes) != 0
1714
+ instrs += I32_CONST (classInfo.specialInstanceTypes)
1715
+ instrs += I32_AND
1716
+ instrs += I32_CONST (0 )
1717
+ instrs += I32_NE
1718
+ instrs += RETURN
1719
+ }
1720
+
1721
+ instrs += I32_CONST (0 ) // false
1722
+ } else {
1723
+ instrs += DROP
1724
+ instrs += I32_CONST (0 ) // false
1725
+ }
1726
+
1682
1727
fctx.buildAndAddToContext()
1683
1728
}
1684
1729
0 commit comments