kagamihogeの日記

kagamihogeの日記です。

JEP 301: Enhanced Enumsをテキトーに訳した

http://openjdk.java.net/jeps/301 をテキトーに訳した。

JEP 301: Enhanced Enums

Owner    Maurizio Cimadamore
Created 2016/11/25 11:27
Updated 2016/12/08 18:51
Type    Feature
Status  Candidate
Component   tools?/?javac
Scope   SE
Discussion  platform dash jep dash discuss at openjdk dot java dot net
Effort  M
Duration    M
Priority    3
Issue   8170351
Relates to  JEP 286: Local-Variable Type Inference

Summary

Java言語のenum定数の表現力を、enum型変数(generic enums)により機能強化することで、enum定数の型チェックをより詳細なものにします。

Goals

二つの機能拡張を共に使うことで、enum定数が定数固有の型情報と定数固有の状態と振る舞いを持てるようにします。開発者が望ましい結果を実現するためにenumをクラスに置き換えなければならないケースが多数存在します。機能拡張によりそのようなケースは減少すると思われます。

以下の例は二つの機能拡張を共に使用しているものです。

enum Argument<X> { // declares generic enum
   STRING<String>(String.class), 
   INTEGER<Integer>(Integer.class), ... ;

   Class<X> clazz;

   Argument(Class<X> clazz) { this.clazz = clazz; }

   Class<X> getClazz() { return clazz; }
}

Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant

Non-Goals

本JEPではenum定数の型チェックの機能拡張は目的としません。例えば、別のenum関連機能として、

  • enumのサブクラス可能化
  • 非staticコンテキストでのenum使用可能化

は本JEPの対象外です。

Motivation

Javaenumは便利な部品です。定数をグループ化し、それぞれの定数はシングルトンのオブジェクトになります。定数はボディを宣言することも可能で、enum宣言のベースの振る舞いをオーバーライドできます。以下の例ではenumJavaのプリミティブ型のモデル化を試みていきます。まずは下記からスタートします。

enum Primitive {
    BYTE,
    SHORT,
    INT,
    FLOAT,
    LONG,
    DOUBLE,
    CHAR,
    BOOLEAN;
}

上述のように、enum宣言はクラスのように行い、コンストラクタを持てます。コンストラクタを用いてボックスクラスの保持と各プリミティブのデフォルト値を指定します。

enum Primitive {
    BYTE(Byte.class, 0),
    SHORT(Short.class, 0),
    INT(Integer.class, 0),
    FLOAT(Float.class, 0f),
    LONG(Long.class, 0L),
    DOUBLE(Double.class, 0d),
    CHAR(Character.class, 0),
    BOOLEAN(Boolean.class, false);

    final Class<?> boxClass;
    final Object defaultValue;

    Primitive(Class<?> boxClass, Object defaultValue) {
       this.boxClass = boxClass;
       this.defaultValue = defaultValue;
    }

}

上記は一応問題ないですが制限があります。フィールドのboxClassClass<?>という弱い型付けになっており、これはフィールドの型がenum定数で使用するすべての特定型(sharper types)*1で互換性が必要なためです。その結果、以下のようなコードを試みると、

Class<Short> cs = SHORT.boxedClass(); //error

コンパイルエラーとなります。さらに、defaultValueフィールドはObject型です。異なるプリミティブ型を表現する定数を単一のフィールドで共有する必要があるのでこれは避けられません。そのため、静的な安全性は無くなり、コンパイラは以下のようなコードを許容します。

String s = (String)INT.defaultValue(); //ok

上述の問題点は、enumとクラス間に固有の非対象性を取り除くことと、enum定数の型チェックの改良によって、対処が可能です。より正確に言うと、

  • enum宣言に型引数を使えるようにする。
  • enum定数に関連付けられた特定型情報の事前削除(prematurely erase)を行わない。

これらの拡張により、Primitive enumは以下のように書き換えられます。

