Jython 3 路线图
这份讨论文档试图概述通往 Jython 3 的步骤,由 MVP 功能定义。可能存在明显的遗漏。它故意没有日期。
除了交付功能外,它还旨在满足某些自愿约束,这些约束被认为从长远来看是健康的。
- 可理解且有文档记录的架构。
- 便于贡献。
- 作为 Python 的模型实现可读。
- 尽管存在
- 彻底的代码重组。
- 彻底的更改(对某些代码)。
- 使某些代码暂时失效或死亡。
为了实现这些目标中的第二个(历史),在以下内容中,如果暗示我们实现了一些类或包,默认方法将是建立在先前的技术之上并对其进行认可。为了在每个源文件中实现这一点,我们使用 git-move(提交),然后修改最接近的对应 Jython 2 文件。
中间提交通常会生成一个无法构建的版本,并且不应将其作为提示推送到项目存储库。随后的编辑和另一个提交将纠正这一点。死代码通常是件坏事,应该保留,直到我们知道我们不会恢复它来提供以后的功能。可能需要创建存根来满足未恢复代码中的引用。
一个粗略的计划
焦土政策
-
重构代码库,使其能够使用 Gradle 构建。遗留代码保留在原位,等待移动和修改。
-
第一个构建目标是一个库
jython-3.8a1-DEV
,但最初它将为空。 -
提供一些基本地标(模块化项目结构)和一个用于控制子系统日志消息的约定。(这对我们来说是一个调试辅助工具,并演变为生产使用中的信息。)
类型和算术
-
概述对象、类型、操作、槽的架构。指定抽象对象 API(类似于 CPython 的)。
-
实现
PyBaseObject
、PyType
和一些简单类型(大多数没有操作)。仅实现 Java API 并为类型构造和继承编写 JUnit 测试。 -
实现类型槽,向简单类型添加槽函数,并实现抽象对象 API。通过 JUnit 测试整个过程,调用抽象对象 API。从这里开始,添加的新操作意味着新的抽象对象 API 和匹配的 JUnit 测试。
-
验证通过 API 调用算术运算是否实现了可接受的性能。可能使用微基准测试进行测量,这些测试作为库上的应用程序构建。
add(a, b)
的性能与 CPythona+b
的性能相当是可接受的性能。(目标是一系列操作,而不仅仅是+
。)微基准测试套件应该随着功能的添加而增长。
解释器和线程
-
概述解释器、帧和线程模型的架构。
-
Interpreter
、PyFrame
和PyCode
支持执行 CPython 字节码的初始子集。从这里开始,添加新功能包括对字节码解释器的功能库进行相应的添加,以便接受依赖于该功能的字节码。 -
读取 CPython 输出的代码对象的方法。它可能只是一个临时机制,或者是对
pickle
的部分实现。 -
PyJavaFunction
和PyJavaModule
(但还没有import
)。 -
builtins
模块的初步形式。随后,将根据需要在此添加对象。 -
微基准测试,在兼容的 Jython
PyFrame
中执行 Python 片段的编译形式。目标是与 CPythontimeit
在相同片段上的结果相当。代码和引用从字符串生成。(是否有可能创建一个框架,使这个不断扩展的套件工作量最小?) -
微基准测试验证与 CPython
f(args, kwargs)
的一致性,涵盖各种参数模式f()
、f(x)
、f(x, k=1)
等。 -
验证并发线程的正确操作,特别是类型在构造过程中不会逃逸不完整。随着添加可能存在并发错误风险的功能,此套件应该不断扩展。
描述符协议
-
对象模型的进一步架构,旨在完整描述在 Python 或 Java 中定义的类型以及多重继承。
-
在 Python 中定义的类的实现(但仍然由 CPython 编译)。
-
描述符协议和机制,用于从类中填充
PyType
字典和槽。通过 JUnit(直接或通过抽象对象 API)进行测试。 -
使用 Java 中的注释定义类、成员和方法。(类似于 Jython 2 的暴露器,但更透明、有文档记录,并使用
MethodHandle
简化)。
对象实验
考虑将每个 Object
变成 Python 对象对性能和 Java 集成透明度的优势。探索对常见内置类型的“可接受实现”的想法,以允许例如 String
成为 str
。使用 CallSite
作为 MethodHandle
(已在槽中)的使用者进行实验。
解决 PyObject
与 Object
的困境。
Java 集成
将 Java 对象视为 Python 对象的方法和基本实现,当它们没有被明确识别(内置)时,它们具有与 Java 类相关的 Python 类型。对编译为 Java 的代码进行性能微基准测试。
模块导入
-
模块和导入器的架构概述,特别关注 Java 包和模块的语义。Python 中模块概念的进步应该使我们能够避免在 Jython 2 中发现的一些特殊情况和反复操作。
-
sys
和io
的基本形式。随后,根据需要添加对象。 -
实现紧密遵循 CPython 的导入机制。
-
使用自定义查找器(可能)从 Java 导入对象。
编译器
-
根据需要在编译器中进一步选择
stdlib
模块。 -
从 Python ASDL 生成的 AST 类。生成的类是
ast
模块中的 Python 对象。(问题:它们应该在 Java 中生成吗?使用 ANTLR?) -
从 Python 源代码到 AST 的编译器,可能使用 PEG 解析器。(如果采用 PEG,请使用 CPython 编译它,并使用 Jython 运行它)。
-
从 AST 到 CPython 字节码的编译器:如果可能,使用 Python 中的版本(使用 CPython 编译)。否则,在 Java 中遵循 CPython 实现。(Jython 2 遗留中没有 CPython 字节码编译器)。
Jython 命令
-
Jython 3 控制台命令作为基于库的 Java 应用程序。
-
在所有主要操作系统上调用 Jython 的方法。
Python stdlib
逐步引入 stdlib
及其回归测试套件。
CPython 回归测试套件对于推动我们的一致性和完整性非常有用,但测试过程本身依赖于很大一部分语言和 stdlib
已经工作。
实现说明
一些原则,一些来自 jython-dev
或脱机讨论。
- 与 Jython 2 相比,采用或编写更多用 Python 而不是 Java 编写的模块。(性能良好但不是高性能的解释器是先决条件)。
- 只有性能关键的模块是用 Java 手动制作的。
- 利用 Java 库的模块从 Python 调用它们。
- 对用 Java 编写的热情应该用于重新实现扩展 Jython 使用的流行库(
numpy
等)。
- 与 Jython 2 相比,使用更少的外部 JAR。
- 每个 JAR 的用途应在构建中记录。
- 避免绕过 JVM 的库
- 处理字符串和 I/O 的不兼容性代价高昂。
- 许多与
jnr.posix
相关的错误。 (用java.nio.file
替换?) - 仔细考虑我们提供的
os.*
方法及其语义。 - 重新考虑
jnr.jffi
。 (删除相关的ctypes
支持。)
- 从
MethodHandle
开始,使用动态语言特性 (终于)。- 一个更接近现代 CPython 的核心实现。
- MVP: 使用
MethodHandle
填充类型槽 (概念已证明)。 - 编译成 JVM 字节码时,使用相同或相关的
MethodHandle
创建调用站点。
- 使用 PEG 解析器,遵循 GvR 的领导。
- 为我们提供了很多免费的东西 (但不是一个完整的编译器)。
- MVP: 仍然需要一个词法分析器。 (ANTLR?)
- MVP: 从 ASDL 生成 AST 类。 (Python 或 ANTLR?)
- MVP: 从 AST 到 Python 字节码的编译器。 (Python 中可用?)
- 从 AST 到 Java 字节码的编译器。 (我们自己编写/更新。)
- 在开发过程中使用 six 模块,以确保我们的用户可以使用它进行迁移。 (建议需要探索。)
构建环境
所有这些都应该从一开始就遵循,以保持可接受的质量 (即 MVP)。
-
该项目位于 GitHub,其中 3.8 是一个分支。
- 我们遵循 CPython 流程
- Jython 开发指南应反映这些流程
- 可能无法接受 miss-islington 等集成。
- 使用 Gradle 构建
- 多项目,例如:
core
、compiler
、lib
、apps
子项目。 - 复合项目,例如,
tools
仅供我们构建时使用。
- 多项目,例如:
- 构建依赖于目标版本的 CPython。
- 可能需要用于代码生成
- 作为 StringTemplate 的处理器,或者替代 StringTemplate
- 生成 CPython 字节码 (交付的一部分)
- 性能微基准测试的参考。
- 测试结果的参考 (可能只针对程序员)。
- 交付 (MVP) 不需要安装或运行 CPython。
- 可能需要用于代码生成
- 定期在多个层级进行测试
- JUnit 测试用于隔离核心元素 (每次构建/提交)。
regrtest
测试集成解释器 (提交之前)。- 测试 REPL 中的解析 (以某种方式模拟,合并之前)。
- 这是与 CPython 共享的需求。
- 测试用户实际安装的内容:JAR 和应用程序 (合并之前)。
- 测试典型的用户集成 (合并之前)。
一些不应采用的道路
- 不:直接在
jython/jython3
仓库上构建。- 它复制了 Jython 2 对象模型。我们希望继续前进。
- 它从未从主干中提取任何错误修复,我们认为合并过于困难。
- 希望以某种方式承认这项工作,并提取一些内容,也许是转换后的模块,如果这样做效率很高。
- 我们应该在
jython/Jython3
上明确说明它不是 Jython 3。- 关于项目死亡的报告不断出现在那里。
- 当然,它们被大大夸大了。
- 不:将 Gradle 的使用弯曲到为 Ant 设计的文件结构。
- 现有的 Gradle 构建以这种方式工作,而且它非常辛苦。
- Git 能够跟踪已移动文件的祖先。
- 不:从头开始。
- Jython 2 代码库包含大量
- 我们甚至在 Jython 3 中没有意识到的问题的解决方案。
- 设计选择 (虽然大部分没有理由)。
- 我们希望将我们的历史追溯到早期贡献者。
- 缺点:在相当长的一段时间内,我们将在
/src
中拥有等待合并的遗留代码。
- Jython 2 代码库包含大量