Javaプログラムのコード生成コンポーネントの一部をScalaマクロに置き換え、Java仮想マシンの個々のメソッドの生成バイトコードのサイズ制限(64キロバイト)。ScalaマクロとJVMのメソッドサイズ制限
たとえば、私たちのプログラムで使用したい整数から整数へのマッピングを表すlarge-ish 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です。それは動作しますが、それは不愉快です。私は、生成されたコードのサイズがいくつかの外部リソースに依存するマクロを書くたびに、このアプローチを使用する必要はありません。
この問題に対処するためのよりクリーンな方法はありますか?もっと重要なのは、この種のコンパイラエラーをよりうまく処理する方法があるかどうかです。マクロで処理されているXMLファイルの一部が(かなり低い)サイズのしきい値を超えたため、ライブラリユーザーが「コンパイラを破棄したように見える」エラーメッセージが表示されるのは嫌いです。
この質問は(http://stackoverflow.com/q/6570343/334519)[「既に回答」]としてマークされますが、私が求めていることはその中で求められているものとは全く異なるされています質問。JVMのメソッドのサイズ制限を変更することはできないことを知っています.Scalaの新しい(2.10)マクロシステムのコンテキストでは、回避策とエラー処理について質問しています。 –
素朴に試してみました。この地球上の私の時間は有限であるので、私はctl-c'dです。なぜこれがひどく終わらなければならなかったのか分かります。 –
@ som-snytt:ここで面白いのは同じだし、それがどういう意味かわからない。 '-optimize'がなければ、2.11.0-M3は妥当なエラーメッセージを少なくとも出します。 –