enum Primitive<X> {
    INT(Integer.class, 0) {
       int mod(int x, int y) { return x % y; }
       int add(int x, int y) { return x + y; }
    },
    FLOAT(Float.class, 0f)  {
       long add(long x, long y) { return x + y; }
    }, ... ;

    final Class<X> boxClass;
    final X defaultValue;

    Primitive(Class<X> boxClass, X defaultValue) {
       this.boxClass = boxClass;
       this.defaultValue = defaultValue;
    }
}

以前のものと比べるとジェネリック宣言によって明確さが向上しています。enum定数Primitive.INTは特定パラメータ型Primitiveを持ち、そのメンバは特定型になります。

Class<Short> cs = SHORT.boxedClass(); //ok!

また、enum定数の型情報は事前削除されないため、コンパイラは定数のメンバについて推論可能になります。例は以下になります。

int zero_int = INT.mod(50, 2); //ok
int zero_float = FLOAT.mod(50, 2); //error

enum定数FLOATmodというメンバが無いのでコンパイラは上記の二つ目についてはエラーに出来ます。これにより型安全性を保証します。

Description

Generic enums

JDK-6408723で議論されたように、enumジェネリクスを適用可能にする重要な要求があり、その内容は型パラメータをenum定数宣言に完全にバインドします。これにより現行のenumを補強するシンプルな変換スキーマ(straightforward translation scheme)が使用可能になります。例えば、以下のようなenum宣言があるとき、

enum Foo<X> {
   ONE<String>,
   TWO<Integer>;
}

糖衣構文を除去した後の同等なコードは以下になる予定です。

/* enum */ class Foo<X> {
   static Foo<String> ONE = ...
   static Foo<Integer> TWO = ...

   ...
}

型のバインディングは静的に与えられているため、各定数とstaticフィールド宣言とのマッピングは可能です。

enum定数の初期化にはダイアモンドを使えることが望ましいです。たとえば、

enum Bar<X> {
   ONE<>(Integer.class),
   TWO<>(String.class);

   Bar(X x) { ... }
}

ダイアモンドを使う場合、enum定数にボディ(=無名クラスに変換される)があり、かつ、推論型がnon-denotableの場合、特別な配慮が必要となります。無名内部クラスにダイアモンドがある場合、コンパイラはそのダイアモンドを拒否する必要があります。

Sharper typing of enum constants

現行のルールでは、enum定数のstatic型はenum自身の型となります。このルールでは、上述の定数Foo.ONEFoo.TWOは同じ型Fooとなります。このルールは少なくとも以下2つの理由により望ましくありません。

  • ジェネリックenumの場合、定数のstatic型はその定数の完全な型を捕捉するには不十分です。
  • ジェネリックenumが無い場合であっても、enum定数にだけ定義されているメンバへクライアントからアクセスするのに定数型は不十分です(本JEPの冒頭の例を参照)。

この制約を越えるため、enum定数がそれ自身の型を得るようにenum定数の型付けを再定義すべきです。いまEenum宣言し、ECジェネリック可)をenum定数宣言するとします。もし以下条件のどちらかが満たされる場合、定数Cは特定型に関連付けられます。

  • CC<T1, T2 ... Tn>でボディ宣言無し。定数の特定型はE<T1, T2 ... Tn>となる。
  • Cがボディを持つ。定数の特定型は以下どちらかがスーパータイプとなる無名型(E.C)になる。

これらの拡張される型付けによって、Foo.ONEFoo.TWOのstatic型はそれぞれ異なるものに出来ます。

Additional Considerations

Binary compatibility

以下のenumがあるとします。

enum Test {
   A { void a() { } }
   B { void b() { } }
}

前述の通り、以下のように変換されます。

/* enum */ class Test {
   static Test A = new Test() { void a() { } }
   static Test B = new Test() { void b() { } }
}

enum定数に特定型を持たせるには、素朴なやり方として以下のような変換が考えれます。

