java - Scala 宏和 JVM 的方法大小限制

标签 java scala macros jvm scala-macros

我正在用 Scala 宏替换 Java 程序中的一些代码生成组件,并且遇到了 Java 虚拟机对单个方法生成的字节码大小的限制(64 KB)。

例如,假设我们有一个很大的 XML 文件,它表示我们想要在程序中使用的从整数到整数的映射。我们想避免在运行时解析这个文件,所以我们将编写一个宏来在编译时进行解析并使用文件的内容来创建我们方法的主体:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object BigMethod {
  // For this simplified example we'll just make some data up.
  val mapping = List.tabulate(7000)(i => (i, i + 1))

  def lookup(i: Int): Int = macro lookup_impl
  def lookup_impl(c: Context)(i: c.Expr[Int]): c.Expr[Int] = {
    import c.universe._

    val switch = reify(new scala.annotation.switch).tree
    val cases = mapping map {
      case (k, v) => CaseDef(c.literal(k).tree, EmptyTree, c.literal(v).tree)
    }

    c.Expr(Match(Annotated(switch, i.tree), cases))
  }
}

在这种情况下,编译后的方法将刚好超过大小限制,但不是一个很好的错误说明,而是给我们一个巨大的堆栈跟踪,其中包含对 TreePrinter.printSeq 的大量调用并被告知我们已经杀死了编译器。

我有 a solution这涉及将案例分成固定大小的组,为每个组创建一个单独的方法,并添加一个将输入值分派(dispatch)到适当组的方法的顶级匹配。它有效,但令人不快,而且我不希望每次编写宏时都必须使用这种方法,其中生成的代码的大小取决于某些外部资源。

有没有更简洁的方法来解决这个问题?更重要的是,有没有办法更优雅地处理这种编译器错误?我不喜欢图书馆用户收到一个难以理解的“那个条目似乎已经杀死了编译器”错误消息的想法,只是因为某个宏正在处理的 XML 文件已经超过了一些(相当低的)大小阈值。

最佳答案

Imo 将数据放入 .class 并不是一个好主意。 它们也被解析,它们只是二进制的。但是将它们存储在 JVM 中可能会对垃圾收集器和 JIT 编译器的性能产生负面影响。

在您的情况下,我会将 XML 预编译成正确格式的二进制文件并对其进行解析。现有工具的合格格式可以是例如FastRPC或好老DBF .或者可以预先填写 ElasticSearch如果您需要快速的高级查找和搜索,请使用存储库。后者的一些实现还可以提供基本索引,甚至可以忽略解析 - 应用程序只会从相应的偏移量中读取。

关于java - Scala 宏和 JVM 的方法大小限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17004747/

相关文章:

rust - 检查Rust宏中的bool值

scala - 验证 sbt-Assembly IntelliJ 中的着色

tomcat - scalate 不编译 tomcat 中的模板

scala - 启用 REPL 高级用户模式 ​​( :power) from script

C 接口(interface)和实现 : why there are both function assert and macro assert?

clojure - 宏不能返回匿名函数?克洛尤尔

java - Throws 关键字不能与线程的 run 方法一起使用

java - 在 JPanel 上绘制部分透明的 PNG

java - 设置 Windows 光标

Java OutputStream 和 InputStream 初始化