Я заменяю некоторые компоненты генерации кода в программе Java с помощью макросов Scala, и я запускаю лимит виртуальной машины Java на размер сгенерированного байтового кода для отдельных методов (64 килобайта).
Например, предположим, что у нас есть большой 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
, и нам говорят, что мы убил компилятор.
У меня есть решение, которое включает разделение дел на группы фиксированного размера, создание отдельного метода для каждой группы и добавление соответствия верхнего уровня, которое отправляет входное значение к соответствующему групповому методу. Он работает, но это неприятно, и я бы предпочел не использовать этот подход каждый раз, когда пишу макрос, где размер сгенерированного кода зависит от некоторого внешнего ресурса.
Есть ли более чистый способ решить эту проблему? Что еще более важно, есть ли способ более грамотно справиться с такой ошибкой компилятора? Мне не нравится идея о том, что пользователь библиотеки получает сообщение об ошибке "Эта запись, похоже, убил компилятор", только потому, что некоторый XML файл, обрабатываемый макросом, пересек некоторое (довольно низкое) размерное значение.