/* enum */ class Test {
   static Test$1 A = new Test() { void a() { } }
   static Test$2 B = new Test() { void b() { } }
}

これは明らかにバイナリ非互換です。再コンパイル時にenum定数Aの型はTestからTest$1に変更されます。この変更はTestを使用する再コンパイルしていないクライアントコードを壊すことになります。

この問題を解決するには、イレイジャベースの方法がベターです。Aのstatic型を特定型Test.Aにする場合、定数型への参照はベースのenumTestをイレーズしたものとなります。これにより先述のものに反しないバイナリ互換性のコードとなります。しかし、Testへの参照がすべてイレーズされる場合、特定のenum定数のメンバへのアクセスの実装方法はどうすれば良いでしょうか?

Foo.A.a();

上記コードの場合、Aへのシンボリック参照はTestにイレーズされ、メソッド呼び出しは型付け(well-typed)されません(Testにはaという名前のメンバは無いため)。この問題を解消するには、コンパイラはsynthetic cast*2を挿入する必要があります。

checkcast Test$1
invokevirtual Test$1::a

このsynthetic castは、イレーズを経由する交差型(intersection type through erasure)のメンバアクセスと相似形になっていません。

別の直交する所見(orthogonal observation)として、現行のenum定数クラスのネーミング規則は壊れやすい、があります。上述のTest$1Test$2は本質的には順序依存です。つまり、enum定数宣言の順序変更がバイナリ互換問題を発生させる可能性があります。とりわけ、上述のABを入れ替えてenumを再コンパイルすると、Test$1aというメンバのメソッドを持たなくなっているため、クライアントのバイトコードはリンクに失敗します。これらはenumバイナリ互換性のある拡張に関するJLSの言及内容と明らかに反しています。

enumの追加もしくは順序変更(reordering)が既存バイナリとの互換性を壊さないこと。

バイナリ互換を保つための別の方法に順序非依存のクラス名出力があります。例えばTest$1Test$2の代わりにTest$ATest$Bとなります。この変更のリフレクションとシリアライズに対する影響は以下に述べます。

Serialization

JavaEnumはSerializableを実装しているのですべてのenumは暗黙的にserializableになります。本JEPの変更がシリアライズに関する互換性を保とうと我々は考えています。シリアライズ形式を変更すべきではありません。シリアライズ仕様 http://docs.oracle.com/javase/6/docs/platform/serialization/spec/serial-arch.html#6469enumに関する特別な扱いの記述があります。enum定数のシリアライズ形式はその名前についてだけで、また、enum定数のserialization/deserializationのカスタムは不可能です。(すべてのenum定数は<clinit>中に初期化され、デシリアライズenumのstatic values()を呼び出すとEnum.valueOfメソッドが使われます。この動作によりベースenumクラス(とすべての定数)の初期化を暗黙的に強制します。)

つまり、シリアライズ形式はコンパイラが生成するクラス名に依存していないため、既存のシリアライズ形式に関する互換性問題はありません。

Reflection

バイナリ名が出てくる別の領域としてリフレクションがあります。以下は完全に問題の無いリフレクションのコードです。

Class<?> c = Class.forName("Test$1");
System.err.println(c.getName()); //prints Test$1

リフレクションにはenum定数をインスタンス化させないための制約がありますが、enum定数クラスのメンバのインスペクションには制約がありません。上記のイディオムを使用する既存コードは本JEPでenum定数のバイナリ形式を変更すると動作しなくなります。

Denotability

現状、enum定数は値であり型ではありません。よって、enum定数もdenotable typesにすべきかどうか、は妥当な質問です。

The usual arguments apply here - しかし、enum定数にdenotable typeを持たせることでマジックを減らし*3プログラマenum定数の型で変数宣言が可能となります。しかし、欠点もあります。

  • 同一の識別子が値と型の両方を意味するため、コードの可読性を下げる可能性がある(例: A a = A)。
  • すべてのenum定数がそれ自身の型を持つかどうかは事前には明確ではない。メンバを宣言しないenum定数の場合は? 型がベースのenum型のエイリアスに過ぎない場合は?

