Skip to content

Commit 2c6590d

Browse files
committed
Speed up .nn
Some tests by Matt had cases where `.nn` figured prominently in the flamegraph. I optimized it so that the fast path is streamlined and inlined. In the following test code: ``` def x: String | Null = "abc" val y = x.nn ``` the new implementation is ``` 10: getstatic #20 // Field MODULE$:LTest$; 13: invokevirtual #24 // Method x:()Ljava/lang/String; 16: astore_0 17: getstatic #29 // Field scala/runtime/Scala3RunTime$.MODULE$:Lscala/runtime/Scala3RunTime$; 20: aload_0 21: invokevirtual #33 // Method scala/runtime/Scala3RunTime$.nn:(Ljava/lang/Object;)Ljava/lang/Object; 24: checkcast #35 // class java/lang/String 27: putstatic #37 // Field y:Ljava/lang/String; ``` The previous implementation was two bytes shorter, but contained in the critical path - A call to a ScalaRuntime method, which was not inlineable by the JIT compiler due to its size, - A conversion of a cmparison to a Boolean value (not sure this matters) - A cast from the return type `Object` to the actual type.
1 parent cec9aa3 commit 2c6590d

File tree

2 files changed

+10
-2
lines changed

2 files changed

+10
-2
lines changed

library/src/scala/runtime/Scala3RunTime.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,16 @@ object Scala3RunTime:
1414
*
1515
* Extracted to minimize the bytecode size at call site.
1616
*/
17+
@deprecated("use Predef.nn instead", "3.2")
1718
def nn[T](x: T | Null): x.type & T =
1819
val isNull = x == null
19-
if (isNull) throw new NullPointerException("tried to cast away nullability, but value is null")
20+
if isNull then nnFail()
2021
else x.asInstanceOf[x.type & T]
2122

23+
/** Called by the inline extension def `nn`.
24+
*
25+
* Extracted to minimize the bytecode size at call site.
26+
*/
27+
def nnFail(): Nothing =
28+
throw new NullPointerException("tried to cast away nullability, but value is null")
2229
end Scala3RunTime

library/src/scala/runtime/stdLibPatches/Predef.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ object Predef:
4646
* }}}
4747
*/
4848
extension [T](x: T | Null) inline def nn: x.type & T =
49-
scala.runtime.Scala3RunTime.nn(x)
49+
if x.asInstanceOf[Any] == null then scala.runtime.Scala3RunTime.nnFail()
50+
x.asInstanceOf[x.type & T]
5051

5152
extension (inline x: AnyRef | Null)
5253
/** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`

0 commit comments

Comments
 (0)