Skip to content
微信扫码关注公众号

JEP 215: Tiered Attribution for javac | javac 的分层归因

zhai

javac 中实现一种新的方法类型检查策略,以加速参数位置的多态表达式的属性化。

目标

实现一种名为层次化归因(TA)的新方法,用于类型检查多态表达式,其提供:

  • 通过实施一种减少属性化所需的(冗余)传递次数的方法来改进性能,并且

  • 获得与当前类型检查实现相同的结果。

非目标

目标并不是更改可编译程序的范围,尽管在修复现有类型检查方案中隐藏的错误的同时可能会导致一些变化。还可能出现编译器生成消息上的一些细小差异。

显著改善当前代码的清洁度和可维护性也不是目标 - 尽管这个 JEP 引入的一些变化可能导致更简洁的代码。

动机

目前实现的 Java SE 8 多态表达式 javac 类型检查方法被称为'假设归因'(SA);SA 的主要思想是多次针对不同目标对同一棵树进行类型检查;例如,可以将 lambda 表达式与多个重载解析目标进行检查。

在重载解析的中间执行类型检查的能力是一种非常强大和灵活的技术,但它的性能代价非常高。更具体地说,对于 N 个重载候选项,同一参数表达式可以被检查多达 N×3 次(每个重载阶段一次,严格、宽松、可变参数)+ 1 次(最后一次检查阶段)。如果参数表达式允许嵌套(例如,lambda 返回多态方法调用),这些因素需要相乘,导致属性化调用的组合爆炸。

对假设归因机制的指数级调用次数导致了已知的性能问题,并作为错误观察和报告,例如,JDK-8077247JDK-8078093JDK-8055984

描述

本 JEP 提议了一种替代性且更有效的实现方案,以支持在 javac 中对多态表达式进行类型检查。从概念上讲,在执行重载解析时没有必要对表达式进行类型检查;实际上,参数表达式可以以自底向上的方式进行类型检查 - 产生无需属性的重载检查,或者此类表达式与适用性无关(参见 JLS 15.12.2.2)- 表示此类表达式不会对重载解析的适用性检查产生贡献。例如,lambda 表达式可以是显式的 - 在这种情况下,可以在重载解析之前执行主体的类型检查;或者它可以是隐式的,在这种情况下,在重载解析期间不需要进行类型检查。

层次化归因的主要思想是在重载解析之前生成自底向上结构类型(针对给定方法调用中出现的每个多态参数表达式一个)并提供执行重载解析适用性检查所需的所有信息 - 也就是说,无需进一步进行归因。这些结构类型可以包含部分推断的类型变量,这些类型变量只会在稍后的阶段(在调用类型推理时,参见 JLS 18.5.2)被固定。将为以下参数表达式创建新的结构类型:

  • Lambda 表达式,
  • 条件多态表达式,
  • 通用方法调用,
  • 带括号的多态表达式,
  • 方法引用,以及
  • 菱形实例创建表达式。

由于上述一些表达式可以允许嵌套,因此结构类型可能会提及其他结构类型。例如,模拟具有返回通用方法调用的 lambda 体的情况可以使用指向另一个模拟通用方法调用的结构类型(对于 lambda 表达式)的结构类型来建模。在这种情况下,与结构类型相关联的重载检查可以是递归的 - 例如,lambda 主体中返回表达式中提及的所有结构类型都必须与重载解析机制提供的目标类型进行检查。

在属性化方法/构造函数调用的参数时,通常会创建结构类型。在方法/构造函数调用之外的上下文中出现的多态表达式应该与今天的处理方式相同。

为了适当地实现嵌套泛型方法调用,还需要对类型推理进行一些更改;具体而言,类型推理机制必须配备更好的保存和回滚功能,以处理涉及泛型方法调用的重载检查(可能需要执行一些推理任务),而不会永久污染与此类调用相关联的上下文信息。

测试

javac已经包含了一套全面的回归测试,以证明 SA 按预期工作;虽然这些测试大部分是黑盒测试,但它们应该能够有效地捕捉到层次化归因实现中的错误。由于这个 JEP 的结果,可能会添加一些其他测试 - 特别是与众所周知的性能瓶颈相关的测试。

依赖关系

这里提出的工作可能有益于两个相关的 JEP:正确处理导入语句(JEP 216)注解管道 2.0(JEP 217)