enum定数型がnon-denotable typeの場合、プログラマは間接的な相互作用(例:型推論経由)のみ可能となる不透明さが発生します。non-denotable typeの欠点を和らげる、ローカル変数型推論の追加提案に注目しておく必要があります。これは、enum特定型がnon-denotableであっても、その型で変数宣言を技術的には可能とします(例:var a = A)。

Accessibility

enum特定型でのメンバのアクセス性に関するコーナーケースがあります。以下の例を考えます。

package a;

public enum Foo {
  A() { 
    public String s = "Hello!";
  };
}

package b;

class Client {
   public static void main(String[] args) {
      String s = Foo.A.s; //IllegalAccessError
   }
}

このコードを実行すると、VMIllegalAccessErrorを出します。この問題は、enum定数Foo$Aの無名クラスがパッケージプライベートになるため、別パッケージからパッケージプライベートのクラスのpublicフィールドにアクセスしようとしてアクセスエラーになります。この問題を解決するには、enum定数クラスはenumクラスの定義と同じ修飾子になるべきです。

Source compatibility

ソース互換性の観点では、本JEPの機能と型推論との相互作用時に漏れが出る特定型のケースが存在します。以下のコードを考えます。

EnumSet<Test> e = EnumSet.of(Test.A);

上記コードは比較的よく使われるものです。Test.Aのstatic型は単にTestで、両方ともTestという名前の型の制約を持つため、EnumSet.ofの型変数の推論はシンプルです。しかし、Test.Aが型チェックされるような変更をすると、その振る舞いは微妙になり、EnumSet.ofの型変数は二つの競合する制約を取得します。Test(ターゲット型)と等しくかつTest.Aのスーパータイプでなければなりません。幸い、こうした場合には、型推論はより厳密な等価制約を選ぶようなスマートさを備えているため、結果として推論はTestになります。本JEPの変更のソース互換性への影響はJDK-8075793とは異なっており、where the change caused capture variables to appear in more places instead of their upper bounds.

Risks and Assumptions

上述の概要の通り大きく二種類のリスクが本JEPの提案には存在します。

  • enum定数のバイナリ名の変更がリフレクションの中核機能に問題を引き起こす可能性がある。
  • enum定数の型付けに関する変更が、とりわけターゲット型が無い場合のメソッドの型推論に微妙な変更を引き起こす可能性がある。

前者の問題はおそらくあまり心配する必要は無く、上述の通り、enum定数のバイナリ名は現状大変壊れやすくて再順序付けの問題を引き起こしがちです。そのため、enum定数のバイナリ名に依存するコードは本来的に壊れやすく、その理由は本質的に特定のコンパイラの出力に依存しているからです。

後者の問題は、潜在的にソース互換性の問題になりうるため、より厄介です。上述のソース非互換性問題がどの程度発生しうるかを特定するため、我々は様々な引数でEnumSet.ofがどの程度呼ばれているか計測しました。各呼び出しについて、ターゲット型が利用可能なコンテキストで呼び出せるかどうかを追跡しました。以下はその結果です(計測はすべてのオープンなJDKリポジトリ群に対して実施)。

  • EnumSet.ofの呼び出し: 150
    • 引数で呼び出し = 1:69
      • そのうちで、ターゲット型無し: 0

つまり、上述のソース互換性問題は重大な問題を引き起こさないと考えられます。

Dependencies

enum定数で使われる特定型は必ずしもdenotableにならず、non-denotable型の別のカテゴリになります。このことはJEP-286 (Local Variable Type Inference)のnon-denotable型の扱いと相互に影響を及ぼす可能性があります。non-denotable型に関するJEP-286の決定に依存しますが、

var a = Argument.String;

Argumentではなく特定型Argument.Stringの型を持てるように出来るかもしれません。

