@@ -2298,50 +2298,17 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
2298
2298
isJSFunctionDef(currentClassSym)) {
2299
2299
val flags = js.MemberFlags .empty.withNamespace(namespace)
2300
2300
val body = {
2301
- def genAsUnaryOp (op : js.UnaryOp .Code ): js.Tree =
2302
- js.UnaryOp (op, genThis())
2303
- def genAsBinaryOp (op : js.BinaryOp .Code ): js.Tree =
2304
- js.BinaryOp (op, genThis(), jsParams.head.ref)
2305
- def genAsBinaryOpRhsNotNull (op : js.BinaryOp .Code ): js.Tree =
2306
- js.BinaryOp (op, genThis(), js.UnaryOp (js.UnaryOp .CheckNotNull , jsParams.head.ref))
2307
-
2308
- if (currentClassSym.get == HackedStringClass ) {
2309
- /* Hijack the bodies of String.length and String.charAt and replace
2310
- * them with String_length and String_charAt operations, respectively.
2311
- */
2312
- methodName.name match {
2313
- case `lengthMethodName` => genAsUnaryOp(js.UnaryOp .String_length )
2314
- case `charAtMethodName` => genAsBinaryOp(js.BinaryOp .String_charAt )
2315
- case _ => genBody()
2316
- }
2317
- } else if (currentClassSym.get == ClassClass ) {
2318
- // Similar, for the Class_x operations
2319
- methodName.name match {
2320
- case `getNameMethodName` => genAsUnaryOp(js.UnaryOp .Class_name )
2321
- case `isPrimitiveMethodName` => genAsUnaryOp(js.UnaryOp .Class_isPrimitive )
2322
- case `isInterfaceMethodName` => genAsUnaryOp(js.UnaryOp .Class_isInterface )
2323
- case `isArrayMethodName` => genAsUnaryOp(js.UnaryOp .Class_isArray )
2324
- case `getComponentTypeMethodName` => genAsUnaryOp(js.UnaryOp .Class_componentType )
2325
- case `getSuperclassMethodName` => genAsUnaryOp(js.UnaryOp .Class_superClass )
2326
-
2327
- case `isInstanceMethodName` => genAsBinaryOp(js.BinaryOp .Class_isInstance )
2328
- case `isAssignableFromMethodName` => genAsBinaryOpRhsNotNull(js.BinaryOp .Class_isAssignableFrom )
2329
- case `castMethodName` => genAsBinaryOp(js.BinaryOp .Class_cast )
2330
-
2331
- case _ => genBody()
2332
- }
2333
- } else if (currentClassSym.get == JavaLangReflectArrayModClass ) {
2334
- methodName.name match {
2335
- case `arrayNewInstanceMethodName` =>
2336
- val List (jlClassParam, lengthParam) = jsParams
2337
- js.BinaryOp (js.BinaryOp .Class_newArray ,
2338
- js.UnaryOp (js.UnaryOp .CheckNotNull , jlClassParam.ref),
2339
- lengthParam.ref)
2340
- case _ =>
2301
+ val classOwner = currentClassSym.owner
2302
+ if (classOwner != JavaLangPackageClass && classOwner.owner != JavaLangPackageClass ) {
2303
+ // Fast path; it cannot be any of the special methods of the javalib
2304
+ genBody()
2305
+ } else {
2306
+ JavalibMethodsWithOpBody .get((encodeClassName(currentClassSym), methodName.name)) match {
2307
+ case None =>
2341
2308
genBody()
2309
+ case Some (javalibOpBody) =>
2310
+ javalibOpBody.generate(genThis(), jsParams.map(_.ref))
2342
2311
}
2343
- } else {
2344
- genBody()
2345
2312
}
2346
2313
}
2347
2314
js.MethodDef (flags, methodName, originalName, jsParams, resultIRType,
@@ -7379,37 +7346,6 @@ private object GenJSCode {
7379
7346
private val ObjectArgConstructorName =
7380
7347
MethodName .constructor(List (jswkn.ObjectRef ))
7381
7348
7382
- private val lengthMethodName =
7383
- MethodName (" length" , Nil , jstpe.IntRef )
7384
- private val charAtMethodName =
7385
- MethodName (" charAt" , List (jstpe.IntRef ), jstpe.CharRef )
7386
-
7387
- private val getNameMethodName =
7388
- MethodName (" getName" , Nil , jstpe.ClassRef (jswkn.BoxedStringClass ))
7389
- private val isPrimitiveMethodName =
7390
- MethodName (" isPrimitive" , Nil , jstpe.BooleanRef )
7391
- private val isInterfaceMethodName =
7392
- MethodName (" isInterface" , Nil , jstpe.BooleanRef )
7393
- private val isArrayMethodName =
7394
- MethodName (" isArray" , Nil , jstpe.BooleanRef )
7395
- private val getComponentTypeMethodName =
7396
- MethodName (" getComponentType" , Nil , jstpe.ClassRef (jswkn.ClassClass ))
7397
- private val getSuperclassMethodName =
7398
- MethodName (" getSuperclass" , Nil , jstpe.ClassRef (jswkn.ClassClass ))
7399
-
7400
- private val isInstanceMethodName =
7401
- MethodName (" isInstance" , List (jstpe.ClassRef (jswkn.ObjectClass )), jstpe.BooleanRef )
7402
- private val isAssignableFromMethodName =
7403
- MethodName (" isAssignableFrom" , List (jstpe.ClassRef (jswkn.ClassClass )), jstpe.BooleanRef )
7404
- private val castMethodName =
7405
- MethodName (" cast" , List (jstpe.ClassRef (jswkn.ObjectClass )), jstpe.ClassRef (jswkn.ObjectClass ))
7406
-
7407
- private val arrayNewInstanceMethodName = {
7408
- MethodName (" newInstance" ,
7409
- List (jstpe.ClassRef (jswkn.ClassClass ), jstpe.IntRef ),
7410
- jstpe.ClassRef (jswkn.ObjectClass ))
7411
- }
7412
-
7413
7349
private val thisOriginalName = OriginalName (" this" )
7414
7350
7415
7351
private object BlockOrAlone {
@@ -7425,4 +7361,91 @@ private object GenJSCode {
7425
7361
case _ => Some ((tree, Nil ))
7426
7362
}
7427
7363
}
7364
+
7365
+ private sealed abstract class JavalibOpBody {
7366
+ import JavalibOpBody ._
7367
+
7368
+ def generate (receiver : js.Tree , args : List [js.Tree ])(implicit pos : ir.Position ): js.Tree = {
7369
+ def checkNotNullIf (arg : js.Tree , checkNulls : Boolean ): js.Tree =
7370
+ if (checkNulls && arg.tpe.isNullable) js.UnaryOp (js.UnaryOp .CheckNotNull , arg)
7371
+ else arg
7372
+
7373
+
7374
+ this match {
7375
+ case ThisUnaryOp (op) =>
7376
+ assert(args.isEmpty)
7377
+ js.UnaryOp (op, receiver)
7378
+
7379
+ case ThisBinaryOp (op, checkNulls) =>
7380
+ val List (rhs) = args : @ unchecked
7381
+ js.BinaryOp (op, receiver, checkNotNullIf(rhs, checkNulls))
7382
+
7383
+ case ArgUnaryOp (op, checkNulls) =>
7384
+ val List (arg) = args : @ unchecked
7385
+ js.UnaryOp (op, checkNotNullIf(arg, checkNulls))
7386
+
7387
+ case ArgBinaryOp (op, checkNulls) =>
7388
+ val List (lhs, rhs) = args : @ unchecked
7389
+ js.BinaryOp (op, checkNotNullIf(lhs, checkNulls), checkNotNullIf(rhs, checkNulls))
7390
+ }
7391
+ }
7392
+ }
7393
+
7394
+ private object JavalibOpBody {
7395
+ /** UnaryOp applying to the `this` parameter. */
7396
+ final case class ThisUnaryOp (op : js.UnaryOp .Code ) extends JavalibOpBody
7397
+
7398
+ /** BinaryOp applying to the `this` parameter and the regular parameter. */
7399
+ final case class ThisBinaryOp (op : js.BinaryOp .Code , checkNulls : Boolean = false ) extends JavalibOpBody
7400
+
7401
+ /** UnaryOp applying to the only regular parameter (`this` is ignored). */
7402
+ final case class ArgUnaryOp (op : js.UnaryOp .Code , checkNulls : Boolean = false ) extends JavalibOpBody
7403
+
7404
+ /** BinaryOp applying to the two regular paramters (`this` is ignored). */
7405
+ final case class ArgBinaryOp (op : js.BinaryOp .Code , checkNulls : Boolean = false ) extends JavalibOpBody
7406
+ }
7407
+
7408
+ /** Methods of the javalib whose body must be replaced by a dedicated
7409
+ * UnaryOp or BinaryOp.
7410
+ */
7411
+ private lazy val JavalibMethodsWithOpBody : Map [(ClassName , MethodName ), JavalibOpBody ] = {
7412
+ import JavalibOpBody ._
7413
+ import js .{UnaryOp => unop , BinaryOp => binop }
7414
+ import jstpe .{BooleanRef => Z , CharRef => C , IntRef => I }
7415
+ import MethodName .{apply => m }
7416
+
7417
+ val O = jswkn.ObjectRef
7418
+ val CC = jstpe.ClassRef (jswkn.ClassClass )
7419
+ val T = jstpe.ClassRef (jswkn.BoxedStringClass )
7420
+
7421
+ val byClass : Map [ClassName , Map [MethodName , JavalibOpBody ]] = Map (
7422
+ jswkn.BoxedStringClass -> Map (
7423
+ m(" length" , Nil , I ) -> ThisUnaryOp (unop.String_length ),
7424
+ m(" charAt" , List (I ), C ) -> ThisBinaryOp (binop.String_charAt )
7425
+ ),
7426
+ jswkn.ClassClass -> Map (
7427
+ // Unary operators
7428
+ m(" getName" , Nil , T ) -> ThisUnaryOp (unop.Class_name ),
7429
+ m(" isPrimitive" , Nil , Z ) -> ThisUnaryOp (unop.Class_isPrimitive ),
7430
+ m(" isInterface" , Nil , Z ) -> ThisUnaryOp (unop.Class_isInterface ),
7431
+ m(" isArray" , Nil , Z ) -> ThisUnaryOp (unop.Class_isArray ),
7432
+ m(" getComponentType" , Nil , CC ) -> ThisUnaryOp (unop.Class_componentType ),
7433
+ m(" getSuperclass" , Nil , CC ) -> ThisUnaryOp (unop.Class_superClass ),
7434
+ // Binary operators
7435
+ m(" isInstance" , List (O ), Z ) -> ThisBinaryOp (binop.Class_isInstance ),
7436
+ m(" isAssignableFrom" , List (CC ), Z ) -> ThisBinaryOp (binop.Class_isAssignableFrom , checkNulls = true ),
7437
+ m(" cast" , List (O ), O ) -> ThisBinaryOp (binop.Class_cast )
7438
+ ),
7439
+ ClassName (" java.lang.reflect.Array$" ) -> Map (
7440
+ m(" newInstance" , List (CC , I ), O ) -> ArgBinaryOp (binop.Class_newArray , checkNulls = true )
7441
+ )
7442
+ )
7443
+
7444
+ for {
7445
+ (cls, methods) <- byClass
7446
+ (methodName, body) <- methods
7447
+ } yield {
7448
+ (cls, methodName) -> body
7449
+ }
7450
+ }
7428
7451
}
0 commit comments