This is an automated email from the ASF dual-hosted git repository. He-Pin pushed a commit to branch refactor/replace-reflection-with-methodhandles in repository https://gitbox.apache.org/repos/asf/pekko-http.git
commit 0269df0924db824cd446ad12e0525893fb417a8d Author: 虎鸣 <[email protected]> AuthorDate: Mon Jul 6 16:29:58 2026 +0800 refactor: replace java.lang.reflect with MethodHandle/VarHandle for JIT optimization Motivation: java.lang.reflect Method.invoke and Constructor.newInstance bypass JIT inlining, adding overhead to build-time aggregation calls and test code. Modification: - SbtInternalAccess: replace Method.invoke with MethodHandle.invoke via unreflect for Aggregation.showRun calls - Http2ServerSpec: replace Field.get with VarHandle.get via unreflectVarHandle for ManualProbe.probe field access - TurkishISpec: replace Constructor.newInstance with MethodHandle.invoke via unreflectConstructor for HttpCharsets$ instantiation Result: MethodHandle and VarHandle enable JIT inlining, eliminating reflection overhead in both build-time and test code paths. Tests: - sbt "http2-tests / Test / compile" - success - sbt "http-core / Test / compile" - success References: None - internal refactoring --- .../org/apache/pekko/http/scaladsl/model/TurkishISpec.scala | 9 ++++++--- .../apache/pekko/http/impl/engine/http2/Http2ServerSpec.scala | 10 +++++++--- project/SbtInternalAccess.scala | 8 +++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/TurkishISpec.scala b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/TurkishISpec.scala index 58d6a89f6..5ac7ec0cb 100644 --- a/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/TurkishISpec.scala +++ b/http-core/src/test/scala/org/apache/pekko/http/scaladsl/model/TurkishISpec.scala @@ -13,6 +13,7 @@ package org.apache.pekko.http.scaladsl.model +import java.lang.invoke.MethodHandles import java.util.Locale import org.apache.pekko.http.impl.util._ import org.scalatest.matchers.should.Matchers @@ -21,8 +22,10 @@ import org.scalatest.wordspec.AnyWordSpec class TurkishISpec extends AnyWordSpec with Matchers { "Model" should { "not suffer from turkish-i problem" in { - val charsetCons = Class.forName("org.apache.pekko.http.scaladsl.model.HttpCharsets$").getDeclaredConstructor() - charsetCons.setAccessible(true) + val charsetClass = Class.forName("org.apache.pekko.http.scaladsl.model.HttpCharsets$") + val charsetCtor = charsetClass.getDeclaredConstructor() + charsetCtor.setAccessible(true) + val charsetHandle = MethodHandles.lookup().unreflectConstructor(charsetCtor) val previousLocale = Locale.getDefault @@ -34,7 +37,7 @@ class TurkishISpec extends AnyWordSpec with Matchers { // demonstrate difference between toRootLowerCase and toLowerCase(turkishLocale) (testString.toLowerCase should not).equal(testString.toRootLowerCase) - val newCharsets = charsetCons.newInstance().asInstanceOf[HttpCharsets.type] + val newCharsets = charsetHandle.invoke().asInstanceOf[HttpCharsets.type] newCharsets.getForKey("iso-8859-1") shouldEqual Some(newCharsets.`ISO-8859-1`) } finally { Locale.setDefault(previousLocale) diff --git a/http2-tests/src/test/scala/org/apache/pekko/http/impl/engine/http2/Http2ServerSpec.scala b/http2-tests/src/test/scala/org/apache/pekko/http/impl/engine/http2/Http2ServerSpec.scala index 573a96335..bc2b19b7e 100644 --- a/http2-tests/src/test/scala/org/apache/pekko/http/impl/engine/http2/Http2ServerSpec.scala +++ b/http2-tests/src/test/scala/org/apache/pekko/http/impl/engine/http2/Http2ServerSpec.scala @@ -13,6 +13,7 @@ package org.apache.pekko.http.impl.engine.http2 +import java.lang.invoke.MethodHandles import javax.net.ssl.SSLContext import scala.collection.immutable @@ -907,10 +908,13 @@ class Http2ServerSpec extends Http2SpecWithMaterializer(""" def fulfillDemandWithin(publisherProbe: TestPublisher.Probe[?], timeout: FiniteDuration)( body: => Unit): Unit = { // HACK to support `expectRequest` with a timeout + val probeHandle = { + val probeField = classOf[ManualProbe[?]].getDeclaredField("probe") + probeField.setAccessible(true) + MethodHandles.lookup().unreflectVarHandle(probeField) + } def within[T](publisherProbe: TestPublisher.Probe[?], dur: FiniteDuration)(t: => T): T = { - val field = classOf[ManualProbe[?]].getDeclaredField("probe") - field.setAccessible(true) - field.get(publisherProbe).asInstanceOf[TestProbe].within(dur)(t) + probeHandle.get(publisherProbe).asInstanceOf[TestProbe].within(dur)(t) } def expectRequest(timeout: FiniteDuration): Long = within(publisherProbe, timeout)(publisherProbe.expectRequest()) diff --git a/project/SbtInternalAccess.scala b/project/SbtInternalAccess.scala index bd56f21b9..1ed158b73 100644 --- a/project/SbtInternalAccess.scala +++ b/project/SbtInternalAccess.scala @@ -13,16 +13,18 @@ package sbt { package object access { + import java.lang.invoke.MethodHandles + type Aggregation = sbt.internal.Aggregation val Aggregation = sbt.internal.Aggregation - private val showRunMethod = { + private val showRunHandle = { val method = Class.forName("sbt.internal.Aggregation$").getDeclaredMethods.find(_.getName == "showRun").get method.setAccessible(true) - method + MethodHandles.lookup().unreflect(method) } def AggregationShowRun[T](complete: sbt.internal.Aggregation.Complete[T], show: sbt.internal.Aggregation.ShowConfig)( - implicit display: Show[ScopedKey[?]]): Unit = showRunMethod.invoke(Aggregation, complete, show, display) + implicit display: Show[ScopedKey[?]]): Unit = showRunHandle.invoke(Aggregation, complete, show, display) } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