*1:文脈から明らかのとおりClass<?>ではないClass<Integer>とかのことを指してるわけだが、良い日本語浮かばなかったので、とりあえずこう訳した。

*2:java syntheticとかでぐぐれば出てくるが、コンパイラコンパイル時にメソッドやフィールドを合成(synthetic)することを指しているらしい。

*3:makes it less magicが原文。マジックナンバーとかそういうのかと。

アトラス作品ファン交流会の眼鏡祭  シン・メガネ(スーパー眼鏡祭F完結編)(2016/11/12)に行ってきた

11/12 シン・メガネ(スーパー眼鏡祭F完結編) - TwiPla に行ってきました。当日の様子はtwitterハッシュタグ #眼鏡祭1112 で追うことが出来ます。

眼鏡祭はペルソナ中心アトラス作品ファンのオフ会

当日は快晴で気温も落ち着いており、終日穏やかで過ごしやすい一日となりました。当日の朝に電車遅延が若干懸念されたものの大きな問題にならず関係者一同は皆ホッとしていたことと思います。

会場は眼鏡祭常連にいつもの場所であるキリストンカフェ 東京を貸切っての開催です。参加者は約250人近くにもなり、今回も活況を呈しておりました。眼鏡祭は常連も多いのですが、ペルソナ5が発売されて数ヶ月といったタイミングであり、初めての参加者の割合もいつも通りチラホラと見られました。

眼鏡祭の特徴はコスプレOKなオフ会

眼鏡祭の雰囲気を大まかにつかむには、以下のコスプレ参加者による全体集合写真を見るのが良いです。

コスプレするかしないかは個人の自由ですが、参加者の7~8割は何らかのコスプレをしています。アトラス作品縛りのコスプレでこれだけの人数が集まるのは相当レアな光景なこともあり、毎回圧倒させられます。

今回のコスプレの比率は、やはりなんといってもペルソナ5が最大勢力でした。P5主人公ことジョーカーの私服・制服・怪盗衣装に囚人服は当然のこと。竜司君にアン殿など怪盗団はそろい踏みでした。あとはベルベットルームの双子や川上先生、武見女医、ガンショップの岩井などCOOPの人たち。しかしなんといってもやたらいた佐倉惣治郎が皆の心に残ったんではないでしょうか。

ただしコスプレイベントではなく、あくまででもコスプレ可能なオフ会

上記のように眼鏡祭は見た目にも派手なコスプレがどうしても眼を惹きますが、趣旨はあくまでもゲームプレイヤー同士の交流をするオフ会です。そのため、コスプレの撮影に関しては本人の許可を取ること。また、SNSなどのアップロードにも本人の許可を取ること。人が多いので自撮り棒は使わず誰かに依頼すること、など幾つかルールが定められています。

他にもいくつか細かいルールがありますが、どれも常識的な範疇に収まるものなので基本的にはそれほど意識することはありません。前提条件として、アルコールを提供するから20歳以上であり、皆大人なので節度を守った楽しい飲み会にしましょう、というのがこれらルールの根底にあるようです。

ネタバレには出来る限り最大限の配慮がされていた

さて、200人オーバーも集まるとなると気になるのはネタバレの扱い。発売日が2016年9月15日でクリア時間は話を聞いているとおおむね100時間前後くらいのようです。これを考慮すると今回の開催日は絶妙でしたが、しかしまだまだ未クリアな人も多数おり、結構判断が難しいところに見えました。しかし、100%防ぐのは不可能にしてもかなりの程度防止する仕組みが準備されており、これはTECHNICALで素晴らしかったです。

まず、会場は大きく二つに分けてネタバレOK・NGフロアとなりました。もちろん、何か仕切りがあるわけではないので往来は自由です。つまり、最初に来場して席に着くテーブルは間違いなくネタバレOK・NGのどちらかしかいないことになります。

次に、参加者は名前とtwitter等のidを書いた札を首からぶらさげます。これの色が青はスタッフ、黒はネタバレOK、赤はネタバレNG、という色識別になりました。私はまだクリアしていないから体感したんですが、この仕組みは強力でした。

何故かというと、黒札の人はこちらが赤札なのをチラッと見ると会話内容に配慮してくれるためです。プレイ済みな人だからこそネタバレされるのがつまらないことを知っている、ということなんでしょう。

勿論、クリアしていたらもっと楽しく会話出来たことは当然のことです。やはり、ネタバレへの配慮は必要なのだとしても誰はばかることなくオープンに盛り上がりたい、と思うのは自然なことでしょう。

一人で行っても楽しめるかどうか

私も元々は一人だけで参加した類なので、これだけ巨大なオフ会に参加するのに二の足踏む気持ちは大変良く分かります。とはいえ、周囲は全員、皆多かれ少なかれオタクです。朝から晩までゲームアニメマンガの話ずっとしていても何も言われない場ですが、皆そういう欲望をどこかして持っているものです。真昼間から、コスプレして、飲んで、騒ぐ。眼鏡祭は、DJがBGM流してくれてる以外、特に決まった催しものがないですが、そのシンプルな内容に皆惹かれて集まってきているようです。

運営チームの皆さんおつかれさまです

眼鏡祭はイベント会社を使っているわけではなく、会場と飲食提供を除けば、有志のスタッフで回しています。

上記は一例として、マンパワーが大量にいる力仕事の会場設営およびどうしても細かい配慮が必要とされる女子更衣室関連の方のtweetを引用させていただきました。これら目に付くもの以外にもあれやこれや大変な苦労が裏側では確実にあるわけで、毎回本当に頭が上がりません。

最後になりましたが、主催のマソーさん並びに運営スタッフの方々、今回の参加者の皆さんと一・二・三次会で自分と話してくれた人たち、それとこの日記で眼鏡祭の雰囲気を伝えるために勝手ながらtweet引用させて頂いた方々、先日はありがとうございました。

今後のイベントなどリンク

JEP 296: Consolidate the JDK Forest into a Single Repositoryをテキトーに訳した

http://openjdk.java.net/jeps/296 をテキトーに訳した。

JEP 296: Consolidate the JDK Forest into a Single Repository

Author   Joseph D. Darcy
Owner   Joe Darcy
Created 2016/10/07 18:42
Updated 2016/10/26 23:34
Type    Infrastructure
Status  Candidate
Component   infrastructure/build
Scope   Implementation
Discussion  jdk9 dash dev at openjdk dot java dot net
Effort  M
Duration    S
Priority    3
Reviewed by Brian Goetz, Mikael Vidstedt
Release 10
Issue   8167368

Summary

多数のJDKリポジトリ群を単一リポジトリに統合して開発の簡易化と効率化を行います。

Non-Goals

JDKへのFXのソース追加は本JEPには含めません。

Motivation

長年の間に、JDKの完全なコードベースは多数のMercurialリポジトリに分割されてきました。JDK 9では8個のリポジトリroot, corba, hotspot, jaxp, jaxws, jdk, langtools, and nashornがあります。

複数リポジトリには何点かの利点がある一方で様々な欠点があり、あるべきソースコード管理オプションサポートが貧弱になっています。とりわけ、内部的に依存関係のあるチェンジセットの複数リポジトリにまたがるアトミックなコミットが出来ません。たとえば、いま単一のバグフィックスあるいはRFEのコードがjdkとhotspotリポジトリの両方を触るとした場合、両リポジトリへの変更を個々のリポジトリに対してアトミックに実行出来ません。複数リポジトリ変更はよくあることで、1,100以上のバグidがリポジトリで再利用されています。この1,100個という数字は論理的なリポジトリ横断バグ数の下限に過ぎず、その理由はエンジニアによっては異なるリポジトリへのプッシュに異なるバグidを使用しているためです。

上述のMercurialリポジトリの分断とエンジニアの作業単位のミスマッチにより近代的なソースコード管理管理の主なメリットである、個々のファイルではなくファイルのチェンジセットのトラッキング、が薄められています。その結果、SCMトランザクションと論理的なトランザクションとのミスマッチはMercurial bisectなどのツール使用を困難にしています。

JDK全体とは別の開発サイクルを個々のリポジトリが持つわけではありません。すべてのリポジトリJDKのプロモーションサイクルに歩調を合わせます。多数のリポジトリは新規の開発者に対する障壁となり、"get source"スクリプトなどの回避策を取らせることになりました。

Description

これらの問題解決のため、統合リポジトリのプロトタイプが作られました。プロトタイプは以下で利用可能です。

http://hg.openjdk.java.net/jdk9/consol-proto/

プロトタイプ作成に使われた変換スクリプトのいくつかはunify.zipでアタッチされています。

このプロトタイプでは、個々のファイルレベルのヒストリーを保持する自動変換スクリプトで8個のリポジトリを単一リポジトリに統合しており、JDKプロモーションをマークするのに使われるタグで統合コード群を同期化しています。チェンジセットのコメントと生成日も維持しています。

プロトタイプでは異なるコード整理のためのレベルを導入しています。統合リポジトリでは、Javaモジュールのコードは基本的には単一トップレベルsrcディレクトリ下に結合しています。たとえば、現在のJDKリポジトリには以下のようなモジュールベースのディレクトリがあります。

$ROOT/jdk/src/java.base
...
$ROOT/langtools/src/java.compiler
...

統合リポジトリでは以下のように編成されます。

$ROOT/src/java.base
$ROOT/src/java.compiler
...

結果として、リポジトリルートからのモジュール内のソースファイルの相対パスは統合後はsrcディレクトリ下に維持されます。

テストディレクトリに対してはやや異なる再編成策を計画しています(ただし実装は未完成)。*1

$ROOT/jdk/test/Foo.java
$ROOT/langtools/test/Bar.java

上記から以下にします。

$ROOT/test/jdk/Foo.java
$ROOT/tests/langtools/Bar.java

まだプロトタイプであるため、不完全な部分がありますが改善は可能です。$ROOT/jdk, $ROOT/langtoolsなどのディレクトリに残存ファイルがまだありますが、それらのファイルは以降の作業で再編成を予定しています。HotSpot C/C++のソースはモジュール化したJavaコードと共に共有srcディレクトリに移動します。

jtreg設定ファイルのアップデートサポートは現在作業中です(JDK-8165187)。

Alternatives

代案の一つとしては単に現行のリポジトリセットのままにしておくことが挙げられます。単一リポジトリ以降時にはリポジトリのヒストリーの全てあるいはいくつかが消失する可能性がありましたが、that was rejected*2リポジトリの中核セブセットを統合することも考えられましたが、単一リポジトリの明快さという点で無しになりました。

Testing

ファイルの中身の検証には、あるタグの旧リポジトリの内容とそれに対応する同じタグの統合リポジトリの内容を検証するスクリプトを使用しています。最新のJDK 9のタグでは、同一タグの統合リポジトリと旧リポジトリのビルドが比較されており、少数の説明がつく差異のみが存在します。

Risks and Assumptions

上述のテストによりファイル衝突とビルド失敗の重大なリスクを軽減すべきです。統合に必要な作業の大部分はプロトタイプ上に完成していますが、JDK 10でオープンにしたいと考えているその時までに各種の小規模サポート機能は準備出来ないかもしれません。統合前後のコードベースはMercurial senseでは関連がありません。チェンジセットのエクスポートとインポートとは対照的に、foward-portとback-portのためにはDiffs (with suitably massaged paths)を使う使う必要がああります。*3

*1:An analogous but less aggressive reorganization is planned が原文。良い日本語浮かばなかった。

*2:何がrejectされたのか良く分からん…

*3:Risks and Assumptionsの項は良く分からんくて全般的に訳が微妙。