This commit is contained in:
Roger Riggs 2015-07-14 22:21:52 -04:00
commit 9bb445c368
333 changed files with 26477 additions and 13396 deletions

View File

@ -144,7 +144,6 @@ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \
INCLUDES := $(JIMAGE_PKGS), \
EXCLUDES := jdk/internal/jimage/concurrent, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes))
# Because of the explicit INCLUDES in the compilation setup above, the service provider

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -226,6 +226,11 @@ class CharacterData00 extends CharacterData {
case 0xA77D : mapChar = 0x1D79; break;
case 0xA78D : mapChar = 0x0265; break;
case 0xA7AA : mapChar = 0x0266; break;
case 0xA7AB : mapChar = 0x025C; break;
case 0xA7AC : mapChar = 0x0261; break;
case 0xA7AD : mapChar = 0x026C; break;
case 0xA7B0 : mapChar = 0x029E; break;
case 0xA7B1 : mapChar = 0x0287; break;
// default mapChar is already set, so no
// need to redo it here.
// default : mapChar = ch;
@ -284,10 +289,15 @@ class CharacterData00 extends CharacterData {
case 0x0250 : mapChar = 0x2C6F; break;
case 0x0251 : mapChar = 0x2C6D; break;
case 0x0252 : mapChar = 0x2C70; break;
case 0x025C : mapChar = 0xA7AB; break;
case 0x0261 : mapChar = 0xA7AC; break;
case 0x0265 : mapChar = 0xA78D; break;
case 0x0266 : mapChar = 0xA7AA; break;
case 0x026B : mapChar = 0x2C62; break;
case 0x026C : mapChar = 0xA7AD; break;
case 0x0271 : mapChar = 0x2C6E; break;
case 0x0287 : mapChar = 0xA7B1; break;
case 0x029E : mapChar = 0xA7B0; break;
case 0x027D : mapChar = 0x2C64; break;
case 0x1D79 : mapChar = 0xA77D; break;
case 0x1D7D : mapChar = 0x2C63; break;
@ -503,6 +513,22 @@ class CharacterData00 extends CharacterData {
// This is the only char with RLO
directionality = Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE;
break;
case 0x2066 :
// This is the only char with LRI
directionality = Character.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE;
break;
case 0x2067 :
// This is the only char with RLI
directionality = Character.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE;
break;
case 0x2068 :
// This is the only char with FSI
directionality = Character.DIRECTIONALITY_FIRST_STRONG_ISOLATE;
break;
case 0x2069 :
// This is the only char with PDI
directionality = Character.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE;
break;
default :
directionality = Character.DIRECTIONALITY_UNDEFINED;
break;
@ -537,11 +563,16 @@ class CharacterData00 extends CharacterData {
case 0x0250 : mapChar = 0x2C6F; break;
case 0x0251 : mapChar = 0x2C6D; break;
case 0x0252 : mapChar = 0x2C70; break;
case 0x025C : mapChar = 0xA7AB; break;
case 0x0261 : mapChar = 0xA7AC; break;
case 0x0265 : mapChar = 0xA78D; break;
case 0x0266 : mapChar = 0xA7AA; break;
case 0x026B : mapChar = 0x2C62; break;
case 0x026C : mapChar = 0xA7AD; break;
case 0x0271 : mapChar = 0x2C6E; break;
case 0x027D : mapChar = 0x2C64; break;
case 0x0287 : mapChar = 0xA7B1; break;
case 0x029E : mapChar = 0xA7B0; break;
case 0x1D79 : mapChar = 0xA77D; break;
case 0x1D7D : mapChar = 0x2C63; break;
case 0x2C65 : mapChar = 0x023A; break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -244,81 +244,118 @@ class CharacterData01 extends CharacterData {
case 0x10132: retval = 80000; break; // AEGEAN NUMBER EIGHTY THOUSAND
case 0x10133: retval = 90000; break; // AEGEAN NUMBER NINETY THOUSAND
case 0x10323: retval = 50; break; // OLD ITALIC NUMERAL FIFTY
case 0x010144: retval = 50; break; // ACROPHONIC ATTIC FIFTY
case 0x010145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED
case 0x010146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND
case 0x010147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND
case 0x01014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS
case 0x01014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS
case 0x01014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS
case 0x01014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS
case 0x01014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS
case 0x010151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS
case 0x010152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS
case 0x010153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS
case 0x010154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS
case 0x010155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS
case 0x010156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS
case 0x010166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY
case 0x010167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM
case 0x010168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY
case 0x010169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY
case 0x01016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED
case 0x01016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED
case 0x01016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED
case 0x01016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED
case 0x01016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED
case 0x01016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED
case 0x010170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED
case 0x010171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND
case 0x010172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND
case 0x010174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS
case 0x010341: retval = 90; break; // GOTHIC LETTER NINETY
case 0x01034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED
case 0x0103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED
case 0x01085D: retval = 100; break; // IMPERIAL ARAMAIC NUMBER ONE HUNDRED
case 0x01085E: retval = 1000; break; // IMPERIAL ARAMAIC NUMBER ONE THOUSAND
case 0x01085F: retval = 10000; break; // IMPERIAL ARAMAIC NUMBER TEN THOUSAND
case 0x010919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED
case 0x010A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED
case 0x010A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND
case 0x010A7E: retval = 50; break; // OLD SOUTH ARABIAN NUMBER FIFTY
case 0x010B5E: retval = 100; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED
case 0x010B5F: retval = 1000; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
case 0x010B7E: retval = 100; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED
case 0x010B7F: retval = 1000; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
case 0x010E6C: retval = 40; break; // RUMI NUMBER FORTY
case 0x010E6D: retval = 50; break; // RUMI NUMBER FIFTY
case 0x010E6E: retval = 60; break; // RUMI NUMBER SIXTY
case 0x010E6F: retval = 70; break; // RUMI NUMBER SEVENTY
case 0x010E70: retval = 80; break; // RUMI NUMBER EIGHTY
case 0x010E71: retval = 90; break; // RUMI NUMBER NINETY
case 0x010E72: retval = 100; break; // RUMI NUMBER ONE HUNDRED
case 0x010E73: retval = 200; break; // RUMI NUMBER TWO HUNDRED
case 0x010E74: retval = 300; break; // RUMI NUMBER THREE HUNDRED
case 0x010E75: retval = 400; break; // RUMI NUMBER FOUR HUNDRED
case 0x010E76: retval = 500; break; // RUMI NUMBER FIVE HUNDRED
case 0x010E77: retval = 600; break; // RUMI NUMBER SIX HUNDRED
case 0x010E78: retval = 700; break; // RUMI NUMBER SEVEN HUNDRED
case 0x010E79: retval = 800; break; // RUMI NUMBER EIGHT HUNDRED
case 0x010E7A: retval = 900; break; // RUMI NUMBER NINE HUNDRED
case 0x01105E: retval = 40; break; // BRAHMI NUMBER FORTY
case 0x01105F: retval = 50; break; // BRAHMI NUMBER FIFTY
case 0x011060: retval = 60; break; // BRAHMI NUMBER SIXTY
case 0x011061: retval = 70; break; // BRAHMI NUMBER SEVENTY
case 0x011062: retval = 80; break; // BRAHMI NUMBER EIGHTY
case 0x011063: retval = 90; break; // BRAHMI NUMBER NINETY
case 0x011064: retval = 100; break; // BRAHMI NUMBER ONE HUNDRED
case 0x011065: retval = 1000; break; // BRAHMI NUMBER ONE THOUSAND
case 0x012432: retval = 216000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH
case 0x012433: retval = 432000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN
case 0x01D36C: retval = 40; break; // COUNTING ROD TENS DIGIT FOUR
case 0x01D36D: retval = 50; break; // COUNTING ROD TENS DIGIT FIVE
case 0x01D36E: retval = 60; break; // COUNTING ROD TENS DIGIT SIX
case 0x01D36F: retval = 70; break; // COUNTING ROD TENS DIGIT SEVEN
case 0x01D370: retval = 80; break; // COUNTING ROD TENS DIGIT EIGHT
case 0x01D371: retval = 90; break; // COUNTING ROD TENS DIGIT NINE
case 0x10144: retval = 50; break; // ACROPHONIC ATTIC FIFTY
case 0x10145: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED
case 0x10146: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND
case 0x10147: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND
case 0x1014A: retval = 50; break; // ACROPHONIC ATTIC FIFTY TALENTS
case 0x1014B: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED TALENTS
case 0x1014C: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED TALENTS
case 0x1014D: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND TALENTS
case 0x1014E: retval = 5000; break; // ACROPHONIC ATTIC FIVE THOUSAND TALENTS
case 0x10151: retval = 50; break; // ACROPHONIC ATTIC FIFTY STATERS
case 0x10152: retval = 100; break; // ACROPHONIC ATTIC ONE HUNDRED STATERS
case 0x10153: retval = 500; break; // ACROPHONIC ATTIC FIVE HUNDRED STATERS
case 0x10154: retval = 1000; break; // ACROPHONIC ATTIC ONE THOUSAND STATERS
case 0x10155: retval = 10000; break; // ACROPHONIC ATTIC TEN THOUSAND STATERS
case 0x10156: retval = 50000; break; // ACROPHONIC ATTIC FIFTY THOUSAND STATERS
case 0x10166: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY
case 0x10167: retval = 50; break; // ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM
case 0x10168: retval = 50; break; // ACROPHONIC HERMIONIAN FIFTY
case 0x10169: retval = 50; break; // ACROPHONIC THESPIAN FIFTY
case 0x1016A: retval = 100; break; // ACROPHONIC THESPIAN ONE HUNDRED
case 0x1016B: retval = 300; break; // ACROPHONIC THESPIAN THREE HUNDRED
case 0x1016C: retval = 500; break; // ACROPHONIC EPIDAUREAN FIVE HUNDRED
case 0x1016D: retval = 500; break; // ACROPHONIC TROEZENIAN FIVE HUNDRED
case 0x1016E: retval = 500; break; // ACROPHONIC THESPIAN FIVE HUNDRED
case 0x1016F: retval = 500; break; // ACROPHONIC CARYSTIAN FIVE HUNDRED
case 0x10170: retval = 500; break; // ACROPHONIC NAXIAN FIVE HUNDRED
case 0x10171: retval = 1000; break; // ACROPHONIC THESPIAN ONE THOUSAND
case 0x10172: retval = 5000; break; // ACROPHONIC THESPIAN FIVE THOUSAND
case 0x10174: retval = 50; break; // ACROPHONIC STRATIAN FIFTY MNAS
case 0x102ED: retval = 40; break; // COPTIC EPACT NUMBER FORTY
case 0x102EE: retval = 50; break; // COPTIC EPACT NUMBER FIFTY
case 0x102EF: retval = 60; break; // COPTIC EPACT NUMBER SIXTY
case 0x102F0: retval = 70; break; // COPTIC EPACT NUMBER SEVENTY
case 0x102F1: retval = 80; break; // COPTIC EPACT NUMBER EIGHTY
case 0x102F2: retval = 90; break; // COPTIC EPACT NUMBER NINETY
case 0x102F3: retval = 100; break; // COPTIC EPACT NUMBER ONE HUNDRED
case 0x102F4: retval = 200; break; // COPTIC EPACT NUMBER TWO HUNDRED
case 0x102F5: retval = 300; break; // COPTIC EPACT NUMBER THREE HUNDRED
case 0x102F6: retval = 400; break; // COPTIC EPACT NUMBER FOUR HUNDRED
case 0x102F7: retval = 500; break; // COPTIC EPACT NUMBER FIVE HUNDRED
case 0x102F8: retval = 600; break; // COPTIC EPACT NUMBER SIX HUNDRED
case 0x102F9: retval = 700; break; // COPTIC EPACT NUMBER SEVEN HUNDRED
case 0x102FA: retval = 800; break; // COPTIC EPACT NUMBER EIGHT HUNDRED
case 0x102FB: retval = 900; break; // COPTIC EPACT NUMBER NINE HUNDRED
case 0x10341: retval = 90; break; // GOTHIC LETTER NINETY
case 0x1034A: retval = 900; break; // GOTHIC LETTER NINE HUNDRED
case 0x103D5: retval = 100; break; // OLD PERSIAN NUMBER HUNDRED
case 0x1085D: retval = 100; break; // IMPERIAL ARAMAIC NUMBER ONE HUNDRED
case 0x1085E: retval = 1000; break; // IMPERIAL ARAMAIC NUMBER ONE THOUSAND
case 0x1085F: retval = 10000; break; // IMPERIAL ARAMAIC NUMBER TEN THOUSAND
case 0x108AF: retval = 100; break; // NABATAEAN NUMBER ONE HUNDRED
case 0x10919: retval = 100; break; // PHOENICIAN NUMBER ONE HUNDRED
case 0x10A46: retval = 100; break; // KHAROSHTHI NUMBER ONE HUNDRED
case 0x10A47: retval = 1000; break; // KHAROSHTHI NUMBER ONE THOUSAND
case 0x10A7E: retval = 50; break; // OLD SOUTH ARABIAN NUMBER FIFTY
case 0x10AEF: retval = 100; break; // MANICHAEAN NUMBER ONE HUNDRED
case 0x10B5E: retval = 100; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE HUNDRED
case 0x10B5F: retval = 1000; break; // INSCRIPTIONAL PARTHIAN NUMBER ONE THOUSAND
case 0x10B7E: retval = 100; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE HUNDRED
case 0x10B7F: retval = 1000; break; // INSCRIPTIONAL PAHLAVI NUMBER ONE THOUSAND
case 0x10BAF: retval = 100; break; // PSALTER PAHLAVI NUMBER ONE HUNDRED
case 0x10E6C: retval = 40; break; // RUMI NUMBER FORTY
case 0x10E6D: retval = 50; break; // RUMI NUMBER FIFTY
case 0x10E6E: retval = 60; break; // RUMI NUMBER SIXTY
case 0x10E6F: retval = 70; break; // RUMI NUMBER SEVENTY
case 0x10E70: retval = 80; break; // RUMI NUMBER EIGHTY
case 0x10E71: retval = 90; break; // RUMI NUMBER NINETY
case 0x10E72: retval = 100; break; // RUMI NUMBER ONE HUNDRED
case 0x10E73: retval = 200; break; // RUMI NUMBER TWO HUNDRED
case 0x10E74: retval = 300; break; // RUMI NUMBER THREE HUNDRED
case 0x10E75: retval = 400; break; // RUMI NUMBER FOUR HUNDRED
case 0x10E76: retval = 500; break; // RUMI NUMBER FIVE HUNDRED
case 0x10E77: retval = 600; break; // RUMI NUMBER SIX HUNDRED
case 0x10E78: retval = 700; break; // RUMI NUMBER SEVEN HUNDRED
case 0x10E79: retval = 800; break; // RUMI NUMBER EIGHT HUNDRED
case 0x10E7A: retval = 900; break; // RUMI NUMBER NINE HUNDRED
case 0x1105E: retval = 40; break; // BRAHMI NUMBER FORTY
case 0x1105F: retval = 50; break; // BRAHMI NUMBER FIFTY
case 0x11060: retval = 60; break; // BRAHMI NUMBER SIXTY
case 0x11061: retval = 70; break; // BRAHMI NUMBER SEVENTY
case 0x11062: retval = 80; break; // BRAHMI NUMBER EIGHTY
case 0x11063: retval = 90; break; // BRAHMI NUMBER NINETY
case 0x11064: retval = 100; break; // BRAHMI NUMBER ONE HUNDRED
case 0x11065: retval = 1000; break; // BRAHMI NUMBER ONE THOUSAND
case 0x111ED: retval = 40; break; // SINHALA ARCHAIC NUMBER FORTY
case 0x111EE: retval = 50; break; // SINHALA ARCHAIC NUMBER FIFTY
case 0x111EF: retval = 60; break; // SINHALA ARCHAIC NUMBER SIXTY
case 0x111F0: retval = 70; break; // SINHALA ARCHAIC NUMBER SEVENTY
case 0x111F1: retval = 80; break; // SINHALA ARCHAIC NUMBER EIGHTY
case 0x111F2: retval = 90; break; // SINHALA ARCHAIC NUMBER NINETY
case 0x111F3: retval = 100; break; // SINHALA ARCHAIC NUMBER ONE HUNDRED
case 0x111F4: retval = 1000; break; // SINHALA ARCHAIC NUMBER ONE THOUSAND
case 0x118ED: retval = 40; break; // WARANG CITI NUMBER FORTY
case 0x118EE: retval = 50; break; // WARANG CITI NUMBER FIFTY
case 0x118EF: retval = 60; break; // WARANG CITI NUMBER SIXTY
case 0x118F0: retval = 70; break; // WARANG CITI NUMBER SEVENTY
case 0x118F1: retval = 80; break; // WARANG CITI NUMBER EIGHTY
case 0x118F2: retval = 90; break; // WARANG CITI NUMBER NINETY
case 0x12432: retval = 216000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS DISH
case 0x12433: retval = 432000; break; // CUNEIFORM NUMERIC SIGN SHAR2 TIMES GAL PLUS MIN
case 0x12467: retval = 40; break; // CUNEIFORM NUMERIC SIGN ELAMITE FORTY
case 0x12468: retval = 50; break; // CUNEIFORM NUMERIC SIGN ELAMITE FIFTY
case 0x16B5C: retval = 100; break; // PAHAWH HMONG NUMBER HUNDREDS
case 0x16B5D: retval = 10000; break; // PAHAWH HMONG NUMBER TEN THOUSANDS
case 0x16B5E: retval = 1000000; break; // PAHAWH HMONG NUMBER MILLIONS
case 0x16B5F: retval = 100000000; break;// PAHAWH HMONG NUMBER HUNDRED MILLIONS
case 0x1D36C: retval = 40; break; // COUNTING ROD TENS DIGIT FOUR
case 0x1D36D: retval = 50; break; // COUNTING ROD TENS DIGIT FIVE
case 0x1D36E: retval = 60; break; // COUNTING ROD TENS DIGIT SIX
case 0x1D36F: retval = 70; break; // COUNTING ROD TENS DIGIT SEVEN
case 0x1D370: retval = 80; break; // COUNTING ROD TENS DIGIT EIGHT
case 0x1D371: retval = 90; break; // COUNTING ROD TENS DIGIT NINE
default: retval = -2; break;
}

View File

@ -1,8 +1,8 @@
# PropList-6.2.0.txt
# Date: 2012-05-23, 20:34:59 GMT [MD]
# PropList-7.0.0.txt
# Date: 2014-02-19, 15:51:26 GMT [MD]
#
# Unicode Character Database
# Copyright (c) 1991-2012 Unicode, Inc.
# Copyright (c) 1991-2014 Unicode, Inc.
# For terms of use, see http://www.unicode.org/terms_of_use.html
# For documentation, see http://www.unicode.org/reports/tr44/
@ -13,7 +13,6 @@
0085 ; White_Space # Cc <control-0085>
00A0 ; White_Space # Zs NO-BREAK SPACE
1680 ; White_Space # Zs OGHAM SPACE MARK
180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE
2028 ; White_Space # Zl LINE SEPARATOR
2029 ; White_Space # Zp PARAGRAPH SEPARATOR
@ -21,14 +20,16 @@
205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
3000 ; White_Space # Zs IDEOGRAPHIC SPACE
# Total code points: 26
# Total code points: 25
# ================================================
061C ; Bidi_Control # Cf ARABIC LETTER MARK
200E..200F ; Bidi_Control # Cf [2] LEFT-TO-RIGHT MARK..RIGHT-TO-LEFT MARK
202A..202E ; Bidi_Control # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE
2066..2069 ; Bidi_Control # Cf [4] LEFT-TO-RIGHT ISOLATE..POP DIRECTIONAL ISOLATE
# Total code points: 7
# Total code points: 12
# ================================================
@ -51,6 +52,7 @@
2E17 ; Dash # Pd DOUBLE OBLIQUE HYPHEN
2E1A ; Dash # Pd HYPHEN WITH DIAERESIS
2E3A..2E3B ; Dash # Pd [2] TWO-EM DASH..THREE-EM DASH
2E40 ; Dash # Pd DOUBLE HYPHEN
301C ; Dash # Pd WAVE DASH
3030 ; Dash # Pd WAVY DASH
30A0 ; Dash # Pd KATAKANA-HIRAGANA DOUBLE HYPHEN
@ -59,7 +61,7 @@ FE58 ; Dash # Pd SMALL EM DASH
FE63 ; Dash # Pd SMALL HYPHEN-MINUS
FF0D ; Dash # Pd FULLWIDTH HYPHEN-MINUS
# Total code points: 27
# Total code points: 28
# ================================================
@ -91,6 +93,7 @@ FF65 ; Hyphen # Po HALFWIDTH KATAKANA MIDDLE DOT
201F ; Quotation_Mark # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK
2039 ; Quotation_Mark # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK
203A ; Quotation_Mark # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
2E42 ; Quotation_Mark # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
300C ; Quotation_Mark # Ps LEFT CORNER BRACKET
300D ; Quotation_Mark # Pe RIGHT CORNER BRACKET
300E ; Quotation_Mark # Ps LEFT WHITE CORNER BRACKET
@ -106,7 +109,7 @@ FF07 ; Quotation_Mark # Po FULLWIDTH APOSTROPHE
FF62 ; Quotation_Mark # Ps HALFWIDTH LEFT CORNER BRACKET
FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
# Total code points: 29
# Total code points: 30
# ================================================
@ -136,6 +139,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
1361..1368 ; Terminal_Punctuation # Po [8] ETHIOPIC WORDSPACE..ETHIOPIC PARAGRAPH SEPARATOR
166D..166E ; Terminal_Punctuation # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP
16EB..16ED ; Terminal_Punctuation # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION
1735..1736 ; Terminal_Punctuation # Po [2] PHILIPPINE SINGLE PUNCTUATION..PHILIPPINE DOUBLE PUNCTUATION
17D4..17D6 ; Terminal_Punctuation # Po [3] KHMER SIGN KHAN..KHMER SIGN CAMNUC PII KUUH
17DA ; Terminal_Punctuation # Po KHMER SIGN KOOMUUT
1802..1805 ; Terminal_Punctuation # Po [4] MONGOLIAN COMMA..MONGOLIAN FOUR DOTS
@ -149,6 +153,8 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
203C..203D ; Terminal_Punctuation # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG
2047..2049 ; Terminal_Punctuation # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK
2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK
2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP
2E41 ; Terminal_Punctuation # Po REVERSED COMMA
3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP
A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK
@ -174,14 +180,27 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
103D0 ; Terminal_Punctuation # Po OLD PERSIAN WORD DIVIDER
10857 ; Terminal_Punctuation # Po IMPERIAL ARAMAIC SECTION SIGN
1091F ; Terminal_Punctuation # Po PHOENICIAN WORD SEPARATOR
10A56..10A57 ; Terminal_Punctuation # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA
10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS
10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION
10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
111C5..111C6 ; Terminal_Punctuation # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA
12470..12473 ; Terminal_Punctuation # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON
111CD ; Terminal_Punctuation # Po SHARADA SUTRA MARK
11238..1123C ; Terminal_Punctuation # Po [5] KHOJKI DANDA..KHOJKI DOUBLE SECTION MARK
115C2..115C5 ; Terminal_Punctuation # Po [4] SIDDHAM DANDA..SIDDHAM SEPARATOR BAR
115C9 ; Terminal_Punctuation # Po SIDDHAM END OF TEXT MARK
11641..11642 ; Terminal_Punctuation # Po [2] MODI DANDA..MODI DOUBLE DANDA
12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP
16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM
16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS
1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
# Total code points: 176
# Total code points: 214
# ================================================
@ -230,6 +249,10 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
21D5..21DB ; Other_Math # So [7] UP DOWN DOUBLE ARROW..RIGHTWARDS TRIPLE ARROW
21DD ; Other_Math # So RIGHTWARDS SQUIGGLE ARROW
21E4..21E5 ; Other_Math # So [2] LEFTWARDS ARROW TO BAR..RIGHTWARDS ARROW TO BAR
2308 ; Other_Math # Ps LEFT CEILING
2309 ; Other_Math # Pe RIGHT CEILING
230A ; Other_Math # Ps LEFT FLOOR
230B ; Other_Math # Pe RIGHT FLOOR
23B4..23B5 ; Other_Math # So [2] TOP SQUARE BRACKET..BOTTOM SQUARE BRACKET
23B7 ; Other_Math # So RADICAL SYMBOL BOTTOM
23D0 ; Other_Math # So VERTICAL LINE EXTENSION
@ -358,7 +381,7 @@ FF3E ; Other_Math # Sk FULLWIDTH CIRCUMFLEX ACCENT
1EEA5..1EEA9 ; Other_Math # Lo [5] ARABIC MATHEMATICAL DOUBLE-STRUCK WAW..ARABIC MATHEMATICAL DOUBLE-STRUCK YEH
1EEAB..1EEBB ; Other_Math # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
# Total code points: 1358
# Total code points: 1362
# ================================================
@ -403,8 +426,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0825..0827 ; Other_Alphabetic # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
0829..082C ; Other_Alphabetic # Mn [4] SAMARITAN VOWEL SIGN LONG I..SAMARITAN VOWEL SIGN SUKUN
08E4..08E9 ; Other_Alphabetic # Mn [6] ARABIC CURLY FATHA..ARABIC CURLY KASRATAN
08F0..08FE ; Other_Alphabetic # Mn [15] ARABIC OPEN FATHATAN..ARABIC DAMMA WITH DOT
0900..0902 ; Other_Alphabetic # Mn [3] DEVANAGARI SIGN INVERTED CANDRABINDU..DEVANAGARI SIGN ANUSVARA
08F0..0902 ; Other_Alphabetic # Mn [19] ARABIC OPEN FATHATAN..DEVANAGARI SIGN ANUSVARA
0903 ; Other_Alphabetic # Mc DEVANAGARI SIGN VISARGA
093A ; Other_Alphabetic # Mn DEVANAGARI VOWEL SIGN OE
093B ; Other_Alphabetic # Mc DEVANAGARI VOWEL SIGN OOE
@ -457,6 +479,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0BC6..0BC8 ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI
0BCA..0BCC ; Other_Alphabetic # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU
0BD7 ; Other_Alphabetic # Mc TAMIL AU LENGTH MARK
0C00 ; Other_Alphabetic # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
0C01..0C03 ; Other_Alphabetic # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
0C3E..0C40 ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
0C41..0C44 ; Other_Alphabetic # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
@ -464,6 +487,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0C4A..0C4C ; Other_Alphabetic # Mn [3] TELUGU VOWEL SIGN O..TELUGU VOWEL SIGN AU
0C55..0C56 ; Other_Alphabetic # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK
0C62..0C63 ; Other_Alphabetic # Mn [2] TELUGU VOWEL SIGN VOCALIC L..TELUGU VOWEL SIGN VOCALIC LL
0C81 ; Other_Alphabetic # Mn KANNADA SIGN CANDRABINDU
0C82..0C83 ; Other_Alphabetic # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
0CBE ; Other_Alphabetic # Mc KANNADA VOWEL SIGN AA
0CBF ; Other_Alphabetic # Mn KANNADA VOWEL SIGN I
@ -474,6 +498,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
0CCC ; Other_Alphabetic # Mn KANNADA VOWEL SIGN AU
0CD5..0CD6 ; Other_Alphabetic # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK
0CE2..0CE3 ; Other_Alphabetic # Mn [2] KANNADA VOWEL SIGN VOCALIC L..KANNADA VOWEL SIGN VOCALIC LL
0D01 ; Other_Alphabetic # Mn MALAYALAM SIGN CANDRABINDU
0D02..0D03 ; Other_Alphabetic # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
0D3E..0D40 ; Other_Alphabetic # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II
0D41..0D44 ; Other_Alphabetic # Mn [4] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC RR
@ -538,7 +563,8 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
19B0..19C0 ; Other_Alphabetic # Mc [17] NEW TAI LUE VOWEL SIGN VOWEL SHORTENER..NEW TAI LUE VOWEL SIGN IY
19C8..19C9 ; Other_Alphabetic # Mc [2] NEW TAI LUE TONE MARK-1..NEW TAI LUE TONE MARK-2
1A17..1A18 ; Other_Alphabetic # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
1A19..1A1B ; Other_Alphabetic # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
1A19..1A1A ; Other_Alphabetic # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
1A1B ; Other_Alphabetic # Mn BUGINESE VOWEL SIGN AE
1A55 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN MEDIAL RA
1A56 ; Other_Alphabetic # Mn TAI THAM CONSONANT SIGN MEDIAL LA
1A57 ; Other_Alphabetic # Mc TAI THAM CONSONANT SIGN LA TANG LAI
@ -564,7 +590,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
1BA2..1BA5 ; Other_Alphabetic # Mn [4] SUNDANESE CONSONANT SIGN PANYAKRA..SUNDANESE VOWEL SIGN PANYUKU
1BA6..1BA7 ; Other_Alphabetic # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
1BA8..1BA9 ; Other_Alphabetic # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
1BAC..1BAD ; Other_Alphabetic # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA
1BAC..1BAD ; Other_Alphabetic # Mn [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA
1BE7 ; Other_Alphabetic # Mc BATAK VOWEL SIGN E
1BE8..1BE9 ; Other_Alphabetic # Mn [2] BATAK VOWEL SIGN PAKPAK E..BATAK VOWEL SIGN EE
1BEA..1BEC ; Other_Alphabetic # Mc [3] BATAK VOWEL SIGN I..BATAK VOWEL SIGN O
@ -575,6 +601,7 @@ FF41..FF46 ; Hex_Digit # L& [6] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH L
1C2C..1C33 ; Other_Alphabetic # Mn [8] LEPCHA VOWEL SIGN E..LEPCHA CONSONANT SIGN T
1C34..1C35 ; Other_Alphabetic # Mc [2] LEPCHA CONSONANT SIGN NYIN-DO..LEPCHA CONSONANT SIGN KANG
1CF2..1CF3 ; Other_Alphabetic # Mc [2] VEDIC SIGN ARDHAVISARGA..VEDIC SIGN ROTATED ARDHAVISARGA
1DE7..1DF4 ; Other_Alphabetic # Mn [14] COMBINING LATIN SMALL LETTER ALPHA..COMBINING LATIN SMALL LETTER U WITH DIAERESIS
24B6..24E9 ; Other_Alphabetic # So [52] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN SMALL LETTER Z
2DE0..2DFF ; Other_Alphabetic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
A674..A67B ; Other_Alphabetic # Mn [8] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC LETTER OMEGA
@ -616,6 +643,7 @@ ABE6..ABE7 ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN YENAP..MEETE
ABE8 ; Other_Alphabetic # Mn MEETEI MAYEK VOWEL SIGN UNAP
ABE9..ABEA ; Other_Alphabetic # Mc [2] MEETEI MAYEK VOWEL SIGN CHEINAP..MEETEI MAYEK VOWEL SIGN NUNG
FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
10376..1037A ; Other_Alphabetic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
@ -636,14 +664,54 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
111B6..111BE ; Other_Alphabetic # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
111BF ; Other_Alphabetic # Mc SHARADA VOWEL SIGN AU
1122C..1122E ; Other_Alphabetic # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
1122F..11231 ; Other_Alphabetic # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
11232..11233 ; Other_Alphabetic # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
11234 ; Other_Alphabetic # Mn KHOJKI SIGN ANUSVARA
11237 ; Other_Alphabetic # Mn KHOJKI SIGN SHADDA
112DF ; Other_Alphabetic # Mn KHUDAWADI SIGN ANUSVARA
112E0..112E2 ; Other_Alphabetic # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
112E3..112E8 ; Other_Alphabetic # Mn [6] KHUDAWADI VOWEL SIGN U..KHUDAWADI VOWEL SIGN AU
11301 ; Other_Alphabetic # Mn GRANTHA SIGN CANDRABINDU
11302..11303 ; Other_Alphabetic # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
1133E..1133F ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
11340 ; Other_Alphabetic # Mn GRANTHA VOWEL SIGN II
11341..11344 ; Other_Alphabetic # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
11347..11348 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
1134B..1134C ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN OO..GRANTHA VOWEL SIGN AU
11357 ; Other_Alphabetic # Mc GRANTHA AU LENGTH MARK
11362..11363 ; Other_Alphabetic # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
114B0..114B2 ; Other_Alphabetic # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
114B3..114B8 ; Other_Alphabetic # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
114B9 ; Other_Alphabetic # Mc TIRHUTA VOWEL SIGN E
114BA ; Other_Alphabetic # Mn TIRHUTA VOWEL SIGN SHORT E
114BB..114BE ; Other_Alphabetic # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
114BF..114C0 ; Other_Alphabetic # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
114C1 ; Other_Alphabetic # Mc TIRHUTA SIGN VISARGA
115AF..115B1 ; Other_Alphabetic # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
115B2..115B5 ; Other_Alphabetic # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
115B8..115BB ; Other_Alphabetic # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
115BC..115BD ; Other_Alphabetic # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
115BE ; Other_Alphabetic # Mc SIDDHAM SIGN VISARGA
11630..11632 ; Other_Alphabetic # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
11633..1163A ; Other_Alphabetic # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
1163B..1163C ; Other_Alphabetic # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
1163D ; Other_Alphabetic # Mn MODI SIGN ANUSVARA
1163E ; Other_Alphabetic # Mc MODI SIGN VISARGA
11640 ; Other_Alphabetic # Mn MODI SIGN ARDHACANDRA
116AB ; Other_Alphabetic # Mn TAKRI SIGN ANUSVARA
116AC ; Other_Alphabetic # Mc TAKRI SIGN VISARGA
116AD ; Other_Alphabetic # Mn TAKRI VOWEL SIGN AA
116AE..116AF ; Other_Alphabetic # Mc [2] TAKRI VOWEL SIGN I..TAKRI VOWEL SIGN II
116B0..116B5 ; Other_Alphabetic # Mn [6] TAKRI VOWEL SIGN U..TAKRI VOWEL SIGN AU
16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK
1F130..1F149 ; Other_Alphabetic # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
# Total code points: 922
# Total code points: 1116
# ================================================
@ -746,6 +814,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
1939..193B ; Diacritic # Mn [3] LIMBU SIGN MUKPHRENG..LIMBU SIGN SA-I
1A75..1A7C ; Diacritic # Mn [8] TAI THAM SIGN TONE-1..TAI THAM SIGN KHUEN-LUE KARAN
1A7F ; Diacritic # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
1AB0..1ABD ; Diacritic # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
1B34 ; Diacritic # Mn BALINESE SIGN REREKAN
1B44 ; Diacritic # Mc BALINESE ADEG ADEG
1B6B..1B73 ; Diacritic # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
@ -760,8 +829,10 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
1CE2..1CE8 ; Diacritic # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
1CED ; Diacritic # Mn VEDIC SIGN TIRYAK
1CF4 ; Diacritic # Mn VEDIC TONE CANDRA ABOVE
1CF8..1CF9 ; Diacritic # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
1D2C..1D6A ; Diacritic # Lm [63] MODIFIER LETTER CAPITAL A..GREEK SUBSCRIPT SMALL LETTER CHI
1DC4..1DCF ; Diacritic # Mn [12] COMBINING MACRON-ACUTE..COMBINING ZIGZAG BELOW
1DF5 ; Diacritic # Mn COMBINING UP TACK ABOVE
1DFD..1DFF ; Diacritic # Mn [3] COMBINING ALMOST EQUAL TO BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
1FBD ; Diacritic # Sk GREEK KORONIS
1FBF..1FC1 ; Diacritic # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI
@ -779,6 +850,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
A66F ; Diacritic # Mn COMBINING CYRILLIC VZMET
A67C..A67D ; Diacritic # Mn [2] COMBINING CYRILLIC KAVYKA..COMBINING CYRILLIC PAYEROK
A67F ; Diacritic # Lm CYRILLIC PAYEROK
A69C..A69D ; Diacritic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
A6F0..A6F1 ; Diacritic # Mn [2] BAMUM COMBINING MARK KOQNDON..BAMUM COMBINING MARK TUKWENTIS
A717..A71F ; Diacritic # Lm [9] MODIFIER LETTER DOT VERTICAL BAR..MODIFIER LETTER LOW INVERTED EXCLAMATION MARK
A720..A721 ; Diacritic # Sk [2] MODIFIER LETTER STRESS AND HIGH TONE..MODIFIER LETTER STRESS AND LOW TONE
@ -791,26 +863,45 @@ A92E ; Diacritic # Po KAYAH LI SIGN CWI
A953 ; Diacritic # Mc REJANG VIRAMA
A9B3 ; Diacritic # Mn JAVANESE SIGN CECAK TELU
A9C0 ; Diacritic # Mc JAVANESE PANGKON
A9E5 ; Diacritic # Mn MYANMAR SIGN SHAN SAW
AA7B ; Diacritic # Mc MYANMAR SIGN PAO KAREN TONE
AA7C ; Diacritic # Mn MYANMAR SIGN TAI LAING TONE-2
AA7D ; Diacritic # Mc MYANMAR SIGN TAI LAING TONE-5
AABF ; Diacritic # Mn TAI VIET TONE MAI EK
AAC0 ; Diacritic # Lo TAI VIET TONE MAI NUENG
AAC1 ; Diacritic # Mn TAI VIET TONE MAI THO
AAC2 ; Diacritic # Lo TAI VIET TONE MAI SONG
AAF6 ; Diacritic # Mn MEETEI MAYEK VIRAMA
AB5B ; Diacritic # Sk MODIFIER BREVE WITH INVERTED BREVE
AB5C..AB5F ; Diacritic # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
ABEC ; Diacritic # Mc MEETEI MAYEK LUM IYEK
ABED ; Diacritic # Mn MEETEI MAYEK APUN IYEK
FB1E ; Diacritic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
FE20..FE26 ; Diacritic # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
FE20..FE2D ; Diacritic # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW
FF3E ; Diacritic # Sk FULLWIDTH CIRCUMFLEX ACCENT
FF40 ; Diacritic # Sk FULLWIDTH GRAVE ACCENT
FF70 ; Diacritic # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
FFE3 ; Diacritic # Sk FULLWIDTH MACRON
102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK
10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA
11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA
111C0 ; Diacritic # Mc SHARADA SIGN VIRAMA
11235 ; Diacritic # Mc KHOJKI SIGN VIRAMA
11236 ; Diacritic # Mn KHOJKI SIGN NUKTA
112E9..112EA ; Diacritic # Mn [2] KHUDAWADI SIGN NUKTA..KHUDAWADI SIGN VIRAMA
1133C ; Diacritic # Mn GRANTHA SIGN NUKTA
1134D ; Diacritic # Mc GRANTHA SIGN VIRAMA
11366..1136C ; Diacritic # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
11370..11374 ; Diacritic # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
114C2..114C3 ; Diacritic # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
115BF..115C0 ; Diacritic # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
1163F ; Diacritic # Mn MODI SIGN VIRAMA
116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA
116B7 ; Diacritic # Mn TAKRI SIGN NUKTA
16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
1D167..1D169 ; Diacritic # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
@ -818,8 +909,9 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
1D17B..1D182 ; Diacritic # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
1D185..1D18B ; Diacritic # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
1D1AA..1D1AD ; Diacritic # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
1E8D0..1E8D6 ; Diacritic # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
# Total code points: 693
# Total code points: 766
# ================================================
@ -841,12 +933,16 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
A015 ; Extender # Lm YI SYLLABLE WU
A60C ; Extender # Lm VAI SYLLABLE LENGTHENER
A9CF ; Extender # Lm JAVANESE PANGRANGKEP
A9E6 ; Extender # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
AA70 ; Extender # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
AADD ; Extender # Lm TAI VIET SYMBOL SAM
AAF3..AAF4 ; Extender # Lm [2] MEETEI MAYEK SYLLABLE REPETITION MARK..MEETEI MAYEK WORD REPETITION MARK
FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
1135D ; Extender # Lo GRANTHA SIGN PLUTA
115C6..115C8 ; Extender # Po [3] SIDDHAM REPETITION MARK-1..SIDDHAM REPETITION MARK-3
16B42..16B43 ; Extender # Lm [2] PAHAWH HMONG SIGN VOS NRUA..PAHAWH HMONG SIGN IB YAM
# Total code points: 31
# Total code points: 38
# ================================================
@ -866,17 +962,22 @@ FF70 ; Extender # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND
2170..217F ; Other_Lowercase # Nl [16] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL ONE THOUSAND
24D0..24E9 ; Other_Lowercase # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z
2C7C..2C7D ; Other_Lowercase # Lm [2] LATIN SUBSCRIPT SMALL LETTER J..MODIFIER LETTER CAPITAL V
A69C..A69D ; Other_Lowercase # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
A770 ; Other_Lowercase # Lm MODIFIER LETTER US
A7F8..A7F9 ; Other_Lowercase # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
AB5C..AB5F ; Other_Lowercase # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
# Total code points: 183
# Total code points: 189
# ================================================
2160..216F ; Other_Uppercase # Nl [16] ROMAN NUMERAL ONE..ROMAN NUMERAL ONE THOUSAND
24B6..24CF ; Other_Uppercase # So [26] CIRCLED LATIN CAPITAL LETTER A..CIRCLED LATIN CAPITAL LETTER Z
1F130..1F149 ; Other_Uppercase # So [26] SQUARED LATIN CAPITAL LETTER A..SQUARED LATIN CAPITAL LETTER Z
1F150..1F169 ; Other_Uppercase # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
1F170..1F189 ; Other_Uppercase # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
# Total code points: 42
# Total code points: 120
# ================================================
@ -918,10 +1019,15 @@ FFFFE..FFFFF ; Noncharacter_Code_Point # Cn [2] <noncharacter-FFFFE>..<noncha
200C..200D ; Other_Grapheme_Extend # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER
302E..302F ; Other_Grapheme_Extend # Mc [2] HANGUL SINGLE DOT TONE MARK..HANGUL DOUBLE DOT TONE MARK
FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
1133E ; Other_Grapheme_Extend # Mc GRANTHA VOWEL SIGN AA
11357 ; Other_Grapheme_Extend # Mc GRANTHA AU LENGTH MARK
114B0 ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN AA
114BD ; Other_Grapheme_Extend # Mc TIRHUTA VOWEL SIGN SHORT O
115AF ; Other_Grapheme_Extend # Mc SIDDHAM VOWEL SIGN AA
1D165 ; Other_Grapheme_Extend # Mc MUSICAL SYMBOL COMBINING STEM
1D16E..1D172 ; Other_Grapheme_Extend # Mc [5] MUSICAL SYMBOL COMBINING FLAG-1..MUSICAL SYMBOL COMBINING FLAG-5
# Total code points: 25
# Total code points: 30
# ================================================
@ -966,7 +1072,7 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C
034F ; Other_Default_Ignorable_Code_Point # Mn COMBINING GRAPHEME JOINER
115F..1160 ; Other_Default_Ignorable_Code_Point # Lo [2] HANGUL CHOSEONG FILLER..HANGUL JUNGSEONG FILLER
17B4..17B5 ; Other_Default_Ignorable_Code_Point # Mn [2] KHMER VOWEL INHERENT AQ..KHMER VOWEL INHERENT AA
2065..2069 ; Other_Default_Ignorable_Code_Point # Cn [5] <reserved-2065>..<reserved-2069>
2065 ; Other_Default_Ignorable_Code_Point # Cn <reserved-2065>
3164 ; Other_Default_Ignorable_Code_Point # Lo HANGUL FILLER
FFA0 ; Other_Default_Ignorable_Code_Point # Lo HALFWIDTH HANGUL FILLER
FFF0..FFF8 ; Other_Default_Ignorable_Code_Point # Cn [9] <reserved-FFF0>..<reserved-FFF8>
@ -975,7 +1081,7 @@ E0002..E001F ; Other_Default_Ignorable_Code_Point # Cn [30] <reserved-E0002>..
E0080..E00FF ; Other_Default_Ignorable_Code_Point # Cn [128] <reserved-E0080>..<reserved-E00FF>
E01F0..E0FFF ; Other_Default_Ignorable_Code_Point # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
# Total code points: 3780
# Total code points: 3776
# ================================================
@ -1060,8 +1166,6 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET
0021 ; STerm # Po EXCLAMATION MARK
002E ; STerm # Po FULL STOP
003F ; STerm # Po QUESTION MARK
055C ; STerm # Po ARMENIAN EXCLAMATION MARK
055E ; STerm # Po ARMENIAN QUESTION MARK
0589 ; STerm # Po ARMENIAN FULL STOP
061F ; STerm # Po ARABIC QUESTION MARK
06D4 ; STerm # Po ARABIC FULL STOP
@ -1084,6 +1188,7 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET
203C..203D ; STerm # Po [2] DOUBLE EXCLAMATION MARK..INTERROBANG
2047..2049 ; STerm # Po [3] DOUBLE QUESTION MARK..EXCLAMATION QUESTION MARK
2E2E ; STerm # Po REVERSED QUESTION MARK
2E3C ; STerm # Po STENOGRAPHIC FULL STOP
3002 ; STerm # Po IDEOGRAPHIC FULL STOP
A4FF ; STerm # Po LISU PUNCTUATION FULL STOP
A60E..A60F ; STerm # Po [2] VAI FULL STOP..VAI QUESTION MARK
@ -1107,8 +1212,19 @@ FF61 ; STerm # Po HALFWIDTH IDEOGRAPHIC FULL STOP
110BE..110C1 ; STerm # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; STerm # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
111C5..111C6 ; STerm # Po [2] SHARADA DANDA..SHARADA DOUBLE DANDA
111CD ; STerm # Po SHARADA SUTRA MARK
11238..11239 ; STerm # Po [2] KHOJKI DANDA..KHOJKI DOUBLE DANDA
1123B..1123C ; STerm # Po [2] KHOJKI SECTION MARK..KHOJKI DOUBLE SECTION MARK
115C2..115C3 ; STerm # Po [2] SIDDHAM DANDA..SIDDHAM DOUBLE DANDA
115C9 ; STerm # Po SIDDHAM END OF TEXT MARK
11641..11642 ; STerm # Po [2] MODI DANDA..MODI DOUBLE DANDA
16A6E..16A6F ; STerm # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; STerm # Po BASSA VAH FULL STOP
16B37..16B38 ; STerm # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB
16B44 ; STerm # Po PAHAWH HMONG SIGN XAUS
1BC9F ; STerm # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
# Total code points: 83
# Total code points: 99
# ================================================
@ -1210,7 +1326,10 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
21D5..21F3 ; Pattern_Syntax # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
21F4..22FF ; Pattern_Syntax # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
2300..2307 ; Pattern_Syntax # So [8] DIAMETER SIGN..WAVY LINE
2308..230B ; Pattern_Syntax # Sm [4] LEFT CEILING..RIGHT FLOOR
2308 ; Pattern_Syntax # Ps LEFT CEILING
2309 ; Pattern_Syntax # Pe RIGHT CEILING
230A ; Pattern_Syntax # Ps LEFT FLOOR
230B ; Pattern_Syntax # Pe RIGHT FLOOR
230C..231F ; Pattern_Syntax # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
2320..2321 ; Pattern_Syntax # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
2322..2328 ; Pattern_Syntax # So [7] FROWN..KEYBOARD
@ -1222,8 +1341,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
239B..23B3 ; Pattern_Syntax # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
23B4..23DB ; Pattern_Syntax # So [40] TOP SQUARE BRACKET..FUSE
23DC..23E1 ; Pattern_Syntax # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
23E2..23F3 ; Pattern_Syntax # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND
23F4..23FF ; Pattern_Syntax # Cn [12] <reserved-23F4>..<reserved-23FF>
23E2..23FA ; Pattern_Syntax # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD
23FB..23FF ; Pattern_Syntax # Cn [5] <reserved-23FB>..<reserved-23FF>
2400..2426 ; Pattern_Syntax # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
2427..243F ; Pattern_Syntax # Cn [25] <reserved-2427>..<reserved-243F>
2440..244A ; Pattern_Syntax # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
@ -1236,9 +1355,7 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
25F8..25FF ; Pattern_Syntax # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
2600..266E ; Pattern_Syntax # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
266F ; Pattern_Syntax # Sm MUSIC SHARP SIGN
2670..26FF ; Pattern_Syntax # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
2700 ; Pattern_Syntax # Cn <reserved-2700>
2701..2767 ; Pattern_Syntax # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET
2670..2767 ; Pattern_Syntax # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET
2768 ; Pattern_Syntax # Ps MEDIUM LEFT PARENTHESIS ORNAMENT
2769 ; Pattern_Syntax # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
276A ; Pattern_Syntax # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
@ -1306,9 +1423,16 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2B30..2B44 ; Pattern_Syntax # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
2B45..2B46 ; Pattern_Syntax # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
2B47..2B4C ; Pattern_Syntax # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
2B4D..2B4F ; Pattern_Syntax # Cn [3] <reserved-2B4D>..<reserved-2B4F>
2B50..2B59 ; Pattern_Syntax # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE
2B5A..2BFF ; Pattern_Syntax # Cn [166] <reserved-2B5A>..<reserved-2BFF>
2B4D..2B73 ; Pattern_Syntax # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
2B74..2B75 ; Pattern_Syntax # Cn [2] <reserved-2B74>..<reserved-2B75>
2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
2B96..2B97 ; Pattern_Syntax # Cn [2] <reserved-2B96>..<reserved-2B97>
2B98..2BB9 ; Pattern_Syntax # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX
2BBA..2BBC ; Pattern_Syntax # Cn [3] <reserved-2BBA>..<reserved-2BBC>
2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
2BC9 ; Pattern_Syntax # Cn <reserved-2BC9>
2BCA..2BD1 ; Pattern_Syntax # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN
2BD2..2BFF ; Pattern_Syntax # Cn [46] <reserved-2BD2>..<reserved-2BFF>
2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET
2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET
@ -1342,7 +1466,11 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2E2F ; Pattern_Syntax # Lm VERTICAL TILDE
2E30..2E39 ; Pattern_Syntax # Po [10] RING POINT..TOP HALF SECTION SIGN
2E3A..2E3B ; Pattern_Syntax # Pd [2] TWO-EM DASH..THREE-EM DASH
2E3C..2E7F ; Pattern_Syntax # Cn [68] <reserved-2E3C>..<reserved-2E7F>
2E3C..2E3F ; Pattern_Syntax # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM
2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN
2E41 ; Pattern_Syntax # Po REVERSED COMMA
2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
2E43..2E7F ; Pattern_Syntax # Cn [61] <reserved-2E43>..<reserved-2E7F>
3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET
3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET
@ -1368,8 +1496,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
301E..301F ; Pattern_Syntax # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK
3020 ; Pattern_Syntax # So POSTAL MARK FACE
3030 ; Pattern_Syntax # Pd WAVY DASH
FD3E ; Pattern_Syntax # Ps ORNATE LEFT PARENTHESIS
FD3F ; Pattern_Syntax # Pe ORNATE RIGHT PARENTHESIS
FD3E ; Pattern_Syntax # Pe ORNATE LEFT PARENTHESIS
FD3F ; Pattern_Syntax # Ps ORNATE RIGHT PARENTHESIS
FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT
# Total code points: 2760

View File

@ -1,8 +1,8 @@
# Scripts-6.2.0.txt
# Date: 2012-06-04, 17:21:29 GMT [MD]
# Scripts-7.0.0.txt
# Date: 2014-05-15, 00:11:35 GMT [MD]
#
# Unicode Character Database
# Copyright (c) 1991-2012 Unicode, Inc.
# Copyright (c) 1991-2014 Unicode, Inc.
# For terms of use, see http://www.unicode.org/terms_of_use.html
# For documentation, see http://www.unicode.org/reports/tr44/
@ -83,8 +83,10 @@
0385 ; Common # Sk GREEK DIALYTIKA TONOS
0387 ; Common # Po GREEK ANO TELEIA
0589 ; Common # Po ARMENIAN FULL STOP
0605 ; Common # Cf ARABIC NUMBER MARK ABOVE
060C ; Common # Po ARABIC COMMA
061B ; Common # Po ARABIC SEMICOLON
061C ; Common # Cf ARABIC LETTER MARK
061F ; Common # Po ARABIC QUESTION MARK
0640 ; Common # Lm ARABIC TATWEEL
0660..0669 ; Common # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE
@ -136,7 +138,7 @@
2055..205E ; Common # Po [10] FLOWER PUNCTUATION MARK..VERTICAL FOUR DOTS
205F ; Common # Zs MEDIUM MATHEMATICAL SPACE
2060..2064 ; Common # Cf [5] WORD JOINER..INVISIBLE PLUS
206A..206F ; Common # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES
2066..206F ; Common # Cf [10] LEFT-TO-RIGHT ISOLATE..NOMINAL DIGIT SHAPES
2070 ; Common # No SUPERSCRIPT ZERO
2074..2079 ; Common # No [6] SUPERSCRIPT FOUR..SUPERSCRIPT NINE
207A..207C ; Common # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN
@ -146,7 +148,7 @@
208A..208C ; Common # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN
208D ; Common # Ps SUBSCRIPT LEFT PARENTHESIS
208E ; Common # Pe SUBSCRIPT RIGHT PARENTHESIS
20A0..20BA ; Common # Sc [27] EURO-CURRENCY SIGN..TURKISH LIRA SIGN
20A0..20BD ; Common # Sc [30] EURO-CURRENCY SIGN..RUBLE SIGN
2100..2101 ; Common # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT
2102 ; Common # L& DOUBLE-STRUCK CAPITAL C
2103..2106 ; Common # So [4] DEGREE CELSIUS..CADA UNA
@ -200,7 +202,10 @@
21D5..21F3 ; Common # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW
21F4..22FF ; Common # Sm [268] RIGHT ARROW WITH SMALL CIRCLE..Z NOTATION BAG MEMBERSHIP
2300..2307 ; Common # So [8] DIAMETER SIGN..WAVY LINE
2308..230B ; Common # Sm [4] LEFT CEILING..RIGHT FLOOR
2308 ; Common # Ps LEFT CEILING
2309 ; Common # Pe RIGHT CEILING
230A ; Common # Ps LEFT FLOOR
230B ; Common # Pe RIGHT FLOOR
230C..231F ; Common # So [20] BOTTOM RIGHT CROP..BOTTOM RIGHT CORNER
2320..2321 ; Common # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL
2322..2328 ; Common # So [7] FROWN..KEYBOARD
@ -212,7 +217,7 @@
239B..23B3 ; Common # Sm [25] LEFT PARENTHESIS UPPER HOOK..SUMMATION BOTTOM
23B4..23DB ; Common # So [40] TOP SQUARE BRACKET..FUSE
23DC..23E1 ; Common # Sm [6] TOP PARENTHESIS..BOTTOM TORTOISE SHELL BRACKET
23E2..23F3 ; Common # So [18] WHITE TRAPEZIUM..HOURGLASS WITH FLOWING SAND
23E2..23FA ; Common # So [25] WHITE TRAPEZIUM..BLACK CIRCLE FOR RECORD
2400..2426 ; Common # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO
2440..244A ; Common # So [11] OCR HOOK..OCR DOUBLE BACKSLASH
2460..249B ; Common # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP
@ -226,8 +231,7 @@
25F8..25FF ; Common # Sm [8] UPPER LEFT TRIANGLE..LOWER RIGHT TRIANGLE
2600..266E ; Common # So [111] BLACK SUN WITH RAYS..MUSIC NATURAL SIGN
266F ; Common # Sm MUSIC SHARP SIGN
2670..26FF ; Common # So [144] WEST SYRIAC CROSS..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
2701..2767 ; Common # So [103] UPPER BLADE SCISSORS..ROTATED FLORAL HEART BULLET
2670..2767 ; Common # So [248] WEST SYRIAC CROSS..ROTATED FLORAL HEART BULLET
2768 ; Common # Ps MEDIUM LEFT PARENTHESIS ORNAMENT
2769 ; Common # Pe MEDIUM RIGHT PARENTHESIS ORNAMENT
276A ; Common # Ps MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT
@ -295,7 +299,11 @@
2B30..2B44 ; Common # Sm [21] LEFT ARROW WITH SMALL CIRCLE..RIGHTWARDS ARROW THROUGH SUPERSET
2B45..2B46 ; Common # So [2] LEFTWARDS QUADRUPLE ARROW..RIGHTWARDS QUADRUPLE ARROW
2B47..2B4C ; Common # Sm [6] REVERSE TILDE OPERATOR ABOVE RIGHTWARDS ARROW..RIGHTWARDS ARROW ABOVE REVERSE TILDE OPERATOR
2B50..2B59 ; Common # So [10] WHITE MEDIUM STAR..HEAVY CIRCLED SALTIRE
2B4D..2B73 ; Common # So [39] DOWNWARDS TRIANGLE-HEADED ZIGZAG ARROW..DOWNWARDS TRIANGLE-HEADED ARROW TO BAR
2B76..2B95 ; Common # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
2B98..2BB9 ; Common # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX
2BBD..2BC8 ; Common # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
2BCA..2BD1 ; Common # So [8] TOP HALF BLACK CIRCLE..UNCERTAINTY SIGN
2E00..2E01 ; Common # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
2E02 ; Common # Pi LEFT SUBSTITUTION BRACKET
2E03 ; Common # Pf RIGHT SUBSTITUTION BRACKET
@ -329,6 +337,10 @@
2E2F ; Common # Lm VERTICAL TILDE
2E30..2E39 ; Common # Po [10] RING POINT..TOP HALF SECTION SIGN
2E3A..2E3B ; Common # Pd [2] TWO-EM DASH..THREE-EM DASH
2E3C..2E3F ; Common # Po [4] STENOGRAPHIC FULL STOP..CAPITULUM
2E40 ; Common # Pd DOUBLE HYPHEN
2E41 ; Common # Po REVERSED COMMA
2E42 ; Common # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
2FF0..2FFB ; Common # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID
3000 ; Common # Zs IDEOGRAPHIC SPACE
3001..3003 ; Common # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
@ -392,9 +404,11 @@ A830..A835 ; Common # No [6] NORTH INDIC FRACTION ONE QUARTER..NORTH INDIC
A836..A837 ; Common # So [2] NORTH INDIC QUARTER MARK..NORTH INDIC PLACEHOLDER MARK
A838 ; Common # Sc NORTH INDIC RUPEE MARK
A839 ; Common # So NORTH INDIC QUANTITY MARK
FD3E ; Common # Ps ORNATE LEFT PARENTHESIS
FD3F ; Common # Pe ORNATE RIGHT PARENTHESIS
FDFD ; Common # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
A92E ; Common # Po KAYAH LI SIGN CWI
A9CF ; Common # Lm JAVANESE PANGRANGKEP
AB5B ; Common # Sk MODIFIER BREVE WITH INVERTED BREVE
FD3E ; Common # Pe ORNATE LEFT PARENTHESIS
FD3F ; Common # Ps ORNATE RIGHT PARENTHESIS
FE10..FE16 ; Common # Po [7] PRESENTATION FORM FOR VERTICAL COMMA..PRESENTATION FORM FOR VERTICAL QUESTION MARK
FE17 ; Common # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET
FE18 ; Common # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET
@ -487,6 +501,8 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR
10137..1013F ; Common # So [9] AEGEAN WEIGHT BASE UNIT..AEGEAN MEASURE THIRD SUBUNIT
10190..1019B ; Common # So [12] ROMAN SEXTANS SIGN..ROMAN CENTURIAL SIGN
101D0..101FC ; Common # So [45] PHAISTOS DISC SIGN PEDESTRIAN..PHAISTOS DISC SIGN WAVY BAND
102E1..102FB ; Common # No [27] COPTIC EPACT DIGIT ONE..COPTIC EPACT NUMBER NINE HUNDRED
1BCA0..1BCA3 ; Common # Cf [4] SHORTHAND FORMAT LETTER OVERLAP..SHORTHAND FORMAT UP STEP
1D000..1D0F5 ; Common # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO
1D100..1D126 ; Common # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2
1D129..1D164 ; Common # So [60] MUSICAL SYMBOL MULTIPLE MEASURE REST..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE
@ -543,10 +559,10 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR
1F000..1F02B ; Common # So [44] MAHJONG TILE EAST WIND..MAHJONG TILE BACK
1F030..1F093 ; Common # So [100] DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
1F0A0..1F0AE ; Common # So [15] PLAYING CARD BACK..PLAYING CARD KING OF SPADES
1F0B1..1F0BE ; Common # So [14] PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS
1F0B1..1F0BF ; Common # So [15] PLAYING CARD ACE OF HEARTS..PLAYING CARD RED JOKER
1F0C1..1F0CF ; Common # So [15] PLAYING CARD ACE OF DIAMONDS..PLAYING CARD BLACK JOKER
1F0D1..1F0DF ; Common # So [15] PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER
1F100..1F10A ; Common # No [11] DIGIT ZERO FULL STOP..DIGIT NINE COMMA
1F0D1..1F0F5 ; Common # So [37] PLAYING CARD ACE OF CLUBS..PLAYING CARD TRUMP-21
1F100..1F10C ; Common # No [13] DIGIT ZERO FULL STOP..DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ZERO
1F110..1F12E ; Common # So [31] PARENTHESIZED LATIN CAPITAL LETTER A..CIRCLED WZ
1F130..1F16B ; Common # So [60] SQUARED LATIN CAPITAL LETTER A..RAISED MD SIGN
1F170..1F19A ; Common # So [43] NEGATIVE SQUARED LATIN CAPITAL LETTER A..SQUARED VS
@ -555,28 +571,29 @@ FFFC..FFFD ; Common # So [2] OBJECT REPLACEMENT CHARACTER..REPLACEMENT CHAR
1F210..1F23A ; Common # So [43] SQUARED CJK UNIFIED IDEOGRAPH-624B..SQUARED CJK UNIFIED IDEOGRAPH-55B6
1F240..1F248 ; Common # So [9] TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-672C..TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
1F250..1F251 ; Common # So [2] CIRCLED IDEOGRAPH ADVANTAGE..CIRCLED IDEOGRAPH ACCEPT
1F300..1F320 ; Common # So [33] CYCLONE..SHOOTING STAR
1F330..1F335 ; Common # So [6] CHESTNUT..CACTUS
1F337..1F37C ; Common # So [70] TULIP..BABY BOTTLE
1F380..1F393 ; Common # So [20] RIBBON..GRADUATION CAP
1F3A0..1F3C4 ; Common # So [37] CAROUSEL HORSE..SURFER
1F3C6..1F3CA ; Common # So [5] TROPHY..SWIMMER
1F3E0..1F3F0 ; Common # So [17] HOUSE BUILDING..EUROPEAN CASTLE
1F400..1F43E ; Common # So [63] RAT..PAW PRINTS
1F440 ; Common # So EYES
1F442..1F4F7 ; Common # So [182] EAR..CAMERA
1F4F9..1F4FC ; Common # So [4] VIDEO CAMERA..VIDEOCASSETTE
1F500..1F53D ; Common # So [62] TWISTED RIGHTWARDS ARROWS..DOWN-POINTING SMALL RED TRIANGLE
1F540..1F543 ; Common # So [4] CIRCLED CROSS POMMEE..NOTCHED LEFT SEMICIRCLE WITH THREE DOTS
1F550..1F567 ; Common # So [24] CLOCK FACE ONE OCLOCK..CLOCK FACE TWELVE-THIRTY
1F5FB..1F640 ; Common # So [70] MOUNT FUJI..WEARY CAT FACE
1F645..1F64F ; Common # So [11] FACE WITH NO GOOD GESTURE..PERSON WITH FOLDED HANDS
1F680..1F6C5 ; Common # So [70] ROCKET..LEFT LUGGAGE
1F300..1F32C ; Common # So [45] CYCLONE..WIND BLOWING FACE
1F330..1F37D ; Common # So [78] CHESTNUT..FORK AND KNIFE WITH PLATE
1F380..1F3CE ; Common # So [79] RIBBON..RACING CAR
1F3D4..1F3F7 ; Common # So [36] SNOW CAPPED MOUNTAIN..LABEL
1F400..1F4FE ; Common # So [255] RAT..PORTABLE STEREO
1F500..1F54A ; Common # So [75] TWISTED RIGHTWARDS ARROWS..DOVE OF PEACE
1F550..1F579 ; Common # So [42] CLOCK FACE ONE OCLOCK..JOYSTICK
1F57B..1F5A3 ; Common # So [41] LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX
1F5A5..1F642 ; Common # So [158] DESKTOP COMPUTER..SLIGHTLY SMILING FACE
1F645..1F6CF ; Common # So [139] FACE WITH NO GOOD GESTURE..BED
1F6E0..1F6EC ; Common # So [13] HAMMER AND WRENCH..AIRPLANE ARRIVING
1F6F0..1F6F3 ; Common # So [4] SATELLITE..PASSENGER SHIP
1F700..1F773 ; Common # So [116] ALCHEMICAL SYMBOL FOR QUINTESSENCE..ALCHEMICAL SYMBOL FOR HALF OUNCE
1F780..1F7D4 ; Common # So [85] BLACK LEFT-POINTING ISOSCELES RIGHT TRIANGLE..HEAVY TWELVE POINTED PINWHEEL STAR
1F800..1F80B ; Common # So [12] LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD..DOWNWARDS ARROW WITH LARGE TRIANGLE ARROWHEAD
1F810..1F847 ; Common # So [56] LEFTWARDS ARROW WITH SMALL EQUILATERAL ARROWHEAD..DOWNWARDS HEAVY ARROW
1F850..1F859 ; Common # So [10] LEFTWARDS SANS-SERIF ARROW..UP DOWN SANS-SERIF ARROW
1F860..1F887 ; Common # So [40] WIDE-HEADED LEFTWARDS LIGHT BARB ARROW..WIDE-HEADED SOUTH WEST VERY HEAVY BARB ARROW
1F890..1F8AD ; Common # So [30] LEFTWARDS TRIANGLE ARROWHEAD..WHITE ARROW SHAFT WIDTH TWO THIRDS
E0001 ; Common # Cf LANGUAGE TAG
E0020..E007F ; Common # Cf [96] TAG SPACE..CANCEL TAG
# Total code points: 6413
# Total code points: 7129
# ================================================
@ -618,16 +635,20 @@ A722..A76F ; Latin # L& [78] LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF..LATIN
A770 ; Latin # Lm MODIFIER LETTER US
A771..A787 ; Latin # L& [23] LATIN SMALL LETTER DUM..LATIN SMALL LETTER INSULAR T
A78B..A78E ; Latin # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
A790..A793 ; Latin # L& [4] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER C WITH BAR
A7A0..A7AA ; Latin # L& [11] LATIN CAPITAL LETTER G WITH OBLIQUE STROKE..LATIN CAPITAL LETTER H WITH HOOK
A790..A7AD ; Latin # L& [30] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER L WITH BELT
A7B0..A7B1 ; Latin # L& [2] LATIN CAPITAL LETTER TURNED K..LATIN CAPITAL LETTER TURNED T
A7F7 ; Latin # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
A7F8..A7F9 ; Latin # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
A7FA ; Latin # L& LATIN LETTER SMALL CAPITAL TURNED M
A7FB..A7FF ; Latin # Lo [5] LATIN EPIGRAPHIC LETTER REVERSED F..LATIN EPIGRAPHIC LETTER ARCHAIC M
AB30..AB5A ; Latin # L& [43] LATIN SMALL LETTER BARRED ALPHA..LATIN SMALL LETTER Y WITH SHORT RIGHT LEG
AB5C..AB5F ; Latin # Lm [4] MODIFIER LETTER SMALL HENG..MODIFIER LETTER SMALL U WITH LEFT HOOK
AB64 ; Latin # L& LATIN SMALL LETTER INVERTED ALPHA
FB00..FB06 ; Latin # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST
FF21..FF3A ; Latin # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z
FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z
# Total code points: 1272
# Total code points: 1338
# ================================================
@ -636,6 +657,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN
0376..0377 ; Greek # L& [2] GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA..GREEK SMALL LETTER PAMPHYLIAN DIGAMMA
037A ; Greek # Lm GREEK YPOGEGRAMMENI
037B..037D ; Greek # L& [3] GREEK SMALL REVERSED LUNATE SIGMA SYMBOL..GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
037F ; Greek # L& GREEK CAPITAL LETTER YOT
0384 ; Greek # Sk GREEK TONOS
0386 ; Greek # L& GREEK CAPITAL LETTER ALPHA WITH TONOS
0388..038A ; Greek # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS
@ -675,15 +697,18 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN
1FF6..1FFC ; Greek # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
1FFD..1FFE ; Greek # Sk [2] GREEK OXIA..GREEK DASIA
2126 ; Greek # L& OHM SIGN
AB65 ; Greek # L& GREEK LETTER SMALL CAPITAL OMEGA
10140..10174 ; Greek # Nl [53] GREEK ACROPHONIC ATTIC ONE QUARTER..GREEK ACROPHONIC STRATIAN FIFTY MNAS
10175..10178 ; Greek # No [4] GREEK ONE HALF SIGN..GREEK THREE QUARTERS SIGN
10179..10189 ; Greek # So [17] GREEK YEAR SIGN..GREEK TRYBLION BASE SIGN
1018A ; Greek # No GREEK ZERO SIGN
1018A..1018B ; Greek # No [2] GREEK ZERO SIGN..GREEK ONE QUARTER SIGN
1018C ; Greek # So GREEK SINUSOID SIGN
101A0 ; Greek # So GREEK SYMBOL TAU RHO
1D200..1D241 ; Greek # So [66] GREEK VOCAL NOTATION SYMBOL-1..GREEK INSTRUMENTAL NOTATION SYMBOL-54
1D242..1D244 ; Greek # Mn [3] COMBINING GREEK MUSICAL TRISEME..COMBINING GREEK MUSICAL PENTASEME
1D245 ; Greek # So GREEK MUSICAL LEIMMA
# Total code points: 511
# Total code points: 516
# ================================================
@ -692,7 +717,7 @@ FF41..FF5A ; Latin # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN
0483..0484 ; Cyrillic # Mn [2] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PALATALIZATION
0487 ; Cyrillic # Mn COMBINING CYRILLIC POKRYTIE
0488..0489 ; Cyrillic # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN
048A..0527 ; Cyrillic # L& [158] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER SHHA WITH DESCENDER
048A..052F ; Cyrillic # L& [166] CYRILLIC CAPITAL LETTER SHORT I WITH TAIL..CYRILLIC SMALL LETTER EL WITH DESCENDER
1D2B ; Cyrillic # L& CYRILLIC LETTER SMALL CAPITAL EL
1D78 ; Cyrillic # Lm MODIFIER LETTER CYRILLIC EN
2DE0..2DFF ; Cyrillic # Mn [32] COMBINING CYRILLIC LETTER BE..COMBINING CYRILLIC LETTER IOTIFIED BIG YUS
@ -704,10 +729,11 @@ A673 ; Cyrillic # Po SLAVONIC ASTERISK
A674..A67D ; Cyrillic # Mn [10] COMBINING CYRILLIC LETTER UKRAINIAN IE..COMBINING CYRILLIC PAYEROK
A67E ; Cyrillic # Po CYRILLIC KAVYKA
A67F ; Cyrillic # Lm CYRILLIC PAYEROK
A680..A697 ; Cyrillic # L& [24] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER SHWE
A680..A69B ; Cyrillic # L& [28] CYRILLIC CAPITAL LETTER DWE..CYRILLIC SMALL LETTER CROSSED O
A69C..A69D ; Cyrillic # Lm [2] MODIFIER LETTER CYRILLIC HARD SIGN..MODIFIER LETTER CYRILLIC SOFT SIGN
A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E
# Total code points: 417
# Total code points: 431
# ================================================
@ -716,10 +742,11 @@ A69F ; Cyrillic # Mn COMBINING CYRILLIC LETTER IOTIFIED E
055A..055F ; Armenian # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK
0561..0587 ; Armenian # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN
058A ; Armenian # Pd ARMENIAN HYPHEN
058D..058E ; Armenian # So [2] RIGHT-FACING ARMENIAN ETERNITY SIGN..LEFT-FACING ARMENIAN ETERNITY SIGN
058F ; Armenian # Sc ARMENIAN DRAM SIGN
FB13..FB17 ; Armenian # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH
# Total code points: 91
# Total code points: 93
# ================================================
@ -779,9 +806,8 @@ FB46..FB4F ; Hebrew # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW LIGATU
06FD..06FE ; Arabic # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN
06FF ; Arabic # Lo ARABIC LETTER HEH WITH INVERTED V
0750..077F ; Arabic # Lo [48] ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS ABOVE
08A0 ; Arabic # Lo ARABIC LETTER BEH WITH SMALL V BELOW
08A2..08AC ; Arabic # Lo [11] ARABIC LETTER JEEM WITH TWO DOTS ABOVE..ARABIC LETTER ROHINGYA YEH
08E4..08FE ; Arabic # Mn [27] ARABIC CURLY FATHA..ARABIC DAMMA WITH DOT
08A0..08B2 ; Arabic # Lo [19] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER ZAIN WITH INVERTED V ABOVE
08E4..08FF ; Arabic # Mn [28] ARABIC CURLY FATHA..ARABIC MARK SIDEWAYS NOON GHUNNA
FB50..FBB1 ; Arabic # Lo [98] ARABIC LETTER ALEF WASLA ISOLATED FORM..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM
FBB2..FBC1 ; Arabic # Sk [16] ARABIC SYMBOL DOT ABOVE..ARABIC SYMBOL SMALL TAH BELOW
FBD3..FD3D ; Arabic # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM
@ -789,6 +815,7 @@ FD50..FD8F ; Arabic # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIA
FD92..FDC7 ; Arabic # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM
FDF0..FDFB ; Arabic # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU
FDFC ; Arabic # Sc RIAL SIGN
FDFD ; Arabic # So ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM
FE70..FE74 ; Arabic # Lo [5] ARABIC FATHATAN ISOLATED FORM..ARABIC KASRATAN ISOLATED FORM
FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM
10E60..10E7E ; Arabic # No [31] RUMI DIGIT ONE..RUMI FRACTION TWO THIRDS
@ -827,7 +854,7 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA
1EEAB..1EEBB ; Arabic # Lo [17] ARABIC MATHEMATICAL DOUBLE-STRUCK LAM..ARABIC MATHEMATICAL DOUBLE-STRUCK GHAIN
1EEF0..1EEF1 ; Arabic # Sm [2] ARABIC MATHEMATICAL OPERATOR MEEM WITH HAH WITH TATWEEL..ARABIC MATHEMATICAL OPERATOR HAH WITH DAL
# Total code points: 1235
# Total code points: 1244
# ================================================
@ -870,17 +897,17 @@ FE76..FEFC ; Arabic # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LA
0966..096F ; Devanagari # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE
0970 ; Devanagari # Po DEVANAGARI ABBREVIATION SIGN
0971 ; Devanagari # Lm DEVANAGARI SIGN HIGH SPACING DOT
0972..0977 ; Devanagari # Lo [6] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER UUE
0979..097F ; Devanagari # Lo [7] DEVANAGARI LETTER ZHA..DEVANAGARI LETTER BBA
0972..097F ; Devanagari # Lo [14] DEVANAGARI LETTER CANDRA A..DEVANAGARI LETTER BBA
A8E0..A8F1 ; Devanagari # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
A8F2..A8F7 ; Devanagari # Lo [6] DEVANAGARI SIGN SPACING CANDRABINDU..DEVANAGARI SIGN CANDRABINDU AVAGRAHA
A8F8..A8FA ; Devanagari # Po [3] DEVANAGARI SIGN PUSHPIKA..DEVANAGARI CARET
A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
# Total code points: 151
# Total code points: 152
# ================================================
0980 ; Bengali # Lo BENGALI ANJI
0981 ; Bengali # Mn BENGALI SIGN CANDRABINDU
0982..0983 ; Bengali # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA
0985..098C ; Bengali # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L
@ -908,7 +935,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
09FA ; Bengali # So BENGALI ISSHAR
09FB ; Bengali # Sc BENGALI GANDA MARK
# Total code points: 92
# Total code points: 93
# ================================================
@ -1025,12 +1052,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
# ================================================
0C00 ; Telugu # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
0C01..0C03 ; Telugu # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA
0C05..0C0C ; Telugu # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L
0C0E..0C10 ; Telugu # Lo [3] TELUGU LETTER E..TELUGU LETTER AI
0C12..0C28 ; Telugu # Lo [23] TELUGU LETTER O..TELUGU LETTER NA
0C2A..0C33 ; Telugu # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA
0C35..0C39 ; Telugu # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA
0C2A..0C39 ; Telugu # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
0C3D ; Telugu # Lo TELUGU SIGN AVAGRAHA
0C3E..0C40 ; Telugu # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
0C41..0C44 ; Telugu # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR
@ -1044,10 +1071,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
0C78..0C7E ; Telugu # No [7] TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR..TELUGU FRACTION DIGIT THREE FOR EVEN POWERS OF FOUR
0C7F ; Telugu # So TELUGU SIGN TUUMU
# Total code points: 93
# Total code points: 95
# ================================================
0C81 ; Kannada # Mn KANNADA SIGN CANDRABINDU
0C82..0C83 ; Kannada # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA
0C85..0C8C ; Kannada # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
0C8E..0C90 ; Kannada # Lo [3] KANNADA LETTER E..KANNADA LETTER AI
@ -1070,10 +1098,11 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
0CE6..0CEF ; Kannada # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE
0CF1..0CF2 ; Kannada # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
# Total code points: 86
# Total code points: 87
# ================================================
0D01 ; Malayalam # Mn MALAYALAM SIGN CANDRABINDU
0D02..0D03 ; Malayalam # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA
0D05..0D0C ; Malayalam # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L
0D0E..0D10 ; Malayalam # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI
@ -1093,7 +1122,7 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
0D79 ; Malayalam # So MALAYALAM DATE MARK
0D7A..0D7F ; Malayalam # Lo [6] MALAYALAM LETTER CHILLU NN..MALAYALAM LETTER CHILLU K
# Total code points: 98
# Total code points: 99
# ================================================
@ -1108,10 +1137,12 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
0DD2..0DD4 ; Sinhala # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA
0DD6 ; Sinhala # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA
0DD8..0DDF ; Sinhala # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA
0DE6..0DEF ; Sinhala # Nd [10] SINHALA LITH DIGIT ZERO..SINHALA LITH DIGIT NINE
0DF2..0DF3 ; Sinhala # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA
0DF4 ; Sinhala # Po SINHALA PUNCTUATION KUNDDALIYA
111E1..111F4 ; Sinhala # No [20] SINHALA ARCHAIC DIGIT ONE..SINHALA ARCHAIC NUMBER ONE THOUSAND
# Total code points: 80
# Total code points: 110
# ================================================
@ -1234,14 +1265,23 @@ A8FB ; Devanagari # Lo DEVANAGARI HEADSTROKE
109A..109C ; Myanmar # Mc [3] MYANMAR SIGN KHAMTI TONE-1..MYANMAR VOWEL SIGN AITON A
109D ; Myanmar # Mn MYANMAR VOWEL SIGN AITON AI
109E..109F ; Myanmar # So [2] MYANMAR SYMBOL SHAN ONE..MYANMAR SYMBOL SHAN EXCLAMATION
A9E0..A9E4 ; Myanmar # Lo [5] MYANMAR LETTER SHAN GHA..MYANMAR LETTER SHAN BHA
A9E5 ; Myanmar # Mn MYANMAR SIGN SHAN SAW
A9E6 ; Myanmar # Lm MYANMAR MODIFIER LETTER SHAN REDUPLICATION
A9E7..A9EF ; Myanmar # Lo [9] MYANMAR LETTER TAI LAING NYA..MYANMAR LETTER TAI LAING NNA
A9F0..A9F9 ; Myanmar # Nd [10] MYANMAR TAI LAING DIGIT ZERO..MYANMAR TAI LAING DIGIT NINE
A9FA..A9FE ; Myanmar # Lo [5] MYANMAR LETTER TAI LAING LLA..MYANMAR LETTER TAI LAING BHA
AA60..AA6F ; Myanmar # Lo [16] MYANMAR LETTER KHAMTI GA..MYANMAR LETTER KHAMTI FA
AA70 ; Myanmar # Lm MYANMAR MODIFIER LETTER KHAMTI REDUPLICATION
AA71..AA76 ; Myanmar # Lo [6] MYANMAR LETTER KHAMTI XA..MYANMAR LOGOGRAM KHAMTI HM
AA77..AA79 ; Myanmar # So [3] MYANMAR SYMBOL AITON EXCLAMATION..MYANMAR SYMBOL AITON TWO
AA7A ; Myanmar # Lo MYANMAR LETTER AITON RA
AA7B ; Myanmar # Mc MYANMAR SIGN PAO KAREN TONE
AA7C ; Myanmar # Mn MYANMAR SIGN TAI LAING TONE-2
AA7D ; Myanmar # Mc MYANMAR SIGN TAI LAING TONE-5
AA7E..AA7F ; Myanmar # Lo [2] MYANMAR LETTER SHWE PALAUNG CHA..MYANMAR LETTER SHWE PALAUNG SHA
# Total code points: 188
# Total code points: 223
# ================================================
@ -1345,8 +1385,9 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
16A0..16EA ; Runic # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X
16EE..16F0 ; Runic # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL
16F1..16F8 ; Runic # Lo [8] RUNIC LETTER K..RUNIC LETTER FRANKS CASKET AESC
# Total code points: 78
# Total code points: 86
# ================================================
@ -1377,7 +1418,7 @@ AB28..AB2E ; Ethiopic # Lo [7] ETHIOPIC SYLLABLE BBA..ETHIOPIC SYLLABLE BBO
1806 ; Mongolian # Pd MONGOLIAN TODO SOFT HYPHEN
1807..180A ; Mongolian # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU
180B..180D ; Mongolian # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE
180E ; Mongolian # Zs MONGOLIAN VOWEL SEPARATOR
180E ; Mongolian # Cf MONGOLIAN VOWEL SEPARATOR
1810..1819 ; Mongolian # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE
1820..1842 ; Mongolian # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI
1843 ; Mongolian # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN
@ -1452,10 +1493,10 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE
# ================================================
10300..1031E ; Old_Italic # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU
10300..1031F ; Old_Italic # Lo [32] OLD ITALIC LETTER A..OLD ITALIC LETTER ESS
10320..10323 ; Old_Italic # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY
# Total code points: 35
# Total code points: 36
# ================================================
@ -1479,12 +1520,15 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE
064B..0655 ; Inherited # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW
0670 ; Inherited # Mn ARABIC LETTER SUPERSCRIPT ALEF
0951..0952 ; Inherited # Mn [2] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI STRESS SIGN ANUDATTA
1AB0..1ABD ; Inherited # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
1ABE ; Inherited # Me COMBINING PARENTHESES OVERLAY
1CD0..1CD2 ; Inherited # Mn [3] VEDIC TONE KARSHANA..VEDIC TONE PRENKHA
1CD4..1CE0 ; Inherited # Mn [13] VEDIC SIGN YAJURVEDIC MIDLINE SVARITA..VEDIC TONE RIGVEDIC KASHMIRI INDEPENDENT SVARITA
1CE2..1CE8 ; Inherited # Mn [7] VEDIC SIGN VISARGA SVARITA..VEDIC SIGN VISARGA ANUDATTA WITH TAIL
1CED ; Inherited # Mn VEDIC SIGN TIRYAK
1CF4 ; Inherited # Mn VEDIC TONE CANDRA ABOVE
1DC0..1DE6 ; Inherited # Mn [39] COMBINING DOTTED GRAVE ACCENT..COMBINING LATIN SMALL LETTER Z
1CF8..1CF9 ; Inherited # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
1DC0..1DF5 ; Inherited # Mn [54] COMBINING DOTTED GRAVE ACCENT..COMBINING UP TACK ABOVE
1DFC..1DFF ; Inherited # Mn [4] COMBINING DOUBLE INVERTED BREVE BELOW..COMBINING RIGHT ARROWHEAD AND DOWN ARROWHEAD BELOW
200C..200D ; Inherited # Cf [2] ZERO WIDTH NON-JOINER..ZERO WIDTH JOINER
20D0..20DC ; Inherited # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE
@ -1495,15 +1539,16 @@ A490..A4C6 ; Yi # So [55] YI RADICAL QOT..YI RADICAL KE
302A..302D ; Inherited # Mn [4] IDEOGRAPHIC LEVEL TONE MARK..IDEOGRAPHIC ENTERING TONE MARK
3099..309A ; Inherited # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
FE00..FE0F ; Inherited # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16
FE20..FE26 ; Inherited # Mn [7] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON
FE20..FE2D ; Inherited # Mn [14] COMBINING LIGATURE LEFT HALF..COMBINING CONJOINING MACRON BELOW
101FD ; Inherited # Mn PHAISTOS DISC SIGN COMBINING OBLIQUE STROKE
102E0 ; Inherited # Mn COPTIC EPACT THOUSANDS MARK
1D167..1D169 ; Inherited # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3
1D17B..1D182 ; Inherited # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE
1D185..1D18B ; Inherited # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE
1D1AA..1D1AD ; Inherited # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO
E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
# Total code points: 523
# Total code points: 563
# ================================================
@ -1537,7 +1582,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2
# ================================================
1900..191C ; Limbu # Lo [29] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER HA
1900..191E ; Limbu # Lo [31] LIMBU VOWEL-CARRIER LETTER..LIMBU LETTER TRA
1920..1922 ; Limbu # Mn [3] LIMBU VOWEL SIGN A..LIMBU VOWEL SIGN U
1923..1926 ; Limbu # Mc [4] LIMBU VOWEL SIGN EE..LIMBU VOWEL SIGN AU
1927..1928 ; Limbu # Mn [2] LIMBU VOWEL SIGN E..LIMBU VOWEL SIGN O
@ -1550,7 +1595,7 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2
1944..1945 ; Limbu # Po [2] LIMBU EXCLAMATION MARK..LIMBU QUESTION MARK
1946..194F ; Limbu # Nd [10] LIMBU DIGIT ZERO..LIMBU DIGIT NINE
# Total code points: 66
# Total code points: 68
# ================================================
@ -1612,7 +1657,8 @@ E0100..E01EF ; Inherited # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-2
1A00..1A16 ; Buginese # Lo [23] BUGINESE LETTER KA..BUGINESE LETTER HA
1A17..1A18 ; Buginese # Mn [2] BUGINESE VOWEL SIGN I..BUGINESE VOWEL SIGN U
1A19..1A1B ; Buginese # Mc [3] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN AE
1A19..1A1A ; Buginese # Mc [2] BUGINESE VOWEL SIGN E..BUGINESE VOWEL SIGN O
1A1B ; Buginese # Mn BUGINESE VOWEL SIGN AE
1A1E..1A1F ; Buginese # Po [2] BUGINESE PALLAWA..BUGINESE END OF SECTION
# Total code points: 30
@ -1724,11 +1770,11 @@ A828..A82B ; Syloti_Nagri # So [4] SYLOTI NAGRI POETRY MARK-1..SYLOTI NAGRI
# ================================================
12000..1236E ; Cuneiform # Lo [879] CUNEIFORM SIGN A..CUNEIFORM SIGN ZUM
12400..12462 ; Cuneiform # Nl [99] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN OLD ASSYRIAN ONE QUARTER
12470..12473 ; Cuneiform # Po [4] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON
12000..12398 ; Cuneiform # Lo [921] CUNEIFORM SIGN A..CUNEIFORM SIGN UM TIMES ME
12400..1246E ; Cuneiform # Nl [111] CUNEIFORM NUMERIC SIGN TWO ASH..CUNEIFORM NUMERIC SIGN NINE U VARIANT FORM
12470..12474 ; Cuneiform # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
# Total code points: 982
# Total code points: 1037
# ================================================
@ -1767,8 +1813,7 @@ A874..A877 ; Phags_Pa # Po [4] PHAGS-PA SINGLE HEAD MARK..PHAGS-PA MARK DOU
1BA6..1BA7 ; Sundanese # Mc [2] SUNDANESE VOWEL SIGN PANAELAENG..SUNDANESE VOWEL SIGN PANOLONG
1BA8..1BA9 ; Sundanese # Mn [2] SUNDANESE VOWEL SIGN PAMEPET..SUNDANESE VOWEL SIGN PANEULEUNG
1BAA ; Sundanese # Mc SUNDANESE SIGN PAMAAEH
1BAB ; Sundanese # Mn SUNDANESE SIGN VIRAMA
1BAC..1BAD ; Sundanese # Mc [2] SUNDANESE CONSONANT SIGN PASANGAN MA..SUNDANESE CONSONANT SIGN PASANGAN WA
1BAB..1BAD ; Sundanese # Mn [3] SUNDANESE SIGN VIRAMA..SUNDANESE CONSONANT SIGN PASANGAN WA
1BAE..1BAF ; Sundanese # Lo [2] SUNDANESE LETTER KHA..SUNDANESE LETTER SYA
1BB0..1BB9 ; Sundanese # Nd [10] SUNDANESE DIGIT ZERO..SUNDANESE DIGIT NINE
1BBA..1BBF ; Sundanese # Lo [6] SUNDANESE AVAGRAHA..SUNDANESE LETTER FINAL M
@ -1825,9 +1870,9 @@ A8D0..A8D9 ; Saurashtra # Nd [10] SAURASHTRA DIGIT ZERO..SAURASHTRA DIGIT NI
A900..A909 ; Kayah_Li # Nd [10] KAYAH LI DIGIT ZERO..KAYAH LI DIGIT NINE
A90A..A925 ; Kayah_Li # Lo [28] KAYAH LI LETTER KA..KAYAH LI LETTER OO
A926..A92D ; Kayah_Li # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
A92E..A92F ; Kayah_Li # Po [2] KAYAH LI SIGN CWI..KAYAH LI SIGN SHYA
A92F ; Kayah_Li # Po KAYAH LI SIGN SHYA
# Total code points: 48
# Total code points: 47
# ================================================
@ -1974,11 +2019,10 @@ A9BA..A9BB ; Javanese # Mc [2] JAVANESE VOWEL SIGN TALING..JAVANESE VOWEL S
A9BC ; Javanese # Mn JAVANESE VOWEL SIGN PEPET
A9BD..A9C0 ; Javanese # Mc [4] JAVANESE CONSONANT SIGN KERET..JAVANESE PANGKON
A9C1..A9CD ; Javanese # Po [13] JAVANESE LEFT RERENGGAN..JAVANESE TURNED PADA PISELEH
A9CF ; Javanese # Lm JAVANESE PANGRANGKEP
A9D0..A9D9 ; Javanese # Nd [10] JAVANESE DIGIT ZERO..JAVANESE DIGIT NINE
A9DE..A9DF ; Javanese # Po [2] JAVANESE PADA TIRTA TUMETES..JAVANESE PADA ISEN-ISEN
# Total code points: 91
# Total code points: 90
# ================================================
@ -2080,8 +2124,9 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI
11047..1104D ; Brahmi # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
11052..11065 ; Brahmi # No [20] BRAHMI NUMBER ONE..BRAHMI NUMBER ONE THOUSAND
11066..1106F ; Brahmi # Nd [10] BRAHMI DIGIT ZERO..BRAHMI DIGIT NINE
1107F ; Brahmi # Mn BRAHMI NUMBER JOINER
# Total code points: 108
# Total code points: 109
# ================================================
@ -2136,9 +2181,11 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI
111BF..111C0 ; Sharada # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
111C1..111C4 ; Sharada # Lo [4] SHARADA SIGN AVAGRAHA..SHARADA OM
111C5..111C8 ; Sharada # Po [4] SHARADA DANDA..SHARADA SEPARATOR
111CD ; Sharada # Po SHARADA SUTRA MARK
111D0..111D9 ; Sharada # Nd [10] SHARADA DIGIT ZERO..SHARADA DIGIT NINE
111DA ; Sharada # Lo SHARADA EKAM
# Total code points: 83
# Total code points: 85
# ================================================
@ -2161,4 +2208,244 @@ ABF0..ABF9 ; Meetei_Mayek # Nd [10] MEETEI MAYEK DIGIT ZERO..MEETEI MAYEK DI
# Total code points: 66
# ================================================
10530..10563 ; Caucasian_Albanian # Lo [52] CAUCASIAN ALBANIAN LETTER ALT..CAUCASIAN ALBANIAN LETTER KIW
1056F ; Caucasian_Albanian # Po CAUCASIAN ALBANIAN CITATION MARK
# Total code points: 53
# ================================================
16AD0..16AED ; Bassa_Vah # Lo [30] BASSA VAH LETTER ENNI..BASSA VAH LETTER I
16AF0..16AF4 ; Bassa_Vah # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16AF5 ; Bassa_Vah # Po BASSA VAH FULL STOP
# Total code points: 36
# ================================================
1BC00..1BC6A ; Duployan # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M
1BC70..1BC7C ; Duployan # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK
1BC80..1BC88 ; Duployan # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL
1BC90..1BC99 ; Duployan # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW
1BC9C ; Duployan # So DUPLOYAN SIGN O WITH CROSS
1BC9D..1BC9E ; Duployan # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
1BC9F ; Duployan # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
# Total code points: 143
# ================================================
10500..10527 ; Elbasan # Lo [40] ELBASAN LETTER A..ELBASAN LETTER KHE
# Total code points: 40
# ================================================
11301 ; Grantha # Mn GRANTHA SIGN CANDRABINDU
11302..11303 ; Grantha # Mc [2] GRANTHA SIGN ANUSVARA..GRANTHA SIGN VISARGA
11305..1130C ; Grantha # Lo [8] GRANTHA LETTER A..GRANTHA LETTER VOCALIC L
1130F..11310 ; Grantha # Lo [2] GRANTHA LETTER EE..GRANTHA LETTER AI
11313..11328 ; Grantha # Lo [22] GRANTHA LETTER OO..GRANTHA LETTER NA
1132A..11330 ; Grantha # Lo [7] GRANTHA LETTER PA..GRANTHA LETTER RA
11332..11333 ; Grantha # Lo [2] GRANTHA LETTER LA..GRANTHA LETTER LLA
11335..11339 ; Grantha # Lo [5] GRANTHA LETTER VA..GRANTHA LETTER HA
1133C ; Grantha # Mn GRANTHA SIGN NUKTA
1133D ; Grantha # Lo GRANTHA SIGN AVAGRAHA
1133E..1133F ; Grantha # Mc [2] GRANTHA VOWEL SIGN AA..GRANTHA VOWEL SIGN I
11340 ; Grantha # Mn GRANTHA VOWEL SIGN II
11341..11344 ; Grantha # Mc [4] GRANTHA VOWEL SIGN U..GRANTHA VOWEL SIGN VOCALIC RR
11347..11348 ; Grantha # Mc [2] GRANTHA VOWEL SIGN EE..GRANTHA VOWEL SIGN AI
1134B..1134D ; Grantha # Mc [3] GRANTHA VOWEL SIGN OO..GRANTHA SIGN VIRAMA
11357 ; Grantha # Mc GRANTHA AU LENGTH MARK
1135D..11361 ; Grantha # Lo [5] GRANTHA SIGN PLUTA..GRANTHA LETTER VOCALIC LL
11362..11363 ; Grantha # Mc [2] GRANTHA VOWEL SIGN VOCALIC L..GRANTHA VOWEL SIGN VOCALIC LL
11366..1136C ; Grantha # Mn [7] COMBINING GRANTHA DIGIT ZERO..COMBINING GRANTHA DIGIT SIX
11370..11374 ; Grantha # Mn [5] COMBINING GRANTHA LETTER A..COMBINING GRANTHA LETTER PA
# Total code points: 83
# ================================================
16B00..16B2F ; Pahawh_Hmong # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
16B30..16B36 ; Pahawh_Hmong # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16B37..16B3B ; Pahawh_Hmong # Po [5] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS FEEM
16B3C..16B3F ; Pahawh_Hmong # So [4] PAHAWH HMONG SIGN XYEEM NTXIV..PAHAWH HMONG SIGN XYEEM FAIB
16B40..16B43 ; Pahawh_Hmong # Lm [4] PAHAWH HMONG SIGN VOS SEEV..PAHAWH HMONG SIGN IB YAM
16B44 ; Pahawh_Hmong # Po PAHAWH HMONG SIGN XAUS
16B45 ; Pahawh_Hmong # So PAHAWH HMONG SIGN CIM TSOV ROG
16B50..16B59 ; Pahawh_Hmong # Nd [10] PAHAWH HMONG DIGIT ZERO..PAHAWH HMONG DIGIT NINE
16B5B..16B61 ; Pahawh_Hmong # No [7] PAHAWH HMONG NUMBER TENS..PAHAWH HMONG NUMBER TRILLIONS
16B63..16B77 ; Pahawh_Hmong # Lo [21] PAHAWH HMONG SIGN VOS LUB..PAHAWH HMONG SIGN CIM NRES TOS
16B7D..16B8F ; Pahawh_Hmong # Lo [19] PAHAWH HMONG CLAN SIGN TSHEEJ..PAHAWH HMONG CLAN SIGN VWJ
# Total code points: 127
# ================================================
11200..11211 ; Khojki # Lo [18] KHOJKI LETTER A..KHOJKI LETTER JJA
11213..1122B ; Khojki # Lo [25] KHOJKI LETTER NYA..KHOJKI LETTER LLA
1122C..1122E ; Khojki # Mc [3] KHOJKI VOWEL SIGN AA..KHOJKI VOWEL SIGN II
1122F..11231 ; Khojki # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
11232..11233 ; Khojki # Mc [2] KHOJKI VOWEL SIGN O..KHOJKI VOWEL SIGN AU
11234 ; Khojki # Mn KHOJKI SIGN ANUSVARA
11235 ; Khojki # Mc KHOJKI SIGN VIRAMA
11236..11237 ; Khojki # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
11238..1123D ; Khojki # Po [6] KHOJKI DANDA..KHOJKI ABBREVIATION SIGN
# Total code points: 61
# ================================================
10600..10736 ; Linear_A # Lo [311] LINEAR A SIGN AB001..LINEAR A SIGN A664
10740..10755 ; Linear_A # Lo [22] LINEAR A SIGN A701 A..LINEAR A SIGN A732 JE
10760..10767 ; Linear_A # Lo [8] LINEAR A SIGN A800..LINEAR A SIGN A807
# Total code points: 341
# ================================================
11150..11172 ; Mahajani # Lo [35] MAHAJANI LETTER A..MAHAJANI LETTER RRA
11173 ; Mahajani # Mn MAHAJANI SIGN NUKTA
11174..11175 ; Mahajani # Po [2] MAHAJANI ABBREVIATION SIGN..MAHAJANI SECTION MARK
11176 ; Mahajani # Lo MAHAJANI LIGATURE SHRI
# Total code points: 39
# ================================================
10AC0..10AC7 ; Manichaean # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW
10AC8 ; Manichaean # So MANICHAEAN SIGN UD
10AC9..10AE4 ; Manichaean # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW
10AE5..10AE6 ; Manichaean # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
10AEB..10AEF ; Manichaean # No [5] MANICHAEAN NUMBER ONE..MANICHAEAN NUMBER ONE HUNDRED
10AF0..10AF6 ; Manichaean # Po [7] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION LINE FILLER
# Total code points: 51
# ================================================
1E800..1E8C4 ; Mende_Kikakui # Lo [197] MENDE KIKAKUI SYLLABLE M001 KI..MENDE KIKAKUI SYLLABLE M060 NYON
1E8C7..1E8CF ; Mende_Kikakui # No [9] MENDE KIKAKUI DIGIT ONE..MENDE KIKAKUI DIGIT NINE
1E8D0..1E8D6 ; Mende_Kikakui # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
# Total code points: 213
# ================================================
11600..1162F ; Modi # Lo [48] MODI LETTER A..MODI LETTER LLA
11630..11632 ; Modi # Mc [3] MODI VOWEL SIGN AA..MODI VOWEL SIGN II
11633..1163A ; Modi # Mn [8] MODI VOWEL SIGN U..MODI VOWEL SIGN AI
1163B..1163C ; Modi # Mc [2] MODI VOWEL SIGN O..MODI VOWEL SIGN AU
1163D ; Modi # Mn MODI SIGN ANUSVARA
1163E ; Modi # Mc MODI SIGN VISARGA
1163F..11640 ; Modi # Mn [2] MODI SIGN VIRAMA..MODI SIGN ARDHACANDRA
11641..11643 ; Modi # Po [3] MODI DANDA..MODI ABBREVIATION SIGN
11644 ; Modi # Lo MODI SIGN HUVA
11650..11659 ; Modi # Nd [10] MODI DIGIT ZERO..MODI DIGIT NINE
# Total code points: 79
# ================================================
16A40..16A5E ; Mro # Lo [31] MRO LETTER TA..MRO LETTER TEK
16A60..16A69 ; Mro # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
16A6E..16A6F ; Mro # Po [2] MRO DANDA..MRO DOUBLE DANDA
# Total code points: 43
# ================================================
10A80..10A9C ; Old_North_Arabian # Lo [29] OLD NORTH ARABIAN LETTER HEH..OLD NORTH ARABIAN LETTER ZAH
10A9D..10A9F ; Old_North_Arabian # No [3] OLD NORTH ARABIAN NUMBER ONE..OLD NORTH ARABIAN NUMBER TWENTY
# Total code points: 32
# ================================================
10880..1089E ; Nabataean # Lo [31] NABATAEAN LETTER FINAL ALEPH..NABATAEAN LETTER TAW
108A7..108AF ; Nabataean # No [9] NABATAEAN NUMBER ONE..NABATAEAN NUMBER ONE HUNDRED
# Total code points: 40
# ================================================
10860..10876 ; Palmyrene # Lo [23] PALMYRENE LETTER ALEPH..PALMYRENE LETTER TAW
10877..10878 ; Palmyrene # So [2] PALMYRENE LEFT-POINTING FLEURON..PALMYRENE RIGHT-POINTING FLEURON
10879..1087F ; Palmyrene # No [7] PALMYRENE NUMBER ONE..PALMYRENE NUMBER TWENTY
# Total code points: 32
# ================================================
11AC0..11AF8 ; Pau_Cin_Hau # Lo [57] PAU CIN HAU LETTER PA..PAU CIN HAU GLOTTAL STOP FINAL
# Total code points: 57
# ================================================
10350..10375 ; Old_Permic # Lo [38] OLD PERMIC LETTER AN..OLD PERMIC LETTER IA
10376..1037A ; Old_Permic # Mn [5] COMBINING OLD PERMIC LETTER AN..COMBINING OLD PERMIC LETTER SII
# Total code points: 43
# ================================================
10B80..10B91 ; Psalter_Pahlavi # Lo [18] PSALTER PAHLAVI LETTER ALEPH..PSALTER PAHLAVI LETTER TAW
10B99..10B9C ; Psalter_Pahlavi # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
10BA9..10BAF ; Psalter_Pahlavi # No [7] PSALTER PAHLAVI NUMBER ONE..PSALTER PAHLAVI NUMBER ONE HUNDRED
# Total code points: 29
# ================================================
11580..115AE ; Siddham # Lo [47] SIDDHAM LETTER A..SIDDHAM LETTER HA
115AF..115B1 ; Siddham # Mc [3] SIDDHAM VOWEL SIGN AA..SIDDHAM VOWEL SIGN II
115B2..115B5 ; Siddham # Mn [4] SIDDHAM VOWEL SIGN U..SIDDHAM VOWEL SIGN VOCALIC RR
115B8..115BB ; Siddham # Mc [4] SIDDHAM VOWEL SIGN E..SIDDHAM VOWEL SIGN AU
115BC..115BD ; Siddham # Mn [2] SIDDHAM SIGN CANDRABINDU..SIDDHAM SIGN ANUSVARA
115BE ; Siddham # Mc SIDDHAM SIGN VISARGA
115BF..115C0 ; Siddham # Mn [2] SIDDHAM SIGN VIRAMA..SIDDHAM SIGN NUKTA
115C1..115C9 ; Siddham # Po [9] SIDDHAM SIGN SIDDHAM..SIDDHAM END OF TEXT MARK
# Total code points: 72
# ================================================
112B0..112DE ; Khudawadi # Lo [47] KHUDAWADI LETTER A..KHUDAWADI LETTER HA
112DF ; Khudawadi # Mn KHUDAWADI SIGN ANUSVARA
112E0..112E2 ; Khudawadi # Mc [3] KHUDAWADI VOWEL SIGN AA..KHUDAWADI VOWEL SIGN II
112E3..112EA ; Khudawadi # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
112F0..112F9 ; Khudawadi # Nd [10] KHUDAWADI DIGIT ZERO..KHUDAWADI DIGIT NINE
# Total code points: 69
# ================================================
11480..114AF ; Tirhuta # Lo [48] TIRHUTA ANJI..TIRHUTA LETTER HA
114B0..114B2 ; Tirhuta # Mc [3] TIRHUTA VOWEL SIGN AA..TIRHUTA VOWEL SIGN II
114B3..114B8 ; Tirhuta # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
114B9 ; Tirhuta # Mc TIRHUTA VOWEL SIGN E
114BA ; Tirhuta # Mn TIRHUTA VOWEL SIGN SHORT E
114BB..114BE ; Tirhuta # Mc [4] TIRHUTA VOWEL SIGN AI..TIRHUTA VOWEL SIGN AU
114BF..114C0 ; Tirhuta # Mn [2] TIRHUTA SIGN CANDRABINDU..TIRHUTA SIGN ANUSVARA
114C1 ; Tirhuta # Mc TIRHUTA SIGN VISARGA
114C2..114C3 ; Tirhuta # Mn [2] TIRHUTA SIGN VIRAMA..TIRHUTA SIGN NUKTA
114C4..114C5 ; Tirhuta # Lo [2] TIRHUTA SIGN AVAGRAHA..TIRHUTA GVANG
114C6 ; Tirhuta # Po TIRHUTA ABBREVIATION SIGN
114C7 ; Tirhuta # Lo TIRHUTA OM
114D0..114D9 ; Tirhuta # Nd [10] TIRHUTA DIGIT ZERO..TIRHUTA DIGIT NINE
# Total code points: 82
# ================================================
118A0..118DF ; Warang_Citi # L& [64] WARANG CITI CAPITAL LETTER NGAA..WARANG CITI SMALL LETTER VIYO
118E0..118E9 ; Warang_Citi # Nd [10] WARANG CITI DIGIT ZERO..WARANG CITI DIGIT NINE
118EA..118F2 ; Warang_Citi # No [9] WARANG CITI NUMBER TEN..WARANG CITI NUMBER NINETY
118FF ; Warang_Citi # Lo WARANG CITI OM
# Total code points: 84
# EOF

View File

@ -1,18 +1,25 @@
# SpecialCasing-6.2.0.txt
# Date: 2012-05-23, 20:35:15 GMT [MD]
# SpecialCasing-7.0.0.txt
# Date: 2014-03-18, 07:18:02 GMT [MD]
#
# Unicode Character Database
# Copyright (c) 1991-2012 Unicode, Inc.
# Copyright (c) 1991-2014 Unicode, Inc.
# For terms of use, see http://www.unicode.org/terms_of_use.html
# For documentation, see http://www.unicode.org/reports/tr44/
#
# Special Casing Properties
# Special Casing
#
# This file is a supplement to the UnicodeData file.
# It contains additional information about the casing of Unicode characters.
# (For compatibility, the UnicodeData.txt file only contains case mappings for
# characters where they are 1-1, and independent of context and language.
# For more information, see the discussion of Case Mappings in the Unicode Standard.
# This file is a supplement to the UnicodeData.txt file. It does not define any
# properties, but rather provides additional information about the casing of
# Unicode characters, for situations when casing incurs a change in string length
# or is dependent on context or locale. For compatibility, the UnicodeData.txt
# file only contains simple case mappings for characters where they are one-to-one
# and independent of context and language. The data in this file, combined with
# the simple case mappings in UnicodeData.txt, defines the full case mappings
# Lowercase_Mapping (lc), Titlecase_Mapping (tc), and Uppercase_Mapping (uc).
#
# Note that the preferred mechanism for defining tailored casing operations is
# the Unicode Common Locale Data Repository (CLDR). For more information, see the
# discussion of case mappings and case algorithms in the Unicode Standard.
#
# All code points not listed in this file that do not have a simple case mappings
# in UnicodeData.txt map to themselves.
@ -21,16 +28,17 @@
# ================================================================================
# The entries in this file are in the following machine-readable format:
#
# <code>; <lower> ; <title> ; <upper> ; (<condition_list> ;)? # <comment>
# <code>; <lower>; <title>; <upper>; (<condition_list>;)? # <comment>
#
# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more
# than one character, they are separated by spaces. Other than as used to separate
# elements, spaces are to be ignored.
# <code>, <lower>, <title>, and <upper> provide the respective full case mappings
# of <code>, expressed as character values in hex. If there is more than one character,
# they are separated by spaces. Other than as used to separate elements, spaces are
# to be ignored.
#
# The <condition_list> is optional. Where present, it consists of one or more language IDs
# or contexts, separated by spaces. In these conditions:
# or casing contexts, separated by spaces. In these conditions:
# - A condition list overrides the normal behavior if all of the listed conditions are true.
# - The context is always the context of the characters in the original string,
# - The casing context is always the context of the characters in the original string,
# NOT in the resulting string.
# - Case distinctions in the condition list are not significant.
# - Conditions preceded by "Not_" represent the negation of the condition.
@ -38,18 +46,14 @@
#
# A language ID is defined by BCP 47, with '-' and '_' treated equivalently.
#
# A context for a character C is defined by Section 3.13 Default Case
# Operations, of The Unicode Standard, Version 5.0.
# (This is identical to the context defined by Unicode 4.1.0,
# as specified in http://www.unicode.org/versions/Unicode4.1.0/)
# A casing context for a character is defined by Section 3.13 Default Case Algorithms
# of The Unicode Standard.
#
# Parsers of this file must be prepared to deal with future additions to this format:
# * Additional contexts
# * Additional fields
# ================================================================================
# @missing: 0000..10FFFF; <slc>; <stc>; <suc>;
# ================================================================================
# Unconditional mappings
# ================================================================================
@ -114,7 +118,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
# This process can be achieved by first transforming the text to NFC before casing.
# E.g. <alpha><iota_subscript><acute> is uppercased to <ALPHA><acute><IOTA>
# The following cases are already in the UnicodeData file, so are only commented here.
# The following cases are already in the UnicodeData.txt file, so are only commented here.
# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI
@ -205,7 +209,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA
# Note: the following cases for non-final are already in the UnicodeData file.
# Note: the following cases for non-final are already in the UnicodeData.txt file.
# 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA
# 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA
@ -268,7 +272,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I
0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I
# Note: the following case is already in the UnicodeData file.
# Note: the following case is already in the UnicodeData.txt file.
# 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
6.2.0
7.0.0

View File

@ -196,7 +196,6 @@ SUNWprivate_1.1 {
Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig;
Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities;
Java_sun_java2d_opengl_GLXSurfaceData_initOps;
Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer;
Java_sun_print_CUPSPrinter_initIDs;
Java_sun_print_CUPSPrinter_getCupsServer;

View File

@ -37,7 +37,6 @@ SUNWprivate_1.1 {
Java_sun_awt_image_DataBufferNative_getElem;
Java_sun_awt_image_DataBufferNative_setElem;
Java_java_awt_image_ColorModel_initIDs;
Java_java_awt_image_ComponentSampleModel_initIDs;
Java_java_awt_image_IndexColorModel_initIDs;
Java_java_awt_image_Kernel_initIDs;
Java_java_awt_image_Raster_initIDs;
@ -89,7 +88,6 @@ SUNWprivate_1.1 {
Java_java_awt_Choice_initIDs;
Java_java_awt_Dimension_initIDs;
Java_java_awt_event_MouseEvent_initIDs;
Java_java_awt_image_DataBufferInt_initIDs;
Java_java_awt_image_SinglePixelPackedSampleModel_initIDs;
Java_java_awt_Rectangle_initIDs;
Java_sun_awt_image_BufImgSurfaceData_initIDs;

View File

@ -37,7 +37,6 @@ SUNWprivate_1.1 {
Java_sun_awt_image_DataBufferNative_getElem;
Java_sun_awt_image_DataBufferNative_setElem;
Java_java_awt_image_ColorModel_initIDs;
Java_java_awt_image_ComponentSampleModel_initIDs;
Java_java_awt_image_IndexColorModel_initIDs;
Java_java_awt_image_Kernel_initIDs;
Java_java_awt_image_Raster_initIDs;
@ -89,7 +88,6 @@ SUNWprivate_1.1 {
Java_java_awt_Choice_initIDs;
Java_java_awt_Dimension_initIDs;
Java_java_awt_event_MouseEvent_initIDs;
Java_java_awt_image_DataBufferInt_initIDs;
Java_java_awt_image_SinglePixelPackedSampleModel_initIDs;
Java_java_awt_Rectangle_initIDs;
Java_sun_awt_image_BufImgSurfaceData_getSurfaceData;

View File

@ -337,7 +337,6 @@ SUNWprivate_1.1 {
Java_sun_java2d_opengl_GLXGraphicsConfig_initConfig;
Java_sun_java2d_opengl_GLXGraphicsConfig_getOGLCapabilities;
Java_sun_java2d_opengl_GLXSurfaceData_initOps;
Java_sun_java2d_opengl_GLXSurfaceData_initPbuffer;
Java_sun_java2d_x11_X11PMBlitBgLoops_nativeBlitBg;
Java_sun_java2d_x11_X11PMBlitLoops_nativeBlit;

View File

@ -240,6 +240,16 @@ SUNWprivate_1.1 {
Java_java_util_TimeZone_getSystemTimeZoneID;
Java_java_util_TimeZone_getSystemGMTOffsetID;
Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
Java_jdk_internal_jimage_ImageNativeSubstrate_read;
Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
Java_sun_misc_MessageUtils_toStderr;
Java_sun_misc_MessageUtils_toStdout;
Java_sun_misc_NativeSignalHandler_handle0;
@ -282,9 +292,6 @@ SUNWprivate_1.1 {
Java_sun_misc_VMSupport_initAgentProperties;
Java_sun_misc_VMSupport_getVMTemporaryDirectory;
Java_jdk_internal_jimage_concurrent_ConcurrentPReader_initIDs;
Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread;
# ZipFile.c needs this one
throwFileNotFoundException;
# zip_util.c needs this one

View File

@ -32,8 +32,8 @@ SUNWprivate_1.1 {
Java_java_util_zip_Adler32_updateBytes;
Java_java_util_zip_Adler32_updateByteBuffer;
Java_java_util_zip_CRC32_update;
Java_java_util_zip_CRC32_updateBytes;
Java_java_util_zip_CRC32_updateByteBuffer;
Java_java_util_zip_CRC32_updateBytes0;
Java_java_util_zip_CRC32_updateByteBuffer0;
Java_java_util_zip_Deflater_deflateBytes;
Java_java_util_zip_Deflater_end;
Java_java_util_zip_Deflater_getAdler;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -906,6 +906,14 @@ OUTER: for (int i = 0; i < n; i += m) {
return Integer.toString(UnicodeSpec.DIRECTIONALITY_WHITESPACE);
if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS][UnicodeSpec.LONG]))
return Integer.toString(UnicodeSpec.DIRECTIONALITY_OTHER_NEUTRALS);
if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE][UnicodeSpec.LONG]))
return Integer.toString(UnicodeSpec.DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE);
if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE][UnicodeSpec.LONG]))
return Integer.toString(UnicodeSpec.DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE);
if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE][UnicodeSpec.LONG]))
return Integer.toString(UnicodeSpec.DIRECTIONALITY_FIRST_STRONG_ISOLATE);
if (x.equals(UnicodeSpec.bidiCategoryList[UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE][UnicodeSpec.LONG]))
return Integer.toString(UnicodeSpec.DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE);
FAIL("Unknown text substitution marker " + commandMarker + x);
return commandMarker + x;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -121,7 +121,7 @@ public class UnicodeSpec {
String[] tokens = null;
try {
tokens = tokenSeparator.split(s, REQUIRED_FIELDS);
tokens = tokenSeparator.split(s, REQUIRED_FIELDS);
spec = new UnicodeSpec();
spec.setCodePoint(parseCodePoint(tokens[FIELD_VALUE]));
spec.setName(parseName(tokens[FIELD_NAME]));
@ -672,7 +672,8 @@ public class UnicodeSpec {
* Bidirectional categories
*/
public static final byte
DIRECTIONALITY_UNDEFINED = -1,
DIRECTIONALITY_UNDEFINED = -1,
// Strong category
DIRECTIONALITY_LEFT_TO_RIGHT = 0, // L
DIRECTIONALITY_RIGHT_TO_LEFT = 1, // R
@ -689,15 +690,19 @@ public class UnicodeSpec {
DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10, // B
DIRECTIONALITY_SEGMENT_SEPARATOR = 11, // S
DIRECTIONALITY_WHITESPACE = 12, // WS
DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON
DIRECTIONALITY_OTHER_NEUTRALS = 13, // ON
// Explicit Formatting category
DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14, // LRE
DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15, // LRO
DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16, // RLE
DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17, // RLO
DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18, // PDF
DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE = 19, // LRI
DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE = 20, // RLI
DIRECTIONALITY_FIRST_STRONG_ISOLATE = 21, // FSI
DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE = 22, // PDI
DIRECTIONALITY_CATEGORY_COUNT = 19; // sentinel value
DIRECTIONALITY_CATEGORY_COUNT = 23; // sentinel value
// If changes are made to the above bidi category assignments, this
// list of bidi category names must be changed to keep their order in synch.
@ -722,7 +727,10 @@ public class UnicodeSpec {
{"RLE", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING"},
{"RLO", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE"},
{"PDF", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT"},
{"LRI", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE"},
{"RLI", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE"},
{"FSI", "DIRECTIONALITY_FIRST_STRONG_ISOLATE"},
{"PDI", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE"},
};
// Unicode specification lines have fields in this order.

View File

@ -26,8 +26,6 @@
package build.tools.module;
import jdk.internal.jimage.Archive;
import jdk.internal.jimage.ImageFile;
import jdk.internal.jimage.ImageModules;
import java.io.BufferedReader;
import java.io.File;
@ -35,13 +33,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@ -52,6 +48,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import jdk.internal.jimage.ImageFileCreator;
/**
* A tool for building a runtime image.
@ -84,11 +81,23 @@ class ImageBuilder {
boolean showUsage;
}
static abstract class Option {
static class Option {
interface Processing {
void process(ImageBuilder task, String opt, String arg) throws BadArgs;
}
final boolean hasArg;
final String[] aliases;
Option(boolean hasArg, String... aliases) {
final String description;
final Processing processing;
Option(boolean hasArg, String description, Processing processing,
String... aliases) {
this.hasArg = hasArg;
this.description = description;
this.processing = processing;
this.aliases = aliases;
}
boolean isHidden() {
@ -107,8 +116,12 @@ class ImageBuilder {
boolean ignoreRest() {
return false;
}
abstract void process(ImageBuilder task, String opt, String arg) throws BadArgs;
abstract String description();
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
processing.process(task, opt, arg);
}
String description() {
return description;
}
}
private static Path CWD = Paths.get("");
@ -133,64 +146,44 @@ class ImageBuilder {
}
static Option[] recognizedOptions = {
new Option(true, "--cmds") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
task.options.cmds = splitPath(arg, File.pathSeparator);
}
String description() { return "Location of native commands"; }
},
new Option(true, "--configs") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
task.options.configs = splitPath(arg, File.pathSeparator);
}
String description() { return "Location of config files"; }
},
new Option(false, "--help") {
void process(ImageBuilder task, String opt, String arg) {
task.options.help = true;
}
String description() { return "Print this usage message"; }
},
new Option(true, "--classes") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
task.options.classes = splitPath(arg, File.pathSeparator);
}
String description() { return "Location of module classes files"; }
},
new Option(true, "--libs") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
task.options.libs = splitPath(arg, File.pathSeparator);
}
String description() { return "Location of native libraries"; }
},
new Option(true, "--mods") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
for (String mn : arg.split(",")) {
if (mn.isEmpty())
throw new BadArgs("Module not found", mn);
task.options.mods.add(mn);
new Option(true, "Location of native commands", (task, opt, arg) -> {
task.options.cmds = splitPath(arg, File.pathSeparator);
}, "--cmds"),
new Option(true, "Location of config files", (task, opt, arg) -> {
task.options.configs = splitPath(arg, File.pathSeparator);
}, "--configs"),
new Option(false, "Print this usage message", (task, opt, arg) -> {
task.options.help = true;
}, "--help"),
new Option(true, "Location of module classes files", (task, opt, arg) -> {
task.options.classes = splitPath(arg, File.pathSeparator);
}, "--classes"),
new Option(true, "Location of native libraries", (task, opt, arg) -> {
task.options.libs = splitPath(arg, File.pathSeparator);
}, "--libs"),
new Option(true, "Comma separated list of module names",
(task, opt, arg) -> {
for (String mn : arg.split(",")) {
if (mn.isEmpty()) {
throw new BadArgs("Module not found", mn);
}
task.options.mods.add(mn);
}
String description() { return "Comma separated list of module names"; }
},
new Option(true, "--output") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
Path path = Paths.get(arg);
task.options.output = path;
}, "--mods"),
new Option(true, "Location of the output path", (task, opt, arg) -> {
Path path = Paths.get(arg);
task.options.output = path;
}, "--output"),
new Option(true, "Byte order of the target runtime; {little,big}",
(task, opt, arg) -> {
if (arg.equals("little")) {
task.options.endian = ByteOrder.LITTLE_ENDIAN;
} else if (arg.equals("big")) {
task.options.endian = ByteOrder.BIG_ENDIAN;
} else {
throw new BadArgs("Unknown byte order " + arg);
}
String description() { return "Location of the output path"; }
},
new Option(true, "--endian") {
void process(ImageBuilder task, String opt, String arg) throws BadArgs {
if (arg.equals("little"))
task.options.endian = ByteOrder.LITTLE_ENDIAN;
else if (arg.equals("big"))
task.options.endian = ByteOrder.BIG_ENDIAN;
else
throw new BadArgs("Unknown byte order " + arg);
}
String description() { return "Byte order of the target runtime; {little,big}"; }
}
}, "--endian")
};
private final Options options = new Options();
@ -370,28 +363,35 @@ class ImageBuilder {
final Set<String> bootModules;
final Set<String> extModules;
final Set<String> appModules;
final ImageModules imf;
ImageFileHelper(Collection<String> modules) throws IOException {
this.modules = modules;
this.bootModules = modulesFor(BOOT_MODULES).stream()
.filter(modules::contains)
.collect(Collectors.toSet());
.filter(modules::contains)
.collect(Collectors.toSet());
this.extModules = modulesFor(EXT_MODULES).stream()
.filter(modules::contains)
.collect(Collectors.toSet());
this.appModules = modules.stream()
.filter(m -> !bootModules.contains(m) && !extModules.contains(m))
.filter(m -> m.length() != 0 &&
!bootModules.contains(m) &&
!extModules.contains(m))
.collect(Collectors.toSet());
this.imf = new ImageModules(bootModules, extModules, appModules);
}
void createModularImage(Path output) throws IOException {
Set<Archive> archives = modules.stream()
.map(this::toModuleArchive)
.collect(Collectors.toSet());
ImageFile.create(output, archives, imf, options.endian);
Set<Archive> bootArchives = bootModules.stream()
.map(this::toModuleArchive)
.collect(Collectors.toSet());
Set<Archive> extArchives = extModules.stream()
.map(this::toModuleArchive)
.collect(Collectors.toSet());
Set<Archive> appArchives = appModules.stream()
.map(this::toModuleArchive)
.collect(Collectors.toSet());
ImageFileCreator.create(output, "bootmodules", bootArchives, options.endian);
ImageFileCreator.create(output, "extmodules", extArchives, options.endian);
ImageFileCreator.create(output, "appmodules", appArchives, options.endian);
}
ModuleArchive toModuleArchive(String mn) {

View File

@ -26,15 +26,17 @@
package build.tools.module;
import jdk.internal.jimage.Archive;
import jdk.internal.jimage.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Consumer;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.jimage.Archive.Entry.EntryType;
/**
* An Archive backed by an exploded representation on disk.
@ -46,6 +48,8 @@ public class ModuleArchive implements Archive {
private final Path configs;
private final String moduleName;
private final List<InputStream> opened = new ArrayList<>();
public ModuleArchive(String moduleName, Path classes, Path cmds,
Path libs, Path configs) {
this.moduleName = moduleName;
@ -61,183 +65,119 @@ public class ModuleArchive implements Archive {
}
@Override
public void visitResources(Consumer<Resource> consumer) {
if (classes == null)
return;
try{
Files.walk(classes)
.sorted()
.filter(p -> !Files.isDirectory(p)
&& !classes.relativize(p).toString().startsWith("_the.")
&& !classes.relativize(p).toString().equals("javac_state"))
.map(this::toResource)
.forEach(consumer::accept);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
private Resource toResource(Path path) {
try {
return new Resource(classes.relativize(path).toString().replace('\\','/'),
Files.size(path),
0 /* no compression support yet */);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
private enum Section {
CLASSES,
CMDS,
LIBS,
CONFIGS
public void open() throws IOException {
// NOOP
}
@Override
public void visitEntries(Consumer<Entry> consumer) {
try{
if (classes != null)
Files.walk(classes)
.sorted()
.filter(p -> !Files.isDirectory(p)
&& !classes.relativize(p).toString().startsWith("_the.")
&& !classes.relativize(p).toString().equals("javac_state"))
.map(p -> toEntry(p, classes, Section.CLASSES))
.forEach(consumer::accept);
if (cmds != null)
Files.walk(cmds)
public void close() throws IOException {
IOException e = null;
for (InputStream stream : opened) {
try {
stream.close();
} catch (IOException ex) {
if (e == null) {
e = ex;
} else {
e.addSuppressed(ex);
}
}
}
if (e != null) {
throw e;
}
}
@Override
public Stream<Entry> entries() {
List<Entry> entries = new ArrayList<>();
try {
/*
* This code should be revisited to avoid buffering of the entries.
* 1) Do we really need sorting classes? This force buffering of entries.
* libs, cmds and configs are not sorted.
* 2) I/O streams should be concatenated instead of buffering into
* entries list.
* 3) Close I/O streams in a close handler.
*/
if (classes != null) {
try (Stream<Path> stream = Files.walk(classes)) {
entries.addAll(stream
.filter(p -> !Files.isDirectory(p)
&& !classes.relativize(p).toString().startsWith("_the.")
&& !classes.relativize(p).toString().equals("javac_state"))
.sorted()
.map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE))
.collect(Collectors.toList()));
}
}
if (cmds != null) {
try (Stream<Path> stream = Files.walk(cmds)) {
entries.addAll(stream
.filter(p -> !Files.isDirectory(p))
.map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD))
.collect(Collectors.toList()));
}
}
if (libs != null) {
try (Stream<Path> stream = Files.walk(libs)) {
entries.addAll(stream
.filter(p -> !Files.isDirectory(p))
.map(p -> toEntry(p, libs, EntryType.NATIVE_LIB))
.collect(Collectors.toList()));
}
}
if (configs != null) {
try (Stream<Path> stream = Files.walk(configs)) {
entries.addAll(stream
.filter(p -> !Files.isDirectory(p))
.map(p -> toEntry(p, cmds, Section.CMDS))
.forEach(consumer::accept);
if (libs != null)
Files.walk(libs)
.filter(p -> !Files.isDirectory(p))
.map(p -> toEntry(p, libs, Section.LIBS))
.forEach(consumer::accept);
if (configs != null)
Files.walk(configs)
.filter(p -> !Files.isDirectory(p))
.map(p -> toEntry(p, configs, Section.CONFIGS))
.forEach(consumer::accept);
.map(p -> toEntry(p, configs, EntryType.CONFIG))
.collect(Collectors.toList()));
}
}
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
return entries.stream();
}
private static class FileEntry implements Entry {
private final String name;
private final InputStream is;
private class FileEntry extends Entry {
private final boolean isDirectory;
private final Section section;
FileEntry(String name, InputStream is,
boolean isDirectory, Section section) {
this.name = name;
this.is = is;
private final long size;
private final Path entryPath;
FileEntry(Path entryPath, String path, EntryType type,
boolean isDirectory, long size) {
super(ModuleArchive.this, path, path, type);
this.entryPath = entryPath;
this.isDirectory = isDirectory;
this.section = section;
}
public String getName() {
return name;
}
public Section getSection() {
return section;
}
public InputStream getInputStream() {
return is;
this.size = size;
}
public boolean isDirectory() {
return isDirectory;
}
@Override
public long size() {
return size;
}
@Override
public InputStream stream() throws IOException {
InputStream stream = Files.newInputStream(entryPath);
opened.add(stream);
return stream;
}
}
private Entry toEntry(Path entryPath, Path basePath, Section section) {
private Entry toEntry(Path entryPath, Path basePath, EntryType section) {
try {
return new FileEntry(basePath.relativize(entryPath).toString().replace('\\', '/'),
Files.newInputStream(entryPath), false,
section);
String path = basePath.relativize(entryPath).toString().replace('\\', '/');
return new FileEntry(entryPath, path, section,
false, Files.size(entryPath));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public Consumer<Entry> defaultImageWriter(Path path, OutputStream out) {
return new DefaultEntryWriter(path, out);
}
private static class DefaultEntryWriter implements Consumer<Archive.Entry> {
private final Path root;
private final OutputStream out;
DefaultEntryWriter(Path root, OutputStream out) {
this.root = root;
this.out = out;
}
@Override
public void accept(Archive.Entry entry) {
try {
FileEntry e = (FileEntry)entry;
Section section = e.getSection();
String filename = e.getName();
try (InputStream in = entry.getInputStream()) {
switch (section) {
case CLASSES:
if (!filename.startsWith("_the.") && !filename.equals("javac_state"))
writeEntry(in);
break;
case LIBS:
writeEntry(in, destFile(nativeDir(filename), filename));
break;
case CMDS:
Path path = destFile("bin", filename);
writeEntry(in, path);
path.toFile().setExecutable(true, false);
break;
case CONFIGS:
writeEntry(in, destFile("conf", filename));
break;
default:
throw new InternalError("unexpected entry: " + filename);
}
}
} catch (IOException x) {
throw new UncheckedIOException(x);
}
}
private Path destFile(String dir, String filename) {
return root.resolve(dir).resolve(filename);
}
private static void writeEntry(InputStream in, Path dstFile) throws IOException {
if (Files.notExists(dstFile.getParent()))
Files.createDirectories(dstFile.getParent());
Files.copy(in, dstFile);
}
private void writeEntry(InputStream in) throws IOException {
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) > 0)
out.write(buf, 0, n);
}
private static String nativeDir(String filename) {
if (System.getProperty("os.name").startsWith("Windows")) {
if (filename.endsWith(".dll") || filename.endsWith(".diz")
|| filename.endsWith(".pdb") || filename.endsWith(".map")
|| filename.endsWith(".cpl")) {
return "bin";
} else {
return "lib";
}
} else {
return "lib";
}
}
}
}

View File

@ -38,6 +38,9 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException;
import java.util.Arrays;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* Rijndael --pronounced Reindaal-- is a symmetric cipher with a 128-bit
@ -346,7 +349,16 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
* Encrypt exactly one block of plaintext.
*/
void encryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset)
byte[] out, int outOffset) {
cryptBlockCheck(in, inOffset);
cryptBlockCheck(out, outOffset);
implEncryptBlock(in, inOffset, out, outOffset);
}
// Encryption operation. Possibly replaced with a compiler intrinsic.
@HotSpotIntrinsicCandidate
private void implEncryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset)
{
int keyOffset = 0;
int t0 = ((in[inOffset++] ) << 24 |
@ -412,12 +424,20 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
out[outOffset ] = (byte)(S[(t2 ) & 0xFF] ^ (tt ));
}
/**
* Decrypt exactly one block of plaintext.
*/
void decryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset)
byte[] out, int outOffset) {
cryptBlockCheck(in, inOffset);
cryptBlockCheck(out, outOffset);
implDecryptBlock(in, inOffset, out, outOffset);
}
// Decrypt operation. Possibly replaced with a compiler intrinsic.
@HotSpotIntrinsicCandidate
private void implDecryptBlock(byte[] in, int inOffset,
byte[] out, int outOffset)
{
int keyOffset = 4;
int t0 = ((in[inOffset++] ) << 24 |
@ -572,6 +592,25 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
out[outOffset ] = (byte)(Si[(a0 ) & 0xFF] ^ (t1 ));
}
// Used to perform all checks required by the Java semantics
// (i.e., null checks and bounds checks) on the input parameters
// to encryptBlock and to decryptBlock.
// Normally, the Java Runtime performs these checks, however, as
// encryptBlock and decryptBlock are possibly replaced with
// compiler intrinsics, the JDK performs the required checks instead.
// Does not check accesses to class-internal (private) arrays.
private static void cryptBlockCheck(byte[] array, int offset) {
Objects.requireNonNull(array);
if (offset < 0 || offset >= array.length) {
throw new ArrayIndexOutOfBoundsException(offset);
}
int largestIndex = offset + AES_BLOCK_SIZE - 1;
if (largestIndex < 0 || largestIndex >= array.length) {
throw new ArrayIndexOutOfBoundsException(largestIndex);
}
}
/**
* Expand a user-supplied key material into a session key.

View File

@ -27,6 +27,9 @@ package com.sun.crypto.provider;
import java.security.InvalidKeyException;
import java.security.ProviderException;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
@ -138,15 +141,22 @@ class CipherBlockChaining extends FeedbackCipher {
* @return the length of the encrypted data
*/
int encrypt(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset)
byte[] cipher, int cipherOffset) {
cryptBlockSizeCheck(plainLen);
cryptNullAndBoundsCheck(plain, plainOffset, plainLen);
cryptNullAndBoundsCheck(cipher, cipherOffset, plainLen);
return implEncrypt(plain, plainOffset, plainLen,
cipher, cipherOffset);
}
@HotSpotIntrinsicCandidate
private int implEncrypt(byte[] plain, int plainOffset, int plainLen,
byte[] cipher, int cipherOffset)
{
if ((plainLen % blockSize) != 0) {
throw new ProviderException("Internal error in input buffering");
}
int endIndex = plainOffset + plainLen;
for (; plainOffset < endIndex;
plainOffset+=blockSize, cipherOffset += blockSize) {
plainOffset += blockSize, cipherOffset += blockSize) {
for (int i = 0; i < blockSize; i++) {
k[i] = (byte)(plain[i + plainOffset] ^ r[i]);
}
@ -179,11 +189,17 @@ class CipherBlockChaining extends FeedbackCipher {
* @return the length of the decrypted data
*/
int decrypt(byte[] cipher, int cipherOffset, int cipherLen,
byte[] plain, int plainOffset)
byte[] plain, int plainOffset) {
cryptBlockSizeCheck(cipherLen);
cryptNullAndBoundsCheck(cipher, cipherOffset, cipherLen);
cryptNullAndBoundsCheck(plain, plainOffset, cipherLen);
return implDecrypt(cipher, cipherOffset, cipherLen, plain, plainOffset);
}
@HotSpotIntrinsicCandidate
private int implDecrypt(byte[] cipher, int cipherOffset, int cipherLen,
byte[] plain, int plainOffset)
{
if ((cipherLen % blockSize) != 0) {
throw new ProviderException("Internal error in input buffering");
}
int endIndex = cipherOffset + cipherLen;
for (; cipherOffset < endIndex;
@ -196,4 +212,27 @@ class CipherBlockChaining extends FeedbackCipher {
}
return cipherLen;
}
private void cryptBlockSizeCheck(int len) {
if ((len % blockSize) != 0) {
throw new ProviderException("Internal error in input buffering");
}
}
private static void cryptNullAndBoundsCheck(byte[] array, int offset, int len) {
if (len <= 0) {
return; // not an error because cryptImpl/decryptImpl won't execute if len <= 0
}
Objects.requireNonNull(array);
if (offset < 0 || offset >= array.length) {
throw new ArrayIndexOutOfBoundsException(offset);
}
int endIndex = offset + len - 1;
if (endIndex < 0 || endIndex >= array.length) {
throw new ArrayIndexOutOfBoundsException(endIndex);
}
}
}

View File

@ -31,6 +31,8 @@ package com.sun.crypto.provider;
import java.security.ProviderException;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* This class represents the GHASH function defined in NIST 800-38D
* under section 6.4. It needs to be constructed w/ a hash subkey, i.e.
@ -227,6 +229,7 @@ final class GHASH {
* the hotspot signature. This method and methods called by it, cannot
* throw exceptions or allocate arrays as it will breaking intrinsics
*/
@HotSpotIntrinsicCandidate
private static void processBlocks(byte[] data, int inOfs, int blocks, long[] st, long[] subH) {
int offset = inOfs;
while (blocks > 0) {

View File

@ -25,6 +25,8 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The Boolean class wraps a value of the primitive type
* {@code boolean} in an object. An object of type
@ -128,6 +130,7 @@ public final class Boolean implements java.io.Serializable,
*
* @return the primitive {@code boolean} value of this object.
*/
@HotSpotIntrinsicCandidate
public boolean booleanValue() {
return value;
}
@ -146,6 +149,7 @@ public final class Boolean implements java.io.Serializable,
* @return a {@code Boolean} instance representing {@code b}.
* @since 1.4
*/
@HotSpotIntrinsicCandidate
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}

View File

@ -25,6 +25,8 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
*
* The {@code Byte} class wraps a value of primitive type {@code byte}
@ -98,6 +100,7 @@ public final class Byte extends Number implements Comparable<Byte> {
* @return a {@code Byte} instance representing {@code b}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
@ -320,6 +323,7 @@ public final class Byte extends Number implements Comparable<Byte> {
* Returns the value of this {@code Byte} as a
* {@code byte}.
*/
@HotSpotIntrinsicCandidate
public byte byteValue() {
return value;
}

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,7 @@ import java.util.HashMap;
import java.util.Objects;
import java.util.StringJoiner;
import sun.misc.Unsafe;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.CallerSensitive;
import sun.reflect.ConstantPool;
import sun.reflect.Reflection;
@ -502,6 +503,7 @@ public final class Class<T> implements java.io.Serializable,
*
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native boolean isInstance(Object obj);
@ -529,6 +531,7 @@ public final class Class<T> implements java.io.Serializable,
* null.
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native boolean isAssignableFrom(Class<?> cls);
@ -539,6 +542,7 @@ public final class Class<T> implements java.io.Serializable,
* @return {@code true} if this object represents an interface;
* {@code false} otherwise.
*/
@HotSpotIntrinsicCandidate
public native boolean isInterface();
@ -549,6 +553,7 @@ public final class Class<T> implements java.io.Serializable,
* {@code false} otherwise.
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native boolean isArray();
@ -580,6 +585,7 @@ public final class Class<T> implements java.io.Serializable,
* @see java.lang.Void#TYPE
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native boolean isPrimitive();
/**
@ -751,6 +757,7 @@ public final class Class<T> implements java.io.Serializable,
*
* @return the direct superclass of the class represented by this object
*/
@HotSpotIntrinsicCandidate
public native Class<? super T> getSuperclass();
@ -984,6 +991,7 @@ public final class Class<T> implements java.io.Serializable,
* @see java.lang.reflect.Modifier
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public native int getModifiers();
@ -3382,6 +3390,7 @@ public final class Class<T> implements java.io.Serializable,
* @since 1.5
*/
@SuppressWarnings("unchecked")
@HotSpotIntrinsicCandidate
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException(cannotCastMsg(obj));

View File

@ -27,6 +27,7 @@ package java.lang;
import sun.misc.FloatingDecimal;
import sun.misc.DoubleConsts;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Double} class wraps a value of the primitive type
@ -514,6 +515,7 @@ public final class Double extends Number implements Comparable<Double> {
* @return a {@code Double} instance representing {@code d}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Double valueOf(double d) {
return new Double(d);
}
@ -711,6 +713,7 @@ public final class Double extends Number implements Comparable<Double> {
*
* @return the {@code double} value represented by this object
*/
@HotSpotIntrinsicCandidate
public double doubleValue() {
return value;
}
@ -831,6 +834,7 @@ public final class Double extends Number implements Comparable<Double> {
* @param value a {@code double} precision floating-point number.
* @return the bits that represent the floating-point number.
*/
@HotSpotIntrinsicCandidate
public static long doubleToLongBits(double value) {
if (!isNaN(value)) {
return doubleToRawLongBits(value);
@ -874,6 +878,7 @@ public final class Double extends Number implements Comparable<Double> {
* @return the bits that represent the floating-point number.
* @since 1.3
*/
@HotSpotIntrinsicCandidate
public static native long doubleToRawLongBits(double value);
/**
@ -937,6 +942,7 @@ public final class Double extends Number implements Comparable<Double> {
* @return the {@code double} floating-point value with the same
* bit pattern.
*/
@HotSpotIntrinsicCandidate
public static native double longBitsToDouble(long bits);
/**

View File

@ -28,6 +28,7 @@ package java.lang;
import sun.misc.FloatingDecimal;
import sun.misc.FloatConsts;
import sun.misc.DoubleConsts;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Float} class wraps a value of primitive type
@ -429,6 +430,7 @@ public final class Float extends Number implements Comparable<Float> {
* @return a {@code Float} instance representing {@code f}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Float valueOf(float f) {
return new Float(f);
}
@ -622,6 +624,7 @@ public final class Float extends Number implements Comparable<Float> {
*
* @return the {@code float} value represented by this object
*/
@HotSpotIntrinsicCandidate
public float floatValue() {
return value;
}
@ -740,6 +743,7 @@ public final class Float extends Number implements Comparable<Float> {
* @param value a floating-point number.
* @return the bits that represent the floating-point number.
*/
@HotSpotIntrinsicCandidate
public static int floatToIntBits(float value) {
if (!isNaN(value)) {
return floatToRawIntBits(value);
@ -782,6 +786,7 @@ public final class Float extends Number implements Comparable<Float> {
* @return the bits that represent the floating-point number.
* @since 1.3
*/
@HotSpotIntrinsicCandidate
public static native int floatToRawIntBits(float value);
/**
@ -843,6 +848,7 @@ public final class Float extends Number implements Comparable<Float> {
* @return the {@code float} floating-point value with the same bit
* pattern.
*/
@HotSpotIntrinsicCandidate
public static native float intBitsToFloat(int bits);
/**

View File

@ -27,6 +27,7 @@ package java.lang;
import java.lang.annotation.Native;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Integer} class wraps a value of the primitive type
@ -395,6 +396,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* @param i an integer to be converted.
* @return a string representation of the argument in base&nbsp;10.
*/
@HotSpotIntrinsicCandidate
public static String toString(int i) {
if (i == Integer.MIN_VALUE)
return "-2147483648";
@ -972,6 +974,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
@ -1035,6 +1038,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* Returns the value of this {@code Integer} as an
* {@code int}.
*/
@HotSpotIntrinsicCandidate
public int intValue() {
return value;
}
@ -1538,6 +1542,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* is equal to zero.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0)
@ -1565,6 +1570,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* to zero.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
int y;
@ -1587,6 +1593,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* representation of the specified {@code int} value.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
@ -1688,6 +1695,7 @@ public final class Integer extends Number implements Comparable<Integer> {
* {@code int} value.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |

View File

@ -28,6 +28,7 @@ package java.lang;
import java.lang.annotation.Native;
import java.math.*;
import java.util.Objects;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
@ -1074,6 +1075,7 @@ public final class Long extends Number implements Comparable<Long> {
* @return a {@code Long} instance representing {@code l}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
@ -1238,6 +1240,7 @@ public final class Long extends Number implements Comparable<Long> {
* Returns the value of this {@code Long} as a
* {@code long} value.
*/
@HotSpotIntrinsicCandidate
public long longValue() {
return value;
}
@ -1655,6 +1658,7 @@ public final class Long extends Number implements Comparable<Long> {
* is equal to zero.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int numberOfLeadingZeros(long i) {
// HD, Figure 5-6
if (i == 0)
@ -1684,6 +1688,7 @@ public final class Long extends Number implements Comparable<Long> {
* to zero.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int numberOfTrailingZeros(long i) {
// HD, Figure 5-14
int x, y;
@ -1707,6 +1712,7 @@ public final class Long extends Number implements Comparable<Long> {
* representation of the specified {@code long} value.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static int bitCount(long i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x5555555555555555L);
@ -1810,6 +1816,7 @@ public final class Long extends Number implements Comparable<Long> {
* {@code long} value.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static long reverseBytes(long i) {
i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
return (i << 48) | ((i & 0xffff0000L) << 16) |

View File

@ -24,10 +24,11 @@
*/
package java.lang;
import java.util.Random;
import java.util.Random;
import sun.misc.FloatConsts;
import sun.misc.DoubleConsts;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The class {@code Math} contains methods for performing basic
@ -147,6 +148,7 @@ public final class Math {
* @param a an angle, in radians.
* @return the sine of the argument.
*/
@HotSpotIntrinsicCandidate
public static double sin(double a) {
return StrictMath.sin(a); // default impl. delegates to StrictMath
}
@ -162,6 +164,7 @@ public final class Math {
* @param a an angle, in radians.
* @return the cosine of the argument.
*/
@HotSpotIntrinsicCandidate
public static double cos(double a) {
return StrictMath.cos(a); // default impl. delegates to StrictMath
}
@ -179,6 +182,7 @@ public final class Math {
* @param a an angle, in radians.
* @return the tangent of the argument.
*/
@HotSpotIntrinsicCandidate
public static double tan(double a) {
return StrictMath.tan(a); // default impl. delegates to StrictMath
}
@ -280,6 +284,7 @@ public final class Math {
* @return the value <i>e</i><sup>{@code a}</sup>,
* where <i>e</i> is the base of the natural logarithms.
*/
@HotSpotIntrinsicCandidate
public static double exp(double a) {
return StrictMath.exp(a); // default impl. delegates to StrictMath
}
@ -301,6 +306,7 @@ public final class Math {
* @return the value ln&nbsp;{@code a}, the natural logarithm of
* {@code a}.
*/
@HotSpotIntrinsicCandidate
public static double log(double a) {
return StrictMath.log(a); // default impl. delegates to StrictMath
}
@ -326,6 +332,7 @@ public final class Math {
* @return the base 10 logarithm of {@code a}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static double log10(double a) {
return StrictMath.log10(a); // default impl. delegates to StrictMath
}
@ -347,6 +354,7 @@ public final class Math {
* @return the positive square root of {@code a}.
* If the argument is NaN or less than zero, the result is NaN.
*/
@HotSpotIntrinsicCandidate
public static double sqrt(double a) {
return StrictMath.sqrt(a); // default impl. delegates to StrictMath
// Note that hardware sqrt instructions
@ -525,6 +533,7 @@ public final class Math {
* in polar coordinates that corresponds to the point
* (<i>x</i>,&nbsp;<i>y</i>) in Cartesian coordinates.
*/
@HotSpotIntrinsicCandidate
public static double atan2(double y, double x) {
return StrictMath.atan2(y, x); // default impl. delegates to StrictMath
}
@ -652,6 +661,7 @@ public final class Math {
* @param b the exponent.
* @return the value {@code a}<sup>{@code b}</sup>.
*/
@HotSpotIntrinsicCandidate
public static double pow(double a, double b) {
return StrictMath.pow(a, b); // default impl. delegates to StrictMath
}
@ -806,6 +816,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int addExact(int x, int y) {
int r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
@ -825,6 +836,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long addExact(long x, long y) {
long r = x + y;
// HD 2-12 Overflow iff both arguments have the opposite sign of the result
@ -844,6 +856,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int subtractExact(int x, int y) {
int r = x - y;
// HD 2-12 Overflow iff the arguments have different signs and
@ -864,6 +877,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long subtractExact(long x, long y) {
long r = x - y;
// HD 2-12 Overflow iff the arguments have different signs and
@ -884,6 +898,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int multiplyExact(int x, int y) {
long r = (long)x * (long)y;
if ((int)r != r) {
@ -902,6 +917,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long multiplyExact(long x, long y) {
long r = x * y;
long ax = Math.abs(x);
@ -927,6 +943,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int incrementExact(int a) {
if (a == Integer.MAX_VALUE) {
throw new ArithmeticException("integer overflow");
@ -944,6 +961,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long incrementExact(long a) {
if (a == Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
@ -961,6 +979,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int decrementExact(int a) {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
@ -978,6 +997,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long decrementExact(long a) {
if (a == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
@ -995,6 +1015,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows an int
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static int negateExact(int a) {
if (a == Integer.MIN_VALUE) {
throw new ArithmeticException("integer overflow");
@ -1012,6 +1033,7 @@ public final class Math {
* @throws ArithmeticException if the result overflows a long
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public static long negateExact(long a) {
if (a == Long.MIN_VALUE) {
throw new ArithmeticException("long overflow");
@ -1256,6 +1278,7 @@ public final class Math {
* @param a the argument whose absolute value is to be determined
* @return the absolute value of the argument.
*/
@HotSpotIntrinsicCandidate
public static double abs(double a) {
return (a <= 0.0D) ? 0.0D - a : a;
}
@ -1270,6 +1293,7 @@ public final class Math {
* @param b another argument.
* @return the larger of {@code a} and {@code b}.
*/
@HotSpotIntrinsicCandidate
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
@ -1354,6 +1378,7 @@ public final class Math {
* @param b another argument.
* @return the smaller of {@code a} and {@code b}.
*/
@HotSpotIntrinsicCandidate
public static int min(int a, int b) {
return (a <= b) ? a : b;
}

View File

@ -25,6 +25,8 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* Class {@code Object} is the root of the class hierarchy.
* Every class has {@code Object} as a superclass. All objects,
@ -44,6 +46,7 @@ public class Object {
/**
* Constructs a new object.
*/
@HotSpotIntrinsicCandidate
public Object() {}
/**
@ -65,6 +68,7 @@ public class Object {
* class of this object.
* @jls 15.8.2 Class Literals
*/
@HotSpotIntrinsicCandidate
public final native Class<?> getClass();
/**
@ -101,6 +105,7 @@ public class Object {
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
@HotSpotIntrinsicCandidate
public native int hashCode();
/**
@ -213,6 +218,7 @@ public class Object {
* be cloned.
* @see java.lang.Cloneable
*/
@HotSpotIntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
/**

View File

@ -25,6 +25,8 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Short} class wraps a value of primitive type {@code
* short} in an object. An object of type {@code Short} contains a
@ -227,6 +229,7 @@ public final class Short extends Number implements Comparable<Short> {
* @return a {@code Short} instance representing {@code s}.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
@ -334,6 +337,7 @@ public final class Short extends Number implements Comparable<Short> {
* Returns the value of this {@code Short} as a
* {@code short}.
*/
@HotSpotIntrinsicCandidate
public short shortValue() {
return value;
}
@ -487,6 +491,7 @@ public final class Short extends Number implements Comparable<Short> {
* the bytes in the specified {@code short} value.
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static short reverseBytes(short i) {
return (short) (((i & 0xFF00) >> 8) | (i << 8));
}

View File

@ -24,8 +24,10 @@
*/
package java.lang;
import java.util.Random;
import sun.misc.DoubleConsts;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The class {@code StrictMath} contains methods for performing basic
@ -243,7 +245,6 @@ public final class StrictMath {
*/
public static native double log(double a);
/**
* Returns the base 10 logarithm of a {@code double} value.
* Special cases:
@ -280,6 +281,7 @@ public final class StrictMath {
* @param a a value.
* @return the positive square root of {@code a}.
*/
@HotSpotIntrinsicCandidate
public static native double sqrt(double a);
/**
@ -521,7 +523,6 @@ public final class StrictMath {
*/
public static native double atan2(double y, double x);
/**
* Returns the value of the first argument raised to the power of the
* second argument. Special cases:
@ -1009,6 +1010,7 @@ public final class StrictMath {
* @param b another argument.
* @return the larger of {@code a} and {@code b}.
*/
@HotSpotIntrinsicCandidate
public static int max(int a, int b) {
return Math.max(a, b);
}
@ -1073,6 +1075,7 @@ public final class StrictMath {
* @param b another argument.
* @return the smaller of {@code a} and {@code b}.
*/
@HotSpotIntrinsicCandidate
public static int min(int a, int b) {
return Math.min(a, b);
}

View File

@ -42,6 +42,7 @@ import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code String} class represents character strings. All
@ -152,6 +153,7 @@ public final class String
* @param original
* A {@code String}
*/
@HotSpotIntrinsicCandidate
public String(String original) {
this.value = original.value;
this.hash = original.hash;
@ -978,6 +980,7 @@ public final class String
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
@HotSpotIntrinsicCandidate
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
@ -1154,6 +1157,7 @@ public final class String
* value greater than {@code 0} if this string is
* lexicographically greater than the string argument.
*/
@HotSpotIntrinsicCandidate
public int compareTo(String anotherString) {
char[] v1 = value;
char[] v2 = anotherString.value;
@ -1696,6 +1700,7 @@ public final class String
* @return the index of the first occurrence of the specified substring,
* or {@code -1} if there is no such occurrence.
*/
@HotSpotIntrinsicCandidate
public int indexOf(String str) {
return indexOf(str, 0);
}

View File

@ -26,6 +26,7 @@
package java.lang;
import java.util.Arrays;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A thread-safe, mutable sequence of characters.
@ -112,6 +113,7 @@ import java.util.Arrays;
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
@HotSpotIntrinsicCandidate
public StringBuffer() {
super(16);
}
@ -124,6 +126,7 @@ import java.util.Arrays;
* @exception NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
@HotSpotIntrinsicCandidate
public StringBuffer(int capacity) {
super(capacity);
}
@ -135,6 +138,7 @@ import java.util.Arrays;
*
* @param str the initial contents of the buffer.
*/
@HotSpotIntrinsicCandidate
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
@ -271,6 +275,7 @@ import java.util.Arrays;
}
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
@ -382,6 +387,7 @@ import java.util.Arrays;
}
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(char c) {
toStringCache = null;
super.append(c);
@ -389,6 +395,7 @@ import java.util.Arrays;
}
@Override
@HotSpotIntrinsicCandidate
public synchronized StringBuffer append(int i) {
toStringCache = null;
super.append(i);
@ -670,6 +677,7 @@ import java.util.Arrays;
}
@Override
@HotSpotIntrinsicCandidate
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);

View File

@ -25,6 +25,7 @@
package java.lang;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A mutable sequence of characters. This class provides an API compatible
@ -85,6 +86,7 @@ public final class StringBuilder
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
@HotSpotIntrinsicCandidate
public StringBuilder() {
super(16);
}
@ -97,6 +99,7 @@ public final class StringBuilder
* @throws NegativeArraySizeException if the {@code capacity}
* argument is less than {@code 0}.
*/
@HotSpotIntrinsicCandidate
public StringBuilder(int capacity) {
super(capacity);
}
@ -108,6 +111,7 @@ public final class StringBuilder
*
* @param str the initial contents of the buffer.
*/
@HotSpotIntrinsicCandidate
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
@ -132,6 +136,7 @@ public final class StringBuilder
}
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(String str) {
super.append(str);
return this;
@ -198,12 +203,14 @@ public final class StringBuilder
}
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(char c) {
super.append(c);
return this;
}
@Override
@HotSpotIntrinsicCandidate
public StringBuilder append(int i) {
super.append(i);
return this;
@ -402,6 +409,7 @@ public final class StringBuilder
}
@Override
@HotSpotIntrinsicCandidate
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);

View File

@ -42,6 +42,7 @@ import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import sun.reflect.annotation.AnnotationType;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The <code>System</code> class contains several useful class fields
@ -349,6 +350,7 @@ public final class System {
* the current time and midnight, January 1, 1970 UTC.
* @see java.util.Date
*/
@HotSpotIntrinsicCandidate
public static native long currentTimeMillis();
/**
@ -392,6 +394,7 @@ public final class System {
* high-resolution time source, in nanoseconds
* @since 1.5
*/
@HotSpotIntrinsicCandidate
public static native long nanoTime();
/**
@ -486,6 +489,7 @@ public final class System {
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>.
*/
@HotSpotIntrinsicCandidate
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
@ -501,6 +505,7 @@ public final class System {
* @return the hashCode
* @since 1.1
*/
@HotSpotIntrinsicCandidate
public static native int identityHashCode(Object x);
/**

View File

@ -40,7 +40,7 @@ import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A <i>thread</i> is a thread of execution in a program. The Java
@ -261,6 +261,7 @@ class Thread implements Runnable {
*
* @return the currently executing thread.
*/
@HotSpotIntrinsicCandidate
public static native Thread currentThread();
/**
@ -966,6 +967,7 @@ class Thread implements Runnable {
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
@HotSpotIntrinsicCandidate
private native boolean isInterrupted(boolean ClearInterrupted);
/**

View File

@ -27,6 +27,7 @@ package java.lang.invoke;
import java.util.*;
import jdk.internal.HotSpotIntrinsicCandidate;
import static java.lang.invoke.MethodHandleStatics.*;
@ -476,6 +477,7 @@ public abstract class MethodHandle {
* @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
/**
@ -513,6 +515,7 @@ public abstract class MethodHandle {
* @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
*/
@HotSpotIntrinsicCandidate
public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
/**
@ -532,6 +535,7 @@ public abstract class MethodHandle {
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
@HotSpotIntrinsicCandidate
/*non-public*/ final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
/**
@ -541,6 +545,7 @@ public abstract class MethodHandle {
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
@HotSpotIntrinsicCandidate
/*non-public*/ static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
/**
@ -550,6 +555,7 @@ public abstract class MethodHandle {
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
@HotSpotIntrinsicCandidate
/*non-public*/ static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable;
/**
@ -559,6 +565,7 @@ public abstract class MethodHandle {
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
@HotSpotIntrinsicCandidate
/*non-public*/ static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable;
/**
@ -568,6 +575,7 @@ public abstract class MethodHandle {
* @param args the signature-polymorphic parameter list, statically represented using varargs
* @return the signature-polymorphic result, statically represented using {@code Object}
*/
@HotSpotIntrinsicCandidate
/*non-public*/ static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
/**

View File

@ -36,6 +36,7 @@ import sun.invoke.empty.Empty;
import sun.invoke.util.ValueConversions;
import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import static java.lang.invoke.LambdaForm.*;
@ -709,6 +710,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// Intrinsified by C2. Counters are used during parsing to calculate branch frequencies.
@LambdaForm.Hidden
@jdk.internal.HotSpotIntrinsicCandidate
static
boolean profileBoolean(boolean result, int[] counters) {
// Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively.
@ -724,6 +726,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
// Intrinsified by C2. Returns true if obj is a compile-time constant.
@LambdaForm.Hidden
@jdk.internal.HotSpotIntrinsicCandidate
static
boolean isCompileConstant(Object obj) {
return false;

View File

@ -29,6 +29,7 @@ import sun.misc.Cleaner;
import sun.misc.JavaLangRefAccess;
import sun.misc.ManagedLocalsThread;
import sun.misc.SharedSecrets;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* Abstract base class for reference objects. This class defines the
@ -251,6 +252,7 @@ public abstract class Reference<T> {
* @return The object to which this reference refers, or
* <code>null</code> if this reference object has been cleared
*/
@HotSpotIntrinsicCandidate
public T get() {
return this.referent;
}

View File

@ -25,6 +25,8 @@
package java.lang.reflect;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* The {@code Array} class provides static methods to dynamically create and
* access Java arrays.
@ -119,6 +121,7 @@ class Array {
* @exception IllegalArgumentException if the object argument is not
* an array
*/
@HotSpotIntrinsicCandidate
public static native int getLength(Object array)
throws IllegalArgumentException;
@ -477,6 +480,7 @@ class Array {
* Private
*/
@HotSpotIntrinsicCandidate
private static native Object newArray(Class<?> componentType, int length)
throws NegativeArraySizeException;

View File

@ -25,6 +25,7 @@
package java.lang.reflect;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.reflect.CallerSensitive;
import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;
@ -485,6 +486,7 @@ public final class Method extends Executable {
* provoked by this method fails.
*/
@CallerSensitive
@HotSpotIntrinsicCandidate
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException

View File

@ -34,10 +34,13 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import sun.misc.DoubleConsts;
import sun.misc.FloatConsts;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* Immutable arbitrary-precision integers. All operations behave as if
@ -262,6 +265,15 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
*/
private static final int MULTIPLY_SQUARE_THRESHOLD = 20;
/**
* The threshold for using an intrinsic version of
* implMontgomeryXXX to perform Montgomery multiplication. If the
* number of ints in the number is more than this value we do not
* use the intrinsic.
*/
private static final int MONTGOMERY_INTRINSIC_THRESHOLD = 512;
// Constructors
/**
@ -1639,7 +1651,14 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
* Multiplies int arrays x and y to the specified lengths and places
* the result into z. There will be no leading zeros in the resultant array.
*/
private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
multiplyToLenCheck(x, xlen);
multiplyToLenCheck(y, ylen);
return implMultiplyToLen(x, xlen, y, ylen, z);
}
@HotSpotIntrinsicCandidate
private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
int xstart = xlen - 1;
int ystart = ylen - 1;
@ -1669,6 +1688,18 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return z;
}
private static void multiplyToLenCheck(int[] array, int length) {
if (length <= 0) {
return; // not an error because multiplyToLen won't execute if len <= 0
}
Objects.requireNonNull(array);
if (length > array.length) {
throw new ArrayIndexOutOfBoundsException(length - 1);
}
}
/**
* Multiplies two BigIntegers using the Karatsuba multiplication
* algorithm. This is a recursive divide-and-conquer algorithm which is
@ -1999,6 +2030,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
/**
* Java Runtime may use intrinsic for this method.
*/
@HotSpotIntrinsicCandidate
private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) {
/*
* The algorithm used here is adapted from Colin Plumb's C library.
@ -2601,6 +2633,77 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
return (invertResult ? result.modInverse(m) : result);
}
// Montgomery multiplication. These are wrappers for
// implMontgomeryXX routines which are expected to be replaced by
// virtual machine intrinsics. We don't use the intrinsics for
// very large operands: MONTGOMERY_INTRINSIC_THRESHOLD should be
// larger than any reasonable crypto key.
private static int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
int[] product) {
implMontgomeryMultiplyChecks(a, b, n, len, product);
if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
// Very long argument: do not use an intrinsic
product = multiplyToLen(a, len, b, len, product);
return montReduce(product, n, len, (int)inv);
} else {
return implMontgomeryMultiply(a, b, n, len, inv, materialize(product, len));
}
}
private static int[] montgomerySquare(int[] a, int[] n, int len, long inv,
int[] product) {
implMontgomeryMultiplyChecks(a, a, n, len, product);
if (len > MONTGOMERY_INTRINSIC_THRESHOLD) {
// Very long argument: do not use an intrinsic
product = squareToLen(a, len, product);
return montReduce(product, n, len, (int)inv);
} else {
return implMontgomerySquare(a, n, len, inv, materialize(product, len));
}
}
// Range-check everything.
private static void implMontgomeryMultiplyChecks
(int[] a, int[] b, int[] n, int len, int[] product) throws RuntimeException {
if (len % 2 != 0) {
throw new IllegalArgumentException("input array length must be even: " + len);
}
if (len < 1) {
throw new IllegalArgumentException("invalid input length: " + len);
}
if (len > a.length ||
len > b.length ||
len > n.length ||
(product != null && len > product.length)) {
throw new IllegalArgumentException("input array length out of bound: " + len);
}
}
// Make sure that the int array z (which is expected to contain
// the result of a Montgomery multiplication) is present and
// sufficiently large.
private static int[] materialize(int[] z, int len) {
if (z == null || z.length < len)
z = new int[len];
return z;
}
// These methods are intended to be be replaced by virtual machine
// intrinsics.
@HotSpotIntrinsicCandidate
private static int[] implMontgomeryMultiply(int[] a, int[] b, int[] n, int len,
long inv, int[] product) {
product = multiplyToLen(a, len, b, len, product);
return montReduce(product, n, len, (int)inv);
}
@HotSpotIntrinsicCandidate
private static int[] implMontgomerySquare(int[] a, int[] n, int len,
long inv, int[] product) {
product = squareToLen(a, len, product);
return montReduce(product, n, len, (int)inv);
}
static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793,
Integer.MAX_VALUE}; // Sentinel
@ -2679,6 +2782,17 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int[] mod = z.mag;
int modLen = mod.length;
// Make modLen even. It is conventional to use a cryptographic
// modulus that is 512, 768, 1024, or 2048 bits, so this code
// will not normally be executed. However, it is necessary for
// the correct functioning of the HotSpot intrinsics.
if ((modLen & 1) != 0) {
int[] x = new int[modLen + 1];
System.arraycopy(mod, 0, x, 1, modLen);
mod = x;
modLen++;
}
// Select an appropriate window size
int wbits = 0;
int ebits = bitLength(exp, exp.length);
@ -2697,8 +2811,10 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
for (int i=0; i < tblmask; i++)
table[i] = new int[modLen];
// Compute the modular inverse
int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]);
// Compute the modular inverse of the least significant 64-bit
// digit of the modulus
long n0 = (mod[modLen-1] & LONG_MASK) + ((mod[modLen-2] & LONG_MASK) << 32);
long inv = -MutableBigInteger.inverseMod64(n0);
// Convert base to Montgomery form
int[] a = leftShift(base, base.length, modLen << 5);
@ -2706,6 +2822,8 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
MutableBigInteger q = new MutableBigInteger(),
a2 = new MutableBigInteger(a),
b2 = new MutableBigInteger(mod);
b2.normalize(); // MutableBigInteger.divide() assumes that its
// divisor is in normal form.
MutableBigInteger r= a2.divide(b2, q);
table[0] = r.toIntArray();
@ -2714,22 +2832,19 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
if (table[0].length < modLen) {
int offset = modLen - table[0].length;
int[] t2 = new int[modLen];
for (int i=0; i < table[0].length; i++)
t2[i+offset] = table[0][i];
System.arraycopy(table[0], 0, t2, offset, table[0].length);
table[0] = t2;
}
// Set b to the square of the base
int[] b = squareToLen(table[0], modLen, null);
b = montReduce(b, mod, modLen, inv);
int[] b = montgomerySquare(table[0], mod, modLen, inv, null);
// Set t to high half of b
int[] t = Arrays.copyOf(b, modLen);
// Fill in the table with odd powers of the base
for (int i=1; i < tblmask; i++) {
int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null);
table[i] = montReduce(prod, mod, modLen, inv);
table[i] = montgomeryMultiply(t, table[i-1], mod, modLen, inv, null);
}
// Pre load the window that slides over the exponent
@ -2800,8 +2915,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
isone = false;
} else {
t = b;
a = multiplyToLen(t, modLen, mult, modLen, a);
a = montReduce(a, mod, modLen, inv);
a = montgomeryMultiply(t, mult, mod, modLen, inv, a);
t = a; a = b; b = t;
}
}
@ -2813,8 +2927,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
// Square the input
if (!isone) {
t = b;
a = squareToLen(t, modLen, a);
a = montReduce(a, mod, modLen, inv);
a = montgomerySquare(t, mod, modLen, inv, a);
t = a; a = b; b = t;
}
}
@ -2823,7 +2936,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
int[] t2 = new int[2*modLen];
System.arraycopy(b, 0, t2, modLen, modLen);
b = montReduce(t2, mod, modLen, inv);
b = montReduce(t2, mod, modLen, (int)inv);
t2 = Arrays.copyOf(b, modLen);
@ -2916,6 +3029,7 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
/**
* Java Runtime may use intrinsic for this method.
*/
@HotSpotIntrinsicCandidate
private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
long kLong = k & LONG_MASK;
long carry = 0;

View File

@ -2064,6 +2064,21 @@ class MutableBigInteger {
return t;
}
/**
* Returns the multiplicative inverse of val mod 2^64. Assumes val is odd.
*/
static long inverseMod64(long val) {
// Newton's iteration!
long t = val;
t *= 2 - val*t;
t *= 2 - val*t;
t *= 2 - val*t;
t *= 2 - val*t;
t *= 2 - val*t;
assert(t * val == 1);
return t;
}
/**
* Calculate the multiplicative inverse of 2^k mod mod, where mod is odd.
*/

View File

@ -26,6 +26,7 @@
package java.nio;
import java.util.Spliterator;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A container for data of a specific primitive type.
@ -535,6 +536,7 @@ public abstract class Buffer {
* IndexOutOfBoundsException} if it is not smaller than the limit
* or is smaller than zero.
*/
@HotSpotIntrinsicCandidate
final int checkIndex(int i) { // package-private
if ((i < 0) || (i >= limit))
throw new IndexOutOfBoundsException();

View File

@ -185,7 +185,7 @@ public final class Bidi {
AttributedString astr = new AttributedString("");
Bidi newBidi = new Bidi(astr.getIterator());
return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase,lineStart, lineLimit);
return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase, lineStart, lineLimit);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,6 @@
package java.text;
import sun.text.normalizer.NormalizerBase;
import sun.text.normalizer.NormalizerImpl;
/**
* This class provides the method <code>normalize</code> which transforms Unicode

View File

@ -42,6 +42,7 @@ import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* This class contains various methods for manipulating arrays (such as
@ -2654,6 +2655,7 @@ public class Arrays {
* @param a2 the other array to be tested for equality
* @return <tt>true</tt> if the two arrays are equal
*/
@HotSpotIntrinsicCandidate
public static boolean equals(char[] a, char[] a2) {
if (a==a2)
return true;
@ -3205,6 +3207,7 @@ public class Arrays {
* an array of class <tt>newType</tt>
* @since 1.6
*/
@HotSpotIntrinsicCandidate
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
@ -3474,6 +3477,7 @@ public class Arrays {
* an array of class <tt>newType</tt>.
* @since 1.6
*/
@HotSpotIntrinsicCandidate
public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
int newLength = to - from;
if (newLength < 0)

View File

@ -31,6 +31,7 @@ import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* Utility methods for operating on and creating streams.
@ -98,6 +99,7 @@ final class Streams {
}
@Override
@HotSpotIntrinsicCandidate
public void forEachRemaining(IntConsumer consumer) {
Objects.requireNonNull(consumer);

View File

@ -26,7 +26,10 @@
package java.util.zip;
import java.nio.ByteBuffer;
import java.util.Objects;
import sun.nio.ch.DirectBuffer;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A class that can be used to compute the CRC-32 of a data stream.
@ -123,9 +126,49 @@ class CRC32 implements Checksum {
return (long)crc & 0xffffffffL;
}
@HotSpotIntrinsicCandidate
private native static int update(int crc, int b);
private native static int updateBytes(int crc, byte[] b, int off, int len);
private native static int updateByteBuffer(int adler, long addr,
int off, int len);
private static int updateBytes(int crc, byte[] b, int off, int len) {
updateBytesCheck(b, off, len);
return updateBytes0(crc, b, off, len);
}
@HotSpotIntrinsicCandidate
private native static int updateBytes0(int crc, byte[] b, int off, int len);
private static void updateBytesCheck(byte[] b, int off, int len) {
if (len <= 0) {
return; // not an error because updateBytesImpl won't execute if len <= 0
}
Objects.requireNonNull(b);
if (off < 0 || off >= b.length) {
throw new ArrayIndexOutOfBoundsException(off);
}
int endIndex = off + len - 1;
if (endIndex < 0 || endIndex >= b.length) {
throw new ArrayIndexOutOfBoundsException(endIndex);
}
}
private static int updateByteBuffer(int alder, long addr,
int off, int len) {
updateByteBufferCheck(addr);
return updateByteBuffer0(alder, addr, off, len);
}
@HotSpotIntrinsicCandidate
private native static int updateByteBuffer0(int alder, long addr,
int off, int len);
private static void updateByteBufferCheck(long addr) {
// Performs only a null check because bounds checks
// are not easy to do on raw addresses.
if (addr == 0L) {
throw new NullPointerException();
}
}
}

View File

@ -26,6 +26,8 @@ package java.util.zip;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.internal.HotSpotIntrinsicCandidate;
import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;
@ -204,6 +206,7 @@ public final class CRC32C implements Checksum {
/**
* Updates the CRC-32C checksum with the specified array of bytes.
*/
@HotSpotIntrinsicCandidate
private static int updateBytes(int crc, byte[] b, int off, int end) {
// Do only byte reads for arrays so short they can't be aligned
@ -278,6 +281,7 @@ public final class CRC32C implements Checksum {
/**
* Updates the CRC-32C checksum reading from the specified address.
*/
@HotSpotIntrinsicCandidate
private static int updateDirectByteBuffer(int crc, long address,
int off, int end) {

View File

@ -0,0 +1,125 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal;
import java.lang.annotation.*;
/**
* The {@code @HotSpotIntrinsicCandidate} annotation is specific to the Oracle Java
* HotSpot Virtual Machine implementation and indicates that an annotated method
* may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method
* is intrinsified if the HotSpot VM replaces the annotated method with hand-written
* assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve
* performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the
* Java libraries and is therefore not supposed to have any relevance for application
* code.
*
* Maintainers of the Java libraries must consider the following when
* modifying methods annotated with {@code @HotSpotIntrinsicCandidate}.
*
* <ul>
* <li>When modifying a method annotated with {@code @HotSpotIntrinsicCandidate},
* the corresponding intrinsic code in the HotSpot VM implementation must be
* updated to match the semantics of the annotated method.</li>
* <li>For some annotated methods, the corresponding intrinsic may omit some low-level
* checks that would be performed as a matter of course if the intrinsic is implemented
* using Java bytecodes. This is because individual Java bytecodes implicitly check
* for exceptions like {@code NullPointerException} and {@code ArrayStoreException}.
* If such a method is replaced by an intrinsic coded in assembly language, any
* checks performed as a matter of normal bytecode operation must be performed
* before entry into the assembly code. These checks must be performed, as
* appropriate, on all arguments to the intrinsic, and on other values (if any) obtained
* by the intrinsic through those arguments. The checks may be deduced by inspecting
* the non-intrinsic Java code for the method, and determining exactly which exceptions
* may be thrown by the code, including undeclared implicit {@code RuntimeException}s.
* Therefore, depending on the data accesses performed by the intrinsic,
* the checks may include:
*
* <ul>
* <li>null checks on references</li>
* <li>range checks on primitive values used as array indexes</li>
* <li>other validity checks on primitive values (e.g., for divide-by-zero conditions)</li>
* <li>store checks on reference values stored into arrays</li>
* <li>array length checks on arrays indexed from within the intrinsic</li>
* <li>reference casts (when formal parameters are {@code Object} or some other weak type)</li>
* </ul>
*
* </li>
*
* <li>Note that the receiver value ({@code this}) is passed as a extra argument
* to all non-static methods. If a non-static method is an intrinsic, the receiver
* value does not need a null check, but (as stated above) any values loaded by the
* intrinsic from object fields must also be checked. As a matter of clarity, it is
* better to make intrinisics be static methods, to make the dependency on {@code this}
* clear. Also, it is better to explicitly load all required values from object
* fields before entering the intrinsic code, and pass those values as explicit arguments.
* First, this may be necessary for null checks (or other checks). Second, if the
* intrinsic reloads the values from fields and operates on those without checks,
* race conditions may be able to introduce unchecked invalid values into the intrinsic.
* If the intrinsic needs to store a value back to an object field, that value should be
* returned explicitly from the intrinsic; if there are multiple return values, coders
* should consider buffering them in an array. Removing field access from intrinsics
* not only clarifies the interface with between the JVM and JDK; it also helps decouple
* the HotSpot and JDK implementations, since if JDK code before and after the intrinsic
* manages all field accesses, then intrinsics can be coded to be agnostic of object
* layouts.</li>
*
* Maintainers of the HotSpot VM must consider the following when modifying
* intrinsics.
*
* <ul>
* <li>When adding a new intrinsic, make sure that the corresponding method
* in the Java libraries is annotated with {@code @HotSpotIntrinsicCandidate}
* and that all possible call sequences that result in calling the intrinsic contain
* the checks omitted by the intrinsic (if any).</li>
* <li>When modifying an existing intrinsic, the Java libraries must be updated
* to match the semantics of the intrinsic and to execute all checks omitted
* by the intrinsic (if any).</li>
* </ul>
*
* Persons not directly involved with maintaining the Java libraries or the
* HotSpot VM can safely ignore the fact that a method is annotated with
* {@code @HotSpotIntrinsicCandidate}.
*
* The HotSpot VM defines (internally) a list of intrinsics. Not all intrinsic
* are available on all platforms supported by the HotSpot VM. Furthermore,
* the availability of an intrinsic on a given platform depends on the
* configuration of the HotSpot VM (e.g., the set of VM flags enabled).
* Therefore, annotating a method with {@code @HotSpotIntrinsicCandidate} does
* not guarantee that the marked method is intrinsified by the HotSpot VM.
*
* If the {@code CheckIntrinsics} VM flag is enabled, the HotSpot VM checks
* (when loading a class) that (1) all methods of that class that are also on
* the VM's list of intrinsics are annotated with {@code @HotSpotIntrinsicCandidate}
* and that (2) for all methods of that class annotated with
* {@code @HotSpotIntrinsicCandidate} there is an intrinsic in the list.
*
* @since 1.9
*/
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface HotSpotIntrinsicCandidate {
}

View File

@ -24,42 +24,95 @@
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* An Archive of all content, classes, resources, configuration files, and
* other, for a module.
*/
public interface Archive {
/**
* Entry is contained in an Archive
*/
public abstract class Entry {
public static enum EntryType {
MODULE_NAME,
CLASS_OR_RESOURCE,
NATIVE_LIB,
NATIVE_CMD,
CONFIG,
SERVICE;
}
private final String name;
private final EntryType type;
private final Archive archive;
private final String path;
public Entry(Archive archive, String path, String name, EntryType type) {
this.archive = archive;
this.path = path;
this.name = name;
this.type = type;
}
public Archive archive() {
return archive;
}
public String path() {
return path;
}
public EntryType type() {
return type;
}
/**
* Returns the name of this entry.
*/
public String name() {
return name;
}
@Override
public String toString() {
return "type " + type.name() + " path " + path;
}
/**
* Returns the number of uncompressed bytes for this entry.
*/
public abstract long size();
public abstract InputStream stream() throws IOException;
}
/**
* The module name.
*/
String moduleName();
/**
* Visits all classes and resources.
* Stream of Entry.
* The stream of entries needs to be closed after use
* since it might cover lazy I/O based resources.
* So callers need to use a try-with-resources block.
*/
void visitResources(Consumer<Resource> consumer);
Stream<Entry> entries();
/**
* Visits all entries in the Archive.
* Open the archive
*/
void visitEntries(Consumer<Entry> consumer) ;
void open() throws IOException;
/**
* An entries in the Archive.
* Close the archive
*/
interface Entry {
String getName();
InputStream getInputStream();
boolean isDirectory();
}
/**
* A Consumer suitable for writing Entries from this Archive.
*/
Consumer<Entry> defaultImageWriter(Path path, OutputStream out);
void close() throws IOException;
}

View File

@ -24,63 +24,88 @@
*/
package jdk.internal.jimage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.File;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Comparator;
import java.util.stream.IntStream;
public class BasicImageReader {
private final String imagePath;
private final PReader preader;
private final ImageSubstrate substrate;
private final ByteOrder byteOrder;
private final ImageHeader header;
private final int indexSize;
private final IntBuffer redirectBuffer;
private final IntBuffer offsetsBuffer;
private final ByteBuffer locationsBuffer;
private final ByteBuffer stringsBuffer;
private final ImageStrings strings;
private final ImageStringsReader strings;
protected BasicImageReader(String imagePath, ByteOrder byteOrder) throws IOException {
protected BasicImageReader(String imagePath, ByteOrder byteOrder)
throws IOException {
this.imagePath = imagePath;
this.preader = PReader.open(imagePath);
this.substrate = openImageSubstrate(imagePath, byteOrder);
this.byteOrder = byteOrder;
this.header = ImageHeader.readFrom(byteOrder, getIntBuffer(0, ImageHeader.getHeaderSize()));
this.indexSize = header.getIndexSize();
this.redirectBuffer = getIntBuffer(header.getRedirectOffset(), header.getRedirectSize());
this.offsetsBuffer = getIntBuffer(header.getOffsetsOffset(), header.getOffsetsSize());
this.locationsBuffer = getByteBuffer(header.getLocationsOffset(), header.getLocationsSize());
this.stringsBuffer = getByteBuffer(header.getStringsOffset(), header.getStringsSize());
this.strings = new ImageStrings(new ImageStream(stringsBuffer));
this.strings = new ImageStringsReader(this);
}
protected BasicImageReader(String imagePath) throws IOException {
this(imagePath, ByteOrder.nativeOrder());
}
private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder)
throws IOException {
ImageSubstrate substrate;
try {
substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder);
} catch (UnsatisfiedLinkError ex) {
substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder);
}
return substrate;
}
public static BasicImageReader open(String imagePath) throws IOException {
return new BasicImageReader(imagePath, ByteOrder.nativeOrder());
}
public static void releaseByteBuffer(ByteBuffer buffer) {
ImageBufferCache.releaseBuffer(buffer);
}
public ByteOrder getByteOrder() {
return byteOrder;
}
public String imagePath() {
return imagePath;
}
public String imagePathName() {
int slash = imagePath().lastIndexOf(File.separator);
if (slash != -1) {
return imagePath().substring(slash + 1);
}
return imagePath();
}
public boolean isOpen() {
return preader.isOpen();
return true;
}
public void close() throws IOException {
preader.close();
substrate.close();
}
public ImageHeader getHeader() {
return header;
public ImageHeader getHeader() throws IOException {
return ImageHeader.readFrom(
getIndexIntBuffer(0, ImageHeader.getHeaderSize()));
}
public ImageStringsReader getStrings() {
return strings;
}
public ImageLocation findLocation(String name) {
@ -92,148 +117,147 @@ public class BasicImageReader {
}
public synchronized ImageLocation findLocation(UTF8String name) {
int count = header.getLocationCount();
int hash = name.hashCode() % count;
int redirect = getRedirect(hash);
if (redirect == 0) {
return null;
}
int index;
if (redirect < 0) {
// If no collision.
index = -redirect - 1;
} else {
// If collision, recompute hash code.
index = name.hashCode(redirect) % count;
}
int offset = getOffset(index);
if (offset == 0) {
return null;
}
ImageLocation location = getLocation(offset);
return location.verify(name) ? location : null;
return substrate.findLocation(name, strings);
}
public String[] getEntryNames() {
return getEntryNames(true);
}
public String[] getEntryNames(boolean sorted) {
int count = header.getLocationCount();
List<String> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
int offset = getOffset(i);
if (offset != 0) {
ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings);
list.add(location.getFullnameString());
}
}
String[] array = list.toArray(new String[0]);
if (sorted) {
Arrays.sort(array);
}
return array;
return IntStream.of(substrate.attributeOffsets())
.filter(o -> o != 0)
.mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString())
.sorted()
.toArray(String[]::new);
}
protected ImageLocation[] getAllLocations(boolean sorted) {
int count = header.getLocationCount();
List<ImageLocation> list = new ArrayList<>();
for (int i = 0; i < count; i++) {
int offset = getOffset(i);
if (offset != 0) {
ImageLocation location = ImageLocation.readFrom(locationsBuffer, offset, strings);
list.add(location);
}
}
ImageLocation[] array = list.toArray(new ImageLocation[0]);
if (sorted) {
Arrays.sort(array, (ImageLocation loc1, ImageLocation loc2) ->
loc1.getFullnameString().compareTo(loc2.getFullnameString()));
}
return array;
return IntStream.of(substrate.attributeOffsets())
.filter(o -> o != 0)
.mapToObj(o -> ImageLocation.readFrom(this, o))
.sorted(Comparator.comparing(ImageLocation::getFullNameString))
.toArray(ImageLocation[]::new);
}
private IntBuffer getIntBuffer(long offset, long size) throws IOException {
MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size);
private IntBuffer getIndexIntBuffer(long offset, long size)
throws IOException {
ByteBuffer buffer = substrate.getIndexBuffer(offset, size);
buffer.order(byteOrder);
return buffer.asIntBuffer();
}
private ByteBuffer getByteBuffer(long offset, long size) throws IOException {
MappedByteBuffer buffer = preader.channel().map(FileChannel.MapMode.READ_ONLY, offset, size);
// order is not copied into the readonly copy.
ByteBuffer readOnly = buffer.asReadOnlyBuffer();
readOnly.order(byteOrder);
return readOnly;
ImageLocation getLocation(int offset) {
return ImageLocation.readFrom(this, offset);
}
private int getRedirect(int index) {
return redirectBuffer.get(index);
}
private int getOffset(int index) {
return offsetsBuffer.get(index);
}
private ImageLocation getLocation(int offset) {
return ImageLocation.readFrom(locationsBuffer, offset, strings);
public long[] getAttributes(int offset) {
return substrate.getAttributes(offset);
}
public String getString(int offset) {
return strings.get(offset).toString();
return getUTF8String(offset).toString();
}
public byte[] getResource(ImageLocation loc) throws IOException {
public UTF8String getUTF8String(int offset) {
return new UTF8String(substrate.getStringBytes(offset));
}
private byte[] getBufferBytes(ByteBuffer buffer, long size) {
assert size < Integer.MAX_VALUE;
byte[] bytes = new byte[(int)size];
buffer.get(bytes);
return bytes;
}
private byte[] getBufferBytes(long offset, long size) {
ByteBuffer buffer = substrate.getDataBuffer(offset, size);
return getBufferBytes(buffer, size);
}
public byte[] getResource(ImageLocation loc) {
long offset = loc.getContentOffset();
long compressedSize = loc.getCompressedSize();
long uncompressedSize = loc.getUncompressedSize();
assert compressedSize < Integer.MAX_VALUE;
assert uncompressedSize < Integer.MAX_VALUE;
if (compressedSize == 0) {
return preader.read((int)loc.getUncompressedSize(),
indexSize + loc.getContentOffset());
} else {
byte[] buf = preader.read((int)compressedSize,
indexSize + loc.getContentOffset());
return ImageFile.Compressor.decompress(buf);
if (substrate.supportsDataBuffer() && compressedSize == 0) {
return getBufferBytes(offset, uncompressedSize);
}
ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
boolean isRead;
if (compressedSize != 0) {
ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
isRead = substrate.read(offset, compressedBuffer, compressedSize,
uncompressedBuffer, uncompressedSize);
ImageBufferCache.releaseBuffer(compressedBuffer);
} else {
isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
}
byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer,
uncompressedSize) : null;
ImageBufferCache.releaseBuffer(uncompressedBuffer);
return bytes;
}
public byte[] getResource(String name) throws IOException {
public byte[] getResource(String name) {
ImageLocation location = findLocation(name);
return location != null ? getResource(location) : null;
}
public List<String> getNames(String name) throws IOException {
return getNames(getResource(name));
}
public ByteBuffer getResourceBuffer(ImageLocation loc) {
long offset = loc.getContentOffset();
long compressedSize = loc.getCompressedSize();
long uncompressedSize = loc.getUncompressedSize();
assert compressedSize < Integer.MAX_VALUE;
assert uncompressedSize < Integer.MAX_VALUE;
public List<String> getNames(byte[] bytes) {
IntBuffer buffer = ByteBuffer.wrap(bytes).asIntBuffer();
List<String> names = new ArrayList<>();
while (buffer.hasRemaining()) {
int offset = buffer.get();
names.add(getString(offset));
if (substrate.supportsDataBuffer() && compressedSize == 0) {
return substrate.getDataBuffer(offset, uncompressedSize);
}
return names;
ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize);
boolean isRead;
if (compressedSize != 0) {
ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize);
isRead = substrate.read(offset, compressedBuffer, compressedSize,
uncompressedBuffer, uncompressedSize);
ImageBufferCache.releaseBuffer(compressedBuffer);
} else {
isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize);
}
if (isRead) {
return uncompressedBuffer;
} else {
ImageBufferCache.releaseBuffer(uncompressedBuffer);
return null;
}
}
public ByteBuffer getResourceBuffer(String name) {
ImageLocation location = findLocation(name);
return location != null ? getResourceBuffer(location) : null;
}
public InputStream getResourceStream(ImageLocation loc) {
byte[] bytes = getResource(loc);
return new ByteArrayInputStream(bytes);
}
public InputStream getResourceStream(String name) {
ImageLocation location = findLocation(name);
return location != null ? getResourceStream(location) : null;
}
}

View File

@ -25,67 +25,30 @@
package jdk.internal.jimage;
import java.io.PrintStream;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class BasicImageWriter {
public static final String IMAGE_EXT = ".jimage";
public static final String BOOT_NAME = "bootmodules";
public static final String BOOT_IMAGE_NAME = BOOT_NAME + IMAGE_EXT;
private final static int RETRY_LIMIT = 1000;
private ByteOrder byteOrder;
private ImageStrings strings;
private int count;
private ImageStringsWriter strings;
private int length;
private int[] redirect;
private ImageLocation[] locations;
private List<ImageLocation> input;
private ImageLocationWriter[] locations;
private List<ImageLocationWriter> input;
private ImageStream headerStream;
private ImageStream redirectStream;
private ImageStream locationOffsetStream;
private ImageStream locationStream;
private ImageStream allIndexStream;
static class ImageBucket implements Comparable<ImageBucket> {
final List<ImageLocation> list;
ImageBucket() {
this.list = new ArrayList<>();
}
void add(ImageLocation location) {
list.add(location);
}
int getSize() {
return list.size();
}
List<ImageLocation> getList() {
return list;
}
ImageLocation getFirst() {
assert !list.isEmpty() : "bucket should never be empty";
return list.get(0);
}
@Override
public int hashCode() {
return getFirst().hashCode();
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
@Override
public int compareTo(ImageBucket o) {
return o.getSize() - getSize();
}
}
public BasicImageWriter() {
this(ByteOrder.nativeOrder());
}
@ -93,7 +56,7 @@ public final class BasicImageWriter {
public BasicImageWriter(ByteOrder byteOrder) {
this.byteOrder = byteOrder;
this.input = new ArrayList<>();
this.strings = new ImageStrings();
this.strings = new ImageStringsWriter();
this.headerStream = new ImageStream(byteOrder);
this.redirectStream = new ImageStream(byteOrder);
this.locationOffsetStream = new ImageStream(byteOrder);
@ -101,6 +64,10 @@ public final class BasicImageWriter {
this.allIndexStream = new ImageStream(byteOrder);
}
public ByteOrder getByteOrder() {
return byteOrder;
}
public int addString(String string) {
return addString(new UTF8String(string));
}
@ -109,104 +76,48 @@ public final class BasicImageWriter {
return strings.add(string);
}
public void addLocation(String fullname, long contentOffset, long compressedSize, long uncompressedSize) {
ImageLocation location = ImageLocation.newLocation(new UTF8String(fullname), strings, contentOffset, compressedSize, uncompressedSize);
public String getString(int offset) {
UTF8String utf8 = strings.get(offset);
return utf8 != null? utf8.toString() : null;
}
public void addLocation(String fullname, long contentOffset,
long compressedSize, long uncompressedSize) {
ImageLocationWriter location =
ImageLocationWriter.newLocation(new UTF8String(fullname), strings,
contentOffset, compressedSize, uncompressedSize);
input.add(location);
count++;
length++;
}
ImageLocationWriter[] getLocations() {
return locations;
}
int getLocationsCount() {
return input.size();
}
private void generatePerfectHash() {
redo:
while(true) {
redirect = new int[count];
locations = new ImageLocation[count];
PerfectHashBuilder<ImageLocationWriter> builder =
new PerfectHashBuilder<>(
new PerfectHashBuilder.Entry<ImageLocationWriter>().getClass(),
new PerfectHashBuilder.Bucket<ImageLocationWriter>().getClass());
ImageBucket[] sorted = createBuckets();
int free = 0;
for (ImageBucket bucket : sorted) {
if (bucket.getSize() != 1) {
if (!packCollidedEntries(bucket, count)) {
count = (count + 1) | 1;
continue redo;
}
} else {
for ( ; free < count && locations[free] != null; free++) {}
assert free < count : "no free slots";
locations[free] = bucket.getFirst();
redirect[bucket.hashCode() % count] = -1 - free;
free++;
}
}
break;
}
}
private ImageBucket[] createBuckets() {
ImageBucket[] buckets = new ImageBucket[count];
input.stream().forEach((location) -> {
int index = location.hashCode() % count;
ImageBucket bucket = buckets[index];
if (bucket == null) {
buckets[index] = bucket = new ImageBucket();
}
bucket.add(location);
input.forEach((location) -> {
builder.put(location.getFullName(), location);
});
ImageBucket[] sorted = Arrays.asList(buckets).stream()
.filter((bucket) -> (bucket != null))
.sorted()
.toArray(ImageBucket[]::new);
builder.generate();
return sorted;
}
length = builder.getCount();
redirect = builder.getRedirect();
PerfectHashBuilder.Entry<ImageLocationWriter>[] order = builder.getOrder();
locations = new ImageLocationWriter[length];
private boolean packCollidedEntries(ImageBucket bucket, int count) {
List<Integer> undo = new ArrayList<>();
int base = UTF8String.HASH_MULTIPLIER + 1;
int retry = 0;
redo:
while (true) {
for (ImageLocation location : bucket.getList()) {
int index = location.hashCode(base) % count;
if (locations[index] != null) {
undo.stream().forEach((i) -> {
locations[i] = null;
});
undo.clear();
base++;
if (base == 0) {
base = 1;
}
if (++retry > RETRY_LIMIT) {
return false;
}
continue redo;
}
locations[index] = location;
undo.add(index);
}
redirect[bucket.hashCode() % count] = base;
break;
for (int i = 0; i < length; i++) {
locations[i] = order[i].getValue();
}
return true;
}
private void prepareStringBytes() {
@ -214,17 +125,17 @@ public final class BasicImageWriter {
}
private void prepareRedirectBytes() {
for (int i = 0; i < count; i++) {
for (int i = 0; i < length; i++) {
redirectStream.putInt(redirect[i]);
}
}
private void prepareLocationBytes() {
// Reserve location offset zero for empty locations
locationStream.put(ImageLocation.ATTRIBUTE_END << 3);
locationStream.put(ImageLocationWriter.ATTRIBUTE_END << 3);
for (int i = 0; i < count; i++) {
ImageLocation location = locations[i];
for (int i = 0; i < length; i++) {
ImageLocationWriter location = locations[i];
if (location != null) {
location.writeTo(locationStream);
@ -235,14 +146,16 @@ public final class BasicImageWriter {
}
private void prepareOffsetBytes() {
for (int i = 0; i < count; i++) {
ImageLocation location = locations[i];
locationOffsetStream.putInt(location != null ? location.getLocationOffset() : 0);
for (int i = 0; i < length; i++) {
ImageLocationWriter location = locations[i];
int offset = location != null ? location.getLocationOffset() : 0;
locationOffsetStream.putInt(offset);
}
}
private void prepareHeaderBytes() {
ImageHeader header = new ImageHeader(count, locationStream.getSize(), strings.getSize());
ImageHeader header = new ImageHeader(input.size(), length,
locationStream.getSize(), strings.getSize());
header.writeTo(headerStream);
}
@ -268,33 +181,15 @@ public final class BasicImageWriter {
return allIndexStream.toArray();
}
ImageLocation find(UTF8String key) {
int index = key.hashCode() % count;
index = redirect[index];
ImageLocationWriter find(UTF8String key) {
int index = redirect[key.hashCode() % length];
if (index < 0) {
index = -index - 1;
ImageLocation location = locations[index];
return location;
} else {
index = key.hashCode(index) % count;
ImageLocation location = locations[index];
return location;
index = key.hashCode(index) % length;
}
}
public void statistics() {
getBytes();
PrintStream out = System.out;
out.println("Count: " + count);
out.println("Header bytes size: " + headerStream.getSize());
out.println("Redirect bytes size: " + redirectStream.getSize());
out.println("Offset bytes size: " + locationOffsetStream.getSize());
out.println("Location bytes size: " + locationStream.getSize());
out.println("String count: " + strings.getCount());
out.println("String bytes size: " + strings.getSize());
out.println("Total bytes size: " + allIndexStream.getSize());
return locations[index];
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Consumer;
import jdk.internal.jimage.Archive.Entry;
/**
* A Consumer suitable for processing non resources Archive Entry and writing it to the
* appropriate location.
*/
class ExternalFilesWriter implements Consumer<Entry> {
private final Path root;
ExternalFilesWriter(Path root) {
this.root = root;
}
@Override
public void accept(Entry entry) {
String name = entry.path();
try {
String filename = entry.path();
try (InputStream in = entry.stream()) {
switch (entry.type()) {
case NATIVE_LIB:
writeEntry(in, destFile(nativeDir(filename), filename));
break;
case NATIVE_CMD:
Path path = destFile("bin", filename);
writeEntry(in, path);
path.toFile().setExecutable(true);
break;
case CONFIG:
writeEntry(in, destFile("conf", filename));
break;
case MODULE_NAME:
// skip
break;
case SERVICE:
//throw new UnsupportedOperationException(name + " in " + zipfile.toString()); //TODO
throw new UnsupportedOperationException(name + " in " + name);
default:
//throw new InternalError("unexpected entry: " + name + " " + zipfile.toString()); //TODO
throw new InternalError("unexpected entry: " + name + " " + name);
}
}
} catch (FileAlreadyExistsException x) {
System.err.println("File already exists (skipped) " + name);
} catch (IOException x) {
throw new UncheckedIOException(x);
}
}
private Path destFile(String dir, String filename) {
return root.resolve(dir).resolve(filename);
}
private void writeEntry(InputStream in, Path dstFile) throws IOException {
Files.createDirectories(dstFile.getParent());
Files.copy(in, dstFile);
}
private static String nativeDir(String filename) {
if (System.getProperty("os.name").startsWith("Windows")) {
if (filename.endsWith(".dll") || filename.endsWith(".diz")
|| filename.endsWith(".pdb") || filename.endsWith(".map")) {
return "bin";
} else {
return "lib";
}
} else {
return "lib";
}
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.nio.ByteBuffer;
import java.util.ArrayList;
class ImageBufferCache {
private static final int MAX_FREE_BUFFERS = 3;
private static final int LARGE_BUFFER = 0x10000;
private static final ThreadLocal<ArrayList<ImageBufferCache>>
threadLocal = new ThreadLocal<>();
private final ByteBuffer buffer;
private boolean isUsed;
static ByteBuffer getBuffer(long size) {
assert size < Integer.MAX_VALUE;
ByteBuffer buffer = null;
if (size > LARGE_BUFFER) {
buffer = ByteBuffer.allocateDirect((int)((size + 0xFFF) & ~0xFFF));
} else {
ArrayList<ImageBufferCache> buffers = threadLocal.get();
if (buffers == null) {
buffers = new ArrayList<>(MAX_FREE_BUFFERS);
threadLocal.set(buffers);
}
int i = 0, j = buffers.size();
for (ImageBufferCache imageBuffer : buffers) {
if (size <= imageBuffer.capacity()) {
j = i;
if (!imageBuffer.isUsed) {
imageBuffer.isUsed = true;
buffer = imageBuffer.buffer;
break;
}
} else {
break;
}
i++;
}
if (buffer == null) {
ImageBufferCache imageBuffer = new ImageBufferCache((int)size);
buffers.add(j, imageBuffer);
buffer = imageBuffer.buffer;
}
}
buffer.rewind();
buffer.limit((int)size);
return buffer;
}
static void releaseBuffer(ByteBuffer buffer) {
ArrayList<ImageBufferCache> buffers = threadLocal.get();
if (buffers == null ) {
return;
}
if (buffer.capacity() > LARGE_BUFFER) {
return;
}
int i = 0, j = buffers.size();
for (ImageBufferCache imageBuffer : buffers) {
if (!imageBuffer.isUsed) {
j = Math.min(j, i);
}
if (imageBuffer.buffer == buffer) {
imageBuffer.isUsed = false;
j = Math.min(j, i);
break;
}
}
if (buffers.size() > MAX_FREE_BUFFERS && j != buffers.size()) {
buffers.remove(j);
}
}
private ImageBufferCache(int needed) {
this.buffer = ByteBuffer.allocateDirect((needed + 0xFFF) & ~0xFFF);
this.isUsed = true;
this.buffer.limit(needed);
}
private long capacity() {
return buffer.capacity();
}
}

View File

@ -1,288 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import jdk.internal.jimage.ImageModules.Loader;
import jdk.internal.jimage.ImageModules.ModuleIndex;
/**
* An image (native endian.)
* <pre>{@code
* {
* u4 magic;
* u2 major_version;
* u2 minor_version;
* u4 location_count;
* u4 location_attributes_size;
* u4 strings_size;
* u4 redirect[location_count];
* u4 offsets[location_count];
* u1 location_attributes[location_attributes_size];
* u1 strings[strings_size];
* u1 content[if !EOF];
* }
* }</pre>
*/
public final class ImageFile {
private static final String JAVA_BASE = "java.base";
private static final String IMAGE_EXT = ".jimage";
private static final String JAR_EXT = ".jar";
private final Path root;
private final Path mdir;
private final Map<String, List<Resource>> resourcesForModule = new HashMap<>();
private ImageFile(Path path) {
this.root = path;
this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules"));
}
public static ImageFile open(Path path) throws IOException {
ImageFile lib = new ImageFile(path);
return lib.open();
}
private ImageFile open() throws IOException {
Path path = mdir.resolve("bootmodules" + IMAGE_EXT);
ImageReader reader = new ImageReader(path.toString());
ImageHeader header = reader.getHeader();
if (header.getMagic() != ImageHeader.MAGIC) {
if (header.getMagic() == ImageHeader.BADMAGIC) {
throw new IOException(path + ": Image may be not be native endian");
} else {
throw new IOException(path + ": Invalid magic number");
}
}
if (header.getMajorVersion() > ImageHeader.MAJOR_VERSION ||
(header.getMajorVersion() == ImageHeader.MAJOR_VERSION &&
header.getMinorVersion() > ImageHeader.MINOR_VERSION)) {
throw new IOException("invalid version number");
}
return this;
}
public static ImageFile create(Path output,
Set<Archive> archives,
ImageModules modules)
throws IOException
{
return ImageFile.create(output, archives, modules, ByteOrder.nativeOrder());
}
public static ImageFile create(Path output,
Set<Archive> archives,
ImageModules modules,
ByteOrder byteOrder)
throws IOException
{
ImageFile lib = new ImageFile(output);
// get all resources
lib.readModuleEntries(modules, archives);
// write to modular image
lib.writeImage(modules, archives, byteOrder);
return lib;
}
private void writeImage(ImageModules modules,
Set<Archive> archives,
ByteOrder byteOrder)
throws IOException
{
// name to Archive file
Map<String, Archive> nameToArchive =
archives.stream()
.collect(Collectors.toMap(Archive::moduleName, Function.identity()));
Files.createDirectories(mdir);
for (Loader l : Loader.values()) {
Set<String> mods = modules.getModules(l);
try (OutputStream fos = Files.newOutputStream(mdir.resolve(l.getName() + IMAGE_EXT));
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream out = new DataOutputStream(bos)) {
// store index in addition of the class loader map for boot loader
BasicImageWriter writer = new BasicImageWriter(byteOrder);
Set<String> duplicates = new HashSet<>();
// build package map for modules and add as resources
ModuleIndex mindex = modules.buildModuleIndex(l, writer);
long offset = mindex.size();
// the order of traversing the resources and the order of
// the module content being written must be the same
for (String mn : mods) {
for (Resource res : resourcesForModule.get(mn)) {
String path = res.name();
long uncompressedSize = res.size();
long compressedSize = res.csize();
long onFileSize = compressedSize != 0 ? compressedSize : uncompressedSize;
if (duplicates.contains(path)) {
System.err.format("duplicate resource \"%s\", skipping%n", path);
// TODO Need to hang bytes on resource and write from resource not zip.
// Skipping resource throws off writing from zip.
offset += onFileSize;
continue;
}
duplicates.add(path);
writer.addLocation(path, offset, compressedSize, uncompressedSize);
offset += onFileSize;
}
}
// write header and indices
byte[] bytes = writer.getBytes();
out.write(bytes, 0, bytes.length);
// write module table and packages
mindex.writeTo(out);
// write module content
for (String mn : mods) {
writeModule(nameToArchive.get(mn), out);
}
}
}
}
private void readModuleEntries(ImageModules modules,
Set<Archive> archives)
throws IOException
{
for (Archive archive : archives) {
List<Resource> res = new ArrayList<>();
archive.visitResources(x-> res.add(x));
String mn = archive.moduleName();
resourcesForModule.put(mn, res);
Set<String> pkgs = res.stream().map(Resource::name)
.filter(n -> n.endsWith(".class"))
.map(this::toPackage)
.distinct()
.collect(Collectors.toSet());
modules.setPackages(mn, pkgs);
}
}
private String toPackage(String name) {
int index = name.lastIndexOf('/');
if (index > 0) {
return name.substring(0, index).replace('/', '.');
} else {
// ## unnamed package
System.err.format("Warning: %s in unnamed package%n", name);
return "";
}
}
private void writeModule(Archive archive,
OutputStream out)
throws IOException
{
Consumer<Archive.Entry> consumer = archive.defaultImageWriter(root, out);
archive.visitEntries(consumer);
}
static class Compressor {
public static byte[] compress(byte[] bytesIn) {
Deflater deflater = new Deflater();
deflater.setInput(bytesIn);
ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length);
byte[] buffer = new byte[1024];
deflater.finish();
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
stream.write(buffer, 0, count);
}
try {
stream.close();
} catch (IOException ex) {
return bytesIn;
}
byte[] bytesOut = stream.toByteArray();
deflater.end();
return bytesOut;
}
public static byte[] decompress(byte[] bytesIn) {
Inflater inflater = new Inflater();
inflater.setInput(bytesIn);
ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length);
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
int count;
try {
count = inflater.inflate(buffer);
} catch (DataFormatException ex) {
return null;
}
stream.write(buffer, 0, count);
}
try {
stream.close();
} catch (IOException ex) {
return null;
}
byte[] bytesOut = stream.toByteArray();
inflater.end();
return bytesOut;
}
}
}

View File

@ -0,0 +1,355 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.jimage.Archive.Entry;
import jdk.internal.jimage.Archive.Entry.EntryType;
import static jdk.internal.jimage.BasicImageWriter.BOOT_NAME;
import static jdk.internal.jimage.BasicImageWriter.IMAGE_EXT;
/**
* An image (native endian.)
* <pre>{@code
* {
* u4 magic;
* u2 major_version;
* u2 minor_version;
* u4 resource_count;
* u4 table_length;
* u4 location_attributes_size;
* u4 strings_size;
* u4 redirect[table_length];
* u4 offsets[table_length];
* u1 location_attributes[location_attributes_size];
* u1 strings[strings_size];
* u1 content[if !EOF];
* }
* }</pre>
*/
public final class ImageFileCreator {
private final Path root;
private final Path mdir;
private final Map<String, List<Entry>> entriesForModule = new HashMap<>();
private ImageFileCreator(Path path) {
this.root = path;
this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules"));
}
public static ImageFileCreator create(Path output,
Set<Archive> archives)
throws IOException {
return create(output, BOOT_NAME, archives, ByteOrder.nativeOrder());
}
public static ImageFileCreator create(Path output,
Set<Archive> archives,
ByteOrder byteOrder)
throws IOException {
return create(output, BOOT_NAME, archives, byteOrder);
}
public static ImageFileCreator create(Path output,
String fileName,
Set<Archive> archives,
ByteOrder byteOrder)
throws IOException
{
ImageFileCreator image = new ImageFileCreator(output);
// get all entries
Map<String, Set<String>> modulePackagesMap = new HashMap<>();
image.readAllEntries(modulePackagesMap, archives);
// write to modular image
image.writeImage(fileName, modulePackagesMap, archives, byteOrder);
return image;
}
private void readAllEntries(Map<String, Set<String>> modulePackagesMap,
Set<Archive> archives) {
archives.stream().forEach((archive) -> {
Map<Boolean, List<Entry>> es;
try(Stream<Entry> entries = archive.entries()) {
es = entries.collect(Collectors.partitioningBy(n -> n.type()
== EntryType.CLASS_OR_RESOURCE));
}
String mn = archive.moduleName();
List<Entry> all = new ArrayList<>();
all.addAll(es.get(false));
all.addAll(es.get(true));
entriesForModule.put(mn, all);
// Extract package names
Set<String> pkgs = es.get(true).stream().map(Entry::name)
.filter(n -> isClassPackage(n))
.map(ImageFileCreator::toPackage)
.collect(Collectors.toSet());
modulePackagesMap.put(mn, pkgs);
});
}
public static boolean isClassPackage(String path) {
return path.endsWith(".class");
}
public static boolean isResourcePackage(String path) {
path = path.substring(1);
path = path.substring(path.indexOf("/")+1);
return !path.startsWith("META-INF/");
}
public static void recreateJimage(Path jimageFile,
Set<Archive> archives,
Map<String, Set<String>> modulePackages)
throws IOException {
Map<String, List<Entry>> entriesForModule
= archives.stream().collect(Collectors.toMap(
Archive::moduleName,
a -> {
try(Stream<Entry> entries = a.entries()) {
return entries.collect(Collectors.toList());
}
}));
Map<String, Archive> nameToArchive
= archives.stream()
.collect(Collectors.toMap(Archive::moduleName, Function.identity()));
ByteOrder order = ByteOrder.nativeOrder();
ResourcePoolImpl resources = createResources(modulePackages, nameToArchive,
(Entry t) -> {
throw new UnsupportedOperationException("Not supported, no external file "
+ "in a jimage file");
}, entriesForModule, order);
String fileName = jimageFile.getRoot().toString();
generateJImage(jimageFile, fileName, resources, order);
}
private void writeImage(String fileName,
Map<String, Set<String>> modulePackagesMap,
Set<Archive> archives,
ByteOrder byteOrder)
throws IOException {
Files.createDirectories(mdir);
ExternalFilesWriter filesWriter = new ExternalFilesWriter(root);
// name to Archive file
Map<String, Archive> nameToArchive
= archives.stream()
.collect(Collectors.toMap(Archive::moduleName, Function.identity()));
ResourcePoolImpl resources = createResources(modulePackagesMap,
nameToArchive, filesWriter,
entriesForModule, byteOrder);
generateJImage(mdir.resolve(fileName + IMAGE_EXT), fileName, resources,
byteOrder);
}
private static void generateJImage(Path img,
String fileName,
ResourcePoolImpl resources,
ByteOrder byteOrder
) throws IOException {
BasicImageWriter writer = new BasicImageWriter(byteOrder);
Map<String, Set<String>> modulePackagesMap = resources.getModulePackages();
try (OutputStream fos = Files.newOutputStream(img);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream out = new DataOutputStream(bos)) {
Set<String> duplicates = new HashSet<>();
ImageModuleDataWriter moduleData =
ImageModuleDataWriter.buildModuleData(writer, modulePackagesMap);
moduleData.addLocation(fileName, writer);
long offset = moduleData.size();
List<ResourcePool.Resource> content = new ArrayList<>();
List<String> paths = new ArrayList<>();
// the order of traversing the resources and the order of
// the module content being written must be the same
for (ResourcePool.Resource res : resources.getResources()) {
String path = res.getPath();
int index = path.indexOf("/META-INF/");
if (index != -1) {
path = path.substring(index + 1);
}
content.add(res);
long uncompressedSize = res.getLength();
long compressedSize = 0;
if (res instanceof ResourcePool.CompressedResource) {
ResourcePool.CompressedResource comp =
(ResourcePool.CompressedResource) res;
compressedSize = res.getLength();
uncompressedSize = comp.getUncompressedSize();
}
long onFileSize = res.getLength();
if (duplicates.contains(path)) {
System.err.format("duplicate resource \"%s\", skipping%n",
path);
// TODO Need to hang bytes on resource and write
// from resource not zip.
// Skipping resource throws off writing from zip.
offset += onFileSize;
continue;
}
duplicates.add(path);
writer.addLocation(path, offset, compressedSize, uncompressedSize);
paths.add(path);
offset += onFileSize;
}
ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths);
// write header and indices
byte[] bytes = writer.getBytes();
out.write(bytes, 0, bytes.length);
// write module meta data
moduleData.writeTo(out);
// write module content
for(ResourcePool.Resource res : content) {
byte[] buf = res.getByteArray();
out.write(buf, 0, buf.length);
}
tree.addContent(out);
}
}
private static ResourcePoolImpl createResources(Map<String, Set<String>> modulePackagesMap,
Map<String, Archive> nameToArchive,
Consumer<Entry> externalFileHandler,
Map<String, List<Entry>> entriesForModule,
ByteOrder byteOrder) throws IOException {
ResourcePoolImpl resources = new ResourcePoolImpl(byteOrder);
Set<String> mods = modulePackagesMap.keySet();
for (String mn : mods) {
for (Entry entry : entriesForModule.get(mn)) {
String path = entry.name();
if (entry.type() == EntryType.CLASS_OR_RESOURCE) {
if (!entry.path().endsWith(BOOT_NAME)) {
try (InputStream stream = entry.stream()) {
byte[] bytes = readAllBytes(stream);
path = "/" + mn + "/" + path;
try {
resources.addResource(new ResourcePool.Resource(path,
ByteBuffer.wrap(bytes)));
} catch (Exception ex) {
throw new IOException(ex);
}
}
}
} else {
externalFileHandler.accept(entry);
}
}
// Done with this archive, close it.
Archive archive = nameToArchive.get(mn);
archive.close();
}
return resources;
}
private static final int BUF_SIZE = 8192;
private static byte[] readAllBytes(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[BUF_SIZE];
while (true) {
int n = is.read(buf);
if (n < 0) {
break;
}
baos.write(buf, 0, n);
}
return baos.toByteArray();
}
/**
* Helper method that splits a Resource path onto 3 items: module, parent
* and resource name.
*
* @param path
* @return An array containing module, parent and name.
*/
public static String[] splitPath(String path) {
Objects.requireNonNull(path);
String noRoot = path.substring(1);
int pkgStart = noRoot.indexOf("/");
String module = noRoot.substring(0, pkgStart);
List<String> result = new ArrayList<>();
result.add(module);
String pkg = noRoot.substring(pkgStart + 1);
String resName;
int pkgEnd = pkg.lastIndexOf("/");
if (pkgEnd == -1) { // No package.
resName = pkg;
} else {
resName = pkg.substring(pkgEnd + 1);
}
pkg = toPackage(pkg, false);
result.add(pkg);
result.add(resName);
String[] array = new String[result.size()];
return result.toArray(array);
}
private static String toPackage(String name) {
String pkg = toPackage(name, true);
return pkg;
}
private static String toPackage(String name, boolean log) {
int index = name.lastIndexOf('/');
if (index > 0) {
return name.substring(0, index).replace('/', '.');
} else {
// ## unnamed package
if (log) {
System.err.format("Warning: %s in unnamed package%n", name);
}
return "";
}
}
}

View File

@ -25,67 +25,76 @@
package jdk.internal.jimage;
import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
public final class ImageHeader {
public static final int MAGIC = 0xCAFEDADA;
public static final int BADMAGIC = 0xDADAFECA;
public static final short MAJOR_VERSION = 0;
public static final short MINOR_VERSION = 1;
public static final int MAJOR_VERSION = 1;
public static final int MINOR_VERSION = 0;
private final int magic;
private final short majorVersion;
private final short minorVersion;
private final int locationCount;
private final int majorVersion;
private final int minorVersion;
private final int flags;
private final int resourceCount;
private final int tableLength;
private final int locationsSize;
private final int stringsSize;
ImageHeader(int locationCount, int locationsSize, int stringsSize) {
this(MAGIC, MAJOR_VERSION, MINOR_VERSION, locationCount, locationsSize, stringsSize);
public ImageHeader(int resourceCount, int tableCount,
int locationsSize, int stringsSize) {
this(MAGIC, MAJOR_VERSION, MINOR_VERSION, 0, resourceCount,
tableCount, locationsSize, stringsSize);
}
ImageHeader(int magic, short majorVersion, short minorVersion, int locationCount,
int locationsSize, int stringsSize)
public ImageHeader(int magic, int majorVersion, int minorVersion,
int flags, int resourceCount,
int tableLength, int locationsSize, int stringsSize)
{
this.magic = magic;
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
this.locationCount = locationCount;
this.flags = flags;
this.resourceCount = resourceCount;
this.tableLength = tableLength;
this.locationsSize = locationsSize;
this.stringsSize = stringsSize;
}
static int getHeaderSize() {
return 4 +
2 + 2 +
4 +
4 +
4;
public static int getHeaderSize() {
return 7 * 4;
}
static ImageHeader readFrom(ByteOrder byteOrder, IntBuffer buffer) {
static ImageHeader readFrom(IntBuffer buffer) {
int magic = buffer.get(0);
int version = buffer.get(1);
short majorVersion = (short)(byteOrder == ByteOrder.BIG_ENDIAN ?
version >>> 16 : (version & 0xFFFF));
short minorVersion = (short)(byteOrder == ByteOrder.BIG_ENDIAN ?
(version & 0xFFFF) : version >>> 16);
int locationCount = buffer.get(2);
int locationsSize = buffer.get(3);
int stringsSize = buffer.get(4);
int majorVersion = version >>> 16;
int minorVersion = version & 0xFFFF;
int flags = buffer.get(2);
int resourceCount = buffer.get(3);
int tableLength = buffer.get(4);
int locationsSize = buffer.get(5);
int stringsSize = buffer.get(6);
return new ImageHeader(magic, majorVersion, minorVersion, locationCount,
locationsSize, stringsSize);
return new ImageHeader(magic, majorVersion, minorVersion, flags,
resourceCount, tableLength, locationsSize, stringsSize);
}
void writeTo(ImageStream stream) {
stream.putInt(magic);
stream.putShort(majorVersion);
stream.putShort(minorVersion);
stream.putInt(locationCount);
stream.putInt(locationsSize);
stream.putInt(stringsSize);
stream.ensure(getHeaderSize());
writeTo(stream.getBuffer());
}
public void writeTo(ByteBuffer buffer) {
buffer.putInt(magic);
buffer.putInt(majorVersion << 16 | minorVersion);
buffer.putInt(flags);
buffer.putInt(resourceCount);
buffer.putInt(tableLength);
buffer.putInt(locationsSize);
buffer.putInt(stringsSize);
}
public int getMagic() {
@ -100,16 +109,24 @@ public final class ImageHeader {
return minorVersion;
}
public int getLocationCount() {
return locationCount;
public int getFlags() {
return flags;
}
public int getResourceCount() {
return resourceCount;
}
public int getTableLength() {
return tableLength;
}
public int getRedirectSize() {
return locationCount* 4;
return tableLength * 4;
}
public int getOffsetsSize() {
return locationCount* 4;
return tableLength * 4;
}
public int getLocationsSize() {

View File

@ -0,0 +1,242 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import static java.nio.file.StandardOpenOption.READ;
import jdk.internal.jimage.decompressor.Decompressor;
final class ImageJavaSubstrate implements ImageSubstrate {
private final String imagePath;
private final ByteOrder byteOrder;
private final FileChannel channel;
private final ImageHeader header;
private final long indexSize;
private final int[] redirect;
private final int[] offsets;
private final byte[] locations;
private final byte[] strings;
private final Decompressor decompressor = new Decompressor();
private ImageJavaSubstrate(String imagePath, ByteOrder byteOrder)
throws IOException {
this.imagePath = imagePath;
this.byteOrder = byteOrder;
channel = FileChannel.open(Paths.get(imagePath), READ);
int headerSize = ImageHeader.getHeaderSize();
ByteBuffer buffer = getIndexBuffer(0, headerSize);
header = ImageHeader.readFrom(buffer.asIntBuffer());
if (header.getMagic() != ImageHeader.MAGIC ||
header.getMajorVersion() != ImageHeader.MAJOR_VERSION ||
header.getMinorVersion() != ImageHeader.MINOR_VERSION) {
throw new IOException("Image not found \"" + imagePath + "\"");
}
indexSize = header.getIndexSize();
redirect = readIntegers(header.getRedirectOffset(),
header.getRedirectSize());
offsets = readIntegers(header.getOffsetsOffset(),
header.getOffsetsSize());
locations = readBytes(header.getLocationsOffset(),
header.getLocationsSize());
strings = readBytes(header.getStringsOffset(),
header.getStringsSize());
}
static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder)
throws IOException {
return new ImageJavaSubstrate(imagePath, byteOrder);
}
@Override
public void close() {
try {
channel.close();
} catch (IOException ex) {
// Mostly harmless
}
}
@Override
public boolean supportsDataBuffer() {
return false;
}
private int[] readIntegers(long offset, long size) {
assert size < Integer.MAX_VALUE;
IntBuffer buffer = readBuffer(offset, size).asIntBuffer();
int[] integers = new int[(int)size / 4];
buffer.get(integers);
return integers;
}
private byte[] readBytes(long offset, long size) {
assert size < Integer.MAX_VALUE;
ByteBuffer buffer = readBuffer(offset, size);
byte[] bytes = new byte[(int)size];
buffer.get(bytes);
return bytes;
}
private ByteBuffer readBuffer(long offset, long size) {
assert size < Integer.MAX_VALUE;
ByteBuffer buffer = ByteBuffer.allocate((int)size);
buffer.order(byteOrder);
if (!readBuffer(buffer, offset, size)) {
return null;
}
return buffer;
}
private boolean readBuffer(ByteBuffer buffer, long offset, long size) {
assert size < Integer.MAX_VALUE;
assert buffer.limit() == size;
int read = 0;
try {
read = channel.read(buffer, offset);
buffer.rewind();
} catch (IOException ex) {
// fall thru
}
return read == size;
}
@Override
public ByteBuffer getIndexBuffer(long offset, long size) {
assert size < Integer.MAX_VALUE;
return readBuffer(offset, size);
}
@Override
public ByteBuffer getDataBuffer(long offset, long size) {
assert size < Integer.MAX_VALUE;
return getIndexBuffer(indexSize + offset, size);
}
@Override
public boolean read(long offset,
ByteBuffer compressedBuffer, long compressedSize,
ByteBuffer uncompressedBuffer, long uncompressedSize) {
assert compressedSize < Integer.MAX_VALUE;
assert uncompressedSize < Integer.MAX_VALUE;
boolean isRead = readBuffer(compressedBuffer,
indexSize + offset, compressedSize);
if (isRead) {
byte[] bytesIn = new byte[(int)compressedSize];
compressedBuffer.get(bytesIn);
byte[] bytesOut;
try {
bytesOut = decompressor.decompressResource(byteOrder, (int strOffset) -> {
return new UTF8String(getStringBytes(strOffset)).toString();
}, bytesIn);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
uncompressedBuffer.put(bytesOut);
uncompressedBuffer.rewind();
}
return isRead;
}
@Override
public boolean read(long offset,
ByteBuffer uncompressedBuffer, long uncompressedSize) {
assert uncompressedSize < Integer.MAX_VALUE;
boolean isRead = readBuffer(uncompressedBuffer,
indexSize + offset, uncompressedSize);
return isRead;
}
@Override
public byte[] getStringBytes(int offset) {
if (offset == 0) {
return new byte[0];
}
int length = strings.length - offset;
for (int i = offset; i < strings.length; i++) {
if (strings[i] == 0) {
length = i - offset;
break;
}
}
byte[] bytes = new byte[length];
System.arraycopy(strings, offset, bytes, 0, length);
return bytes;
}
@Override
public long[] getAttributes(int offset) {
return ImageLocationBase.decompress(locations, offset);
}
@Override
public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) {
int count = header.getTableLength();
int index = redirect[name.hashCode() % count];
if (index < 0) {
index = -index - 1;
} else {
index = name.hashCode(index) % count;
}
long[] attributes = getAttributes(offsets[index]);
ImageLocation imageLocation = new ImageLocation(attributes, strings);
if (!imageLocation.verify(name)) {
return null;
}
return imageLocation;
}
@Override
public int[] attributeOffsets() {
return offsets;
}
}

View File

@ -25,369 +25,15 @@
package jdk.internal.jimage;
import java.nio.ByteBuffer;
public final class ImageLocation {
final static int ATTRIBUTE_END = 0;
final static int ATTRIBUTE_BASE = 1;
final static int ATTRIBUTE_PARENT = 2;
final static int ATTRIBUTE_EXTENSION = 3;
final static int ATTRIBUTE_OFFSET = 4;
final static int ATTRIBUTE_COMPRESSED = 5;
final static int ATTRIBUTE_UNCOMPRESSED = 6;
final static int ATTRIBUTE_COUNT = 7;
private int locationOffset;
private long[] attributes;
private byte[] bytes;
private final ImageStrings strings;
private ImageLocation(ImageStrings strings) {
this.strings = strings;
public final class ImageLocation extends ImageLocationBase {
ImageLocation(long[] attributes, ImageStringsReader strings) {
super(attributes, strings);
}
void writeTo(ImageStream stream) {
compress();
locationOffset = stream.getPosition();
stream.put(bytes, 0, bytes.length);
}
static ImageLocation readFrom(BasicImageReader reader, int offset) {
long[] attributes = reader.getAttributes(offset);
ImageStringsReader strings = reader.getStrings();
static ImageLocation readFrom(ByteBuffer locationsBuffer, int offset, ImageStrings strings) {
final long[] attributes = new long[ATTRIBUTE_COUNT];
for (int i = offset; true; ) {
int data = locationsBuffer.get(i++) & 0xFF;
int kind = attributeKind(data);
assert ATTRIBUTE_END <= kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
if (kind == ATTRIBUTE_END) {
break;
}
int length = attributeLength(data);
long value = 0;
for (int j = 0; j < length; j++) {
value <<= 8;
value |= locationsBuffer.get(i++) & 0xFF;
}
attributes[kind] = value;
}
ImageLocation location = new ImageLocation(strings);
location.attributes = attributes;
return location;
}
private static int attributeLength(int data) {
return (data & 0x7) + 1;
}
private static int attributeKind(int data) {
return data >>> 3;
}
public boolean verify(UTF8String name) {
UTF8String match = UTF8String.match(name, getParent());
if (match == null) {
return false;
}
match = UTF8String.match(match, getBase());
if (match == null) {
return false;
}
match = UTF8String.match(match, getExtension());
return match != null && match.length() == 0;
}
long getAttribute(int kind) {
assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
decompress();
return attributes[kind];
}
UTF8String getAttributeUTF8String(int kind) {
assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
decompress();
return strings.get((int)attributes[kind]);
}
String getAttributeString(int kind) {
return getAttributeUTF8String(kind).toString();
}
ImageLocation addAttribute(int kind, long value) {
assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
decompress();
attributes[kind] = value;
return this;
}
private void decompress() {
if (attributes == null) {
attributes = new long[ATTRIBUTE_COUNT];
}
if (bytes != null) {
for (int i = 0; i < bytes.length; ) {
int data = bytes[i++] & 0xFF;
int kind = attributeKind(data);
if (kind == ATTRIBUTE_END) {
break;
}
assert ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
int length = attributeLength(data);
long value = 0;
for (int j = 0; j < length; j++) {
value <<= 8;
value |= bytes[i++] & 0xFF;
}
attributes[kind] = value;
}
bytes = null;
}
}
private void compress() {
if (bytes == null) {
ImageStream stream = new ImageStream(16);
for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
long value = attributes[kind];
if (value != 0) {
int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
stream.put((kind << 3) | n);
for (int i = n; i >= 0; i--) {
stream.put((int)(value >> (i << 3)));
}
}
}
stream.put(ATTRIBUTE_END << 3);
bytes = stream.toArray();
attributes = null;
}
}
static ImageLocation newLocation(UTF8String fullname, ImageStrings strings, long contentOffset, long compressedSize, long uncompressedSize) {
UTF8String base;
UTF8String extension = extension(fullname);
int parentOffset = ImageStrings.EMPTY_OFFSET;
int extensionOffset = ImageStrings.EMPTY_OFFSET;
int baseOffset;
if (extension.length() != 0) {
UTF8String parent = parent(fullname);
base = base(fullname);
parentOffset = strings.add(parent);
extensionOffset = strings.add(extension);
} else {
base = fullname;
}
baseOffset = strings.add(base);
return new ImageLocation(strings)
.addAttribute(ATTRIBUTE_BASE, baseOffset)
.addAttribute(ATTRIBUTE_PARENT, parentOffset)
.addAttribute(ATTRIBUTE_EXTENSION, extensionOffset)
.addAttribute(ATTRIBUTE_OFFSET, contentOffset)
.addAttribute(ATTRIBUTE_COMPRESSED, compressedSize)
.addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize);
}
@Override
public int hashCode() {
return getExtension().hashCode(getBase().hashCode(getParent().hashCode()));
}
int hashCode(int base) {
return getExtension().hashCode(getBase().hashCode(getParent().hashCode(base)));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ImageLocation)) {
return false;
}
ImageLocation other = (ImageLocation)obj;
return getBaseOffset() == other.getBaseOffset() &&
getParentOffset() == other.getParentOffset() &&
getExtensionOffset() == other.getExtensionOffset();
}
static UTF8String parent(UTF8String fullname) {
int slash = fullname.lastIndexOf('/');
return slash == UTF8String.NOT_FOUND ? UTF8String.EMPTY_STRING : fullname.substring(0, slash + 1);
}
static UTF8String extension(UTF8String fullname) {
int dot = fullname.lastIndexOf('.');
return dot == UTF8String.NOT_FOUND ? UTF8String.EMPTY_STRING : fullname.substring(dot);
}
static UTF8String base(UTF8String fullname) {
int slash = fullname.lastIndexOf('/');
if (slash != UTF8String.NOT_FOUND) {
fullname = fullname.substring(slash + 1);
}
int dot = fullname.lastIndexOf('.');
if (dot != UTF8String.NOT_FOUND) {
fullname = fullname.substring(0, dot);
}
return fullname;
}
int getLocationOffset() {
return locationOffset;
}
UTF8String getBase() {
return getAttributeUTF8String(ATTRIBUTE_BASE);
}
public String getBaseString() {
return getBase().toString();
}
int getBaseOffset() {
return (int)getAttribute(ATTRIBUTE_BASE);
}
UTF8String getParent() {
return getAttributeUTF8String(ATTRIBUTE_PARENT);
}
public String getParentString() {
return getParent().toString();
}
int getParentOffset() {
return (int)getAttribute(ATTRIBUTE_PARENT);
}
UTF8String getExtension() {
return getAttributeUTF8String(ATTRIBUTE_EXTENSION);
}
public String getExtensionString() {
return getExtension().toString();
}
int getExtensionOffset() {
return (int)getAttribute(ATTRIBUTE_EXTENSION);
}
UTF8String getName() {
return getBase().concat(getExtension());
}
String getNameString() {
return getName().toString();
}
UTF8String getFullname() {
return getParent().concat(getBase(), getExtension());
}
String getFullnameString() {
return getFullname().toString();
}
public long getContentOffset() {
return getAttribute(ATTRIBUTE_OFFSET);
}
public long getCompressedSize() {
return getAttribute(ATTRIBUTE_COMPRESSED);
}
public long getUncompressedSize() {
return getAttribute(ATTRIBUTE_UNCOMPRESSED);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
decompress();
for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
long value = attributes[kind];
if (value == 0) {
continue;
}
switch (kind) {
case ATTRIBUTE_BASE:
sb.append("Base: ");
sb.append(value);
sb.append(' ');
sb.append(strings.get((int)value).toString());
break;
case ATTRIBUTE_PARENT:
sb.append("Parent: ");
sb.append(value);
sb.append(' ');
sb.append(strings.get((int)value).toString());
break;
case ATTRIBUTE_EXTENSION:
sb.append("Extension: ");
sb.append(value);
sb.append(' ');
sb.append(strings.get((int)value).toString());
break;
case ATTRIBUTE_OFFSET:
sb.append("Offset: ");
sb.append(value);
break;
case ATTRIBUTE_COMPRESSED:
sb.append("Compressed: ");
sb.append(value);
break;
case ATTRIBUTE_UNCOMPRESSED:
sb.append("Uncompressed: ");
sb.append(value);
break;
}
sb.append("; ");
}
return sb.toString();
return new ImageLocation(attributes, strings);
}
}

View File

@ -0,0 +1,264 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
public class ImageLocationBase {
final static int ATTRIBUTE_END = 0;
final static int ATTRIBUTE_MODULE = 1;
final static int ATTRIBUTE_PARENT = 2;
final static int ATTRIBUTE_BASE = 3;
final static int ATTRIBUTE_EXTENSION = 4;
final static int ATTRIBUTE_OFFSET = 5;
final static int ATTRIBUTE_COMPRESSED = 6;
final static int ATTRIBUTE_UNCOMPRESSED = 7;
final static int ATTRIBUTE_COUNT = 8;
protected final long[] attributes;
protected final ImageStrings strings;
protected ImageLocationBase(long[] attributes, ImageStrings strings) {
this.attributes = attributes;
this.strings = strings;
}
ImageStrings getStrings() {
return strings;
}
private static int attributeLength(int data) {
return (data & 0x7) + 1;
}
private static int attributeKind(int data) {
return data >>> 3;
}
static long[] decompress(byte[] bytes) {
return decompress(bytes, 0);
}
static long[] decompress(byte[] bytes, int offset) {
long[] attributes = new long[ATTRIBUTE_COUNT];
if (bytes != null) {
for (int i = offset; i < bytes.length; ) {
int data = bytes[i++] & 0xFF;
int kind = attributeKind(data);
if (kind == ATTRIBUTE_END) {
break;
}
assert ATTRIBUTE_END < kind &&
kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
int length = attributeLength(data);
long value = 0;
for (int j = 0; j < length; j++) {
value <<= 8;
value |= bytes[i++] & 0xFF;
}
attributes[kind] = value;
}
}
return attributes;
}
static byte[] compress(long[] attributes) {
ImageStream stream = new ImageStream(16);
for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
long value = attributes[kind];
if (value != 0) {
int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
stream.put((kind << 3) | n);
for (int i = n; i >= 0; i--) {
stream.put((int)(value >> (i << 3)));
}
}
}
stream.put(ATTRIBUTE_END << 3);
return stream.toArray();
}
public boolean verify(UTF8String name) {
return UTF8String.equals(getFullName(), name);
}
protected long getAttribute(int kind) {
assert ATTRIBUTE_END < kind &&
kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
return attributes[kind];
}
protected UTF8String getAttributeUTF8String(int kind) {
assert ATTRIBUTE_END < kind &&
kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
return getStrings().get((int)attributes[kind]);
}
protected String getAttributeString(int kind) {
return getAttributeUTF8String(kind).toString();
}
UTF8String getModule() {
return getAttributeUTF8String(ATTRIBUTE_MODULE);
}
public String getModuleString() {
return getModule().toString();
}
int getModuleOffset() {
return (int)getAttribute(ATTRIBUTE_MODULE);
}
UTF8String getBase() {
return getAttributeUTF8String(ATTRIBUTE_BASE);
}
public String getBaseString() {
return getBase().toString();
}
int getBaseOffset() {
return (int)getAttribute(ATTRIBUTE_BASE);
}
UTF8String getParent() {
return getAttributeUTF8String(ATTRIBUTE_PARENT);
}
public String getParentString() {
return getParent().toString();
}
int getParentOffset() {
return (int)getAttribute(ATTRIBUTE_PARENT);
}
UTF8String getExtension() {
return getAttributeUTF8String(ATTRIBUTE_EXTENSION);
}
public String getExtensionString() {
return getExtension().toString();
}
int getExtensionOffset() {
return (int)getAttribute(ATTRIBUTE_EXTENSION);
}
UTF8String getFullName() {
return getFullName(false);
}
UTF8String getFullName(boolean modulesPrefix) {
// Note: Consider a UTF8StringBuilder.
UTF8String fullName = UTF8String.EMPTY_STRING;
if (getModuleOffset() != 0) {
fullName = fullName.concat(
// TODO The use of UTF8String.MODULES_STRING does not belong here.
modulesPrefix? UTF8String.MODULES_STRING :
UTF8String.EMPTY_STRING,
UTF8String.SLASH_STRING,
getModule(),
UTF8String.SLASH_STRING);
}
if (getParentOffset() != 0) {
fullName = fullName.concat(getParent(),
UTF8String.SLASH_STRING);
}
fullName = fullName.concat(getBase());
if (getExtensionOffset() != 0) {
fullName = fullName.concat(UTF8String.DOT_STRING,
getExtension());
}
return fullName;
}
UTF8String buildName(boolean includeModule, boolean includeParent,
boolean includeName) {
// Note: Consider a UTF8StringBuilder.
UTF8String name = UTF8String.EMPTY_STRING;
if (includeModule && getModuleOffset() != 0) {
name = name.concat(UTF8String.MODULES_STRING,
UTF8String.SLASH_STRING,
getModule());
}
if (includeParent && getParentOffset() != 0) {
name = name.concat(UTF8String.SLASH_STRING,
getParent());
}
if (includeName) {
if (includeModule || includeParent) {
name = name.concat(UTF8String.SLASH_STRING);
}
name = name.concat(getBase());
if (getExtensionOffset() != 0) {
name = name.concat(UTF8String.DOT_STRING,
getExtension());
}
}
return name;
}
String getFullNameString() {
return getFullName().toString();
}
public long getContentOffset() {
return getAttribute(ATTRIBUTE_OFFSET);
}
public long getCompressedSize() {
return getAttribute(ATTRIBUTE_COMPRESSED);
}
public long getUncompressedSize() {
return getAttribute(ATTRIBUTE_UNCOMPRESSED);
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
public final class ImageLocationWriter extends ImageLocationBase {
private int locationOffset;
private ImageLocationWriter(ImageStringsWriter strings) {
super(new long[ATTRIBUTE_COUNT], strings);
}
void writeTo(ImageStream stream) {
byte[] bytes = ImageLocation.compress(attributes);
locationOffset = stream.getPosition();
stream.put(bytes, 0, bytes.length);
}
private ImageLocationWriter addAttribute(int kind, long value) {
assert ATTRIBUTE_END < kind &&
kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
attributes[kind] = value;
return this;
}
private ImageLocationWriter addAttribute(int kind, UTF8String value) {
return addAttribute(kind, strings.add(value));
}
static ImageLocationWriter newLocation(UTF8String fullName,
ImageStringsWriter strings,
long contentOffset, long compressedSize, long uncompressedSize) {
UTF8String moduleName = UTF8String.EMPTY_STRING;
UTF8String parentName = UTF8String.EMPTY_STRING;
UTF8String baseName;
UTF8String extensionName = UTF8String.EMPTY_STRING;
int offset = fullName.indexOf('/', 1);
if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) {
moduleName = fullName.substring(1, offset - 1);
fullName = fullName.substring(offset + 1);
}
offset = fullName.lastIndexOf('/');
if (offset != -1) {
parentName = fullName.substring(0, offset);
fullName = fullName.substring(offset + 1);
}
offset = fullName.lastIndexOf('.');
if (offset != -1) {
baseName = fullName.substring(0, offset);
extensionName = fullName.substring(offset + 1);
} else {
baseName = fullName;
}
return new ImageLocationWriter(strings)
.addAttribute(ATTRIBUTE_MODULE, moduleName)
.addAttribute(ATTRIBUTE_PARENT, parentName)
.addAttribute(ATTRIBUTE_BASE, baseName)
.addAttribute(ATTRIBUTE_EXTENSION, extensionName)
.addAttribute(ATTRIBUTE_OFFSET, contentOffset)
.addAttribute(ATTRIBUTE_COMPRESSED, compressedSize)
.addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize);
}
@Override
public int hashCode() {
return hashCode(UTF8String.HASH_MULTIPLIER);
}
int hashCode(int seed) {
int hash = seed;
if (getModuleOffset() != 0) {
hash = UTF8String.SLASH_STRING.hashCode(hash);
hash = getModule().hashCode(hash);
hash = UTF8String.SLASH_STRING.hashCode(hash);
}
if (getParentOffset() != 0) {
hash = getParent().hashCode(hash);
hash = UTF8String.SLASH_STRING.hashCode(hash);
}
hash = getBase().hashCode(hash);
if (getExtensionOffset() != 0) {
hash = UTF8String.DOT_STRING.hashCode(hash);
hash = getExtension().hashCode(hash);
}
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ImageLocationWriter)) {
return false;
}
ImageLocation other = (ImageLocation)obj;
return getModuleOffset() == other.getModuleOffset() &&
getParentOffset() == other.getParentOffset() &&
getBaseOffset() == other.getBaseOffset() &&
getExtensionOffset() == other.getExtensionOffset();
}
int getLocationOffset() {
return locationOffset;
}
}

View File

@ -0,0 +1,288 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
* Manage module meta data.
*
* NOTE: needs revision.
* Each loader requires set of module meta data to identify which modules and
* packages are managed by that loader. Currently, there is one image file per
* loader, so only one module meta data resource per file.
*
* Each element in the module meta data is a native endian 4 byte integer. Note
* that entries with zero offsets for string table entries should be ignored (
* padding for hash table lookup.)
*
* Format:
* Count of package to module entries
* Count of module to package entries
* Perfect Hash redirect table[Count of package to module entries]
* Package to module entries[Count of package to module entries]
* Offset to package name in string table
* Offset to module name in string table
* Perfect Hash redirect table[Count of module to package entries]
* Module to package entries[Count of module to package entries]
* Offset to module name in string table
* Count of packages in module
* Offset to first package in packages table
* Packages[]
* Offset to package name in string table
*/
final public class ImageModuleData {
public final static String META_DATA_EXTENSION = ".jdata";
public final static String SEPARATOR = "\t";
public final static int NOT_FOUND = -1;
private final static int ptmCountOffset = 0;
private final static int mtpCountOffset = 1;
private final static int ptmRedirectOffset = 2;
private final static int dataNameOffset = 0;
private final static int ptmDataWidth = 2;
private final static int ptmDataModuleOffset = 1;
private final static int mtpDataWidth = 3;
private final static int mtpDataCountOffset = 1;
private final static int mtpDataOffsetOffset = 2;
private final BasicImageReader reader;
private final IntBuffer intBuffer;
private final int ptmRedirectLength;
private final int mtpRedirectLength;
private final int ptmDataOffset;
private final int mtpRedirectOffset;
private final int mtpDataOffset;
private final int mtpPackagesOffset;
public ImageModuleData(BasicImageReader reader) {
this(reader, getBytes(reader));
}
public ImageModuleData(BasicImageReader reader, byte[] bytes) {
this.reader = reader;
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(reader.getByteOrder());
this.intBuffer = byteBuffer.asIntBuffer();
this.ptmRedirectLength = get(ptmCountOffset);
this.mtpRedirectLength = get(mtpCountOffset);
this.ptmDataOffset = ptmRedirectOffset + ptmRedirectLength;
this.mtpRedirectOffset = ptmDataOffset + ptmRedirectLength * ptmDataWidth;
this.mtpDataOffset = mtpRedirectOffset + mtpRedirectLength;
this.mtpPackagesOffset = mtpDataOffset + mtpRedirectLength * mtpDataWidth;
}
private static byte[] getBytes(BasicImageReader reader) {
String loaderName = reader.imagePathName();
if (loaderName.endsWith(BasicImageWriter.IMAGE_EXT)) {
loaderName = loaderName.substring(0, loaderName.length() -
BasicImageWriter.IMAGE_EXT.length());
}
byte[] bytes = reader.getResource(getModuleDataName(loaderName));
if (bytes == null) {
throw new InternalError("module data missing");
}
return bytes;
}
public List<String> fromModulePackages() {
List<String> lines = new ArrayList<>();
for (int i = 0; i < mtpRedirectLength; i++) {
int index = mtpDataOffset + i * mtpDataWidth;
int offset = get(index + dataNameOffset);
if (offset != 0) {
StringBuilder sb = new StringBuilder();
sb.append(getString(offset));
int count = get(index + mtpDataCountOffset);
int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
for (int j = 0; j < count; j++) {
sb.append(SEPARATOR);
sb.append(stringAt(base + j));
}
lines.add(sb.toString());
}
}
return lines;
}
public static String getModuleDataName(String loaderName) {
return loaderName + META_DATA_EXTENSION;
}
private int get(int index) {
return intBuffer.get(index);
}
private String getString(int offset) {
return reader.getString(offset);
}
private String stringAt(int index) {
return reader.getString(get(index));
}
private UTF8String getUTF8String(int offset) {
return reader.getUTF8String(offset);
}
private UTF8String utf8StringAt(int index) {
return reader.getUTF8String(get(index));
}
private int find(UTF8String name, int baseOffset, int length, int width) {
if (length == 0) {
return NOT_FOUND;
}
int hashCode = name.hashCode();
int index = hashCode % length;
int value = get(baseOffset + index);
if (value > 0 ) {
hashCode = name.hashCode(value);
index = hashCode % length;
} else if (value < 0) {
index = -1 - value;
} else {
return NOT_FOUND;
}
index = baseOffset + length + index * width;
if (!utf8StringAt(index + dataNameOffset).equals(name)) {
return NOT_FOUND;
}
return index;
}
public String packageToModule(String packageName) {
UTF8String moduleName = packageToModule(new UTF8String(packageName));
return moduleName != null ? moduleName.toString() : null;
}
public UTF8String packageToModule(UTF8String packageName) {
int index = find(packageName, ptmRedirectOffset, ptmRedirectLength, ptmDataWidth);
if (index != NOT_FOUND) {
return utf8StringAt(index + ptmDataModuleOffset);
}
return null;
}
public List<String> moduleToPackages(String moduleName) {
int index = find(new UTF8String(moduleName), mtpRedirectOffset,
mtpRedirectLength, mtpDataWidth);
if (index != NOT_FOUND) {
int count = get(index + mtpDataCountOffset);
int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
List<String> packages = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
packages.add(stringAt(base + i));
}
return packages;
}
return null;
}
public List<String> allPackageNames() {
List<String> packages = new ArrayList<>();
for (int i = 0; i < ptmRedirectLength; i++) {
int offset = get(ptmDataOffset + i * ptmDataWidth + dataNameOffset);
if (offset != 0) {
packages.add(getString(offset));
}
}
return packages;
}
public Set<String> allModuleNames() {
Set<String> modules = new HashSet<>();
for (int i = 0; i < mtpRedirectLength; i++) {
int index = mtpDataOffset + i * mtpDataWidth;
int offset = get(index + dataNameOffset);
if (offset != 0) {
modules.add(getString(offset));
}
}
return modules;
}
public Map<String, String> packageModuleMap() {
Map<String, String> map = new HashMap<>();
for (int i = 0; i < mtpRedirectLength; i++) {
int index = mtpDataOffset + i * mtpDataWidth;
int offset = get(index + dataNameOffset);
if (offset != 0) {
String moduleName = getString(offset);
int count = get(index + mtpDataCountOffset);
int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset;
for (int j = 0; j < count; j++) {
map.put(stringAt(base + j), moduleName);
}
}
}
return map;
}
}

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class ImageModuleDataWriter {
final byte[] bytes;
public ImageModuleDataWriter(BasicImageWriter writer,
Map<String, List<String>> modulePackages) {
PerfectHashBuilder<String> packageToModule = new PerfectHashBuilder<>(
new PerfectHashBuilder.Entry<String>().getClass(),
new PerfectHashBuilder.Bucket<String>().getClass());
PerfectHashBuilder<List<String>> moduleToPackages = new PerfectHashBuilder<>(
new PerfectHashBuilder.Entry<List<String>>().getClass(),
new PerfectHashBuilder.Bucket<List<String>>().getClass());
modulePackages.entrySet().stream().forEach((entry) -> {
String moduleName = entry.getKey();
List<String> packages = entry.getValue();
packages.stream().forEach((packageName) -> {
packageToModule.put(packageName, moduleName);
});
moduleToPackages.put(moduleName, packages);
});
packageToModule.generate();
moduleToPackages.generate();
bytes = getBytes(writer, packageToModule, moduleToPackages);
}
public static ImageModuleDataWriter buildModuleData(BasicImageWriter writer,
Map<String, Set<String>> modulePackagesMap) {
Set<String> modules = modulePackagesMap.keySet();
Map<String, List<String>> modulePackages = new LinkedHashMap<>();
modules.stream().sorted().forEach((moduleName) -> {
List<String> localPackages = modulePackagesMap.get(moduleName).stream()
.map(pn -> pn.replace('.', '/'))
.sorted()
.collect(Collectors.toList());
modulePackages.put(moduleName, localPackages);
});
return new ImageModuleDataWriter(writer, modulePackages);
}
public static Map<String, List<String>> toModulePackages(List<String> lines) {
Map<String, List<String>> modulePackages = new LinkedHashMap<>();
for (String line : lines) {
String[] parts = line.split(ImageModuleData.SEPARATOR);
String moduleName = parts[0];
List<String> packages = Arrays.asList(Arrays.copyOfRange(parts, 1, parts.length));
modulePackages.put(moduleName, packages);
}
return modulePackages;
}
public void addLocation(String name, BasicImageWriter writer) {
writer.addLocation(ImageModuleData.getModuleDataName(name), 0, 0, bytes.length);
}
private byte[] getBytes(BasicImageWriter writer,
PerfectHashBuilder<String> packageToModule,
PerfectHashBuilder<List<String>> moduleToPackages) {
ImageStream stream = new ImageStream(writer.getByteOrder());
int[] ptmRedirect = packageToModule.getRedirect();
int[] mtpRedirect = moduleToPackages.getRedirect();
PerfectHashBuilder.Entry<String>[] ptmOrder = packageToModule.getOrder();
PerfectHashBuilder.Entry<List<String>>[] mtpOrder = moduleToPackages.getOrder();
stream.putInt(ptmRedirect.length);
stream.putInt(mtpRedirect.length);
for (int value : ptmRedirect) {
stream.putInt(value);
}
for (PerfectHashBuilder.Entry<String> entry : ptmOrder) {
if (entry != null) {
stream.putInt(writer.addString(entry.getKey()));
stream.putInt(writer.addString(entry.getValue()));
} else {
stream.putInt(0);
stream.putInt(0);
}
}
for (int value : mtpRedirect) {
stream.putInt(value);
}
int index = 0;
for (PerfectHashBuilder.Entry<List<String>> entry : mtpOrder) {
if (entry != null) {
int count = entry.getValue().size();
stream.putInt(writer.addString(entry.getKey()));
stream.putInt(count);
stream.putInt(index);
index += count;
} else {
stream.putInt(0);
stream.putInt(0);
stream.putInt(0);
}
}
for (PerfectHashBuilder.Entry<List<String>> entry : mtpOrder) {
if (entry != null) {
List<String> value = entry.getValue();
value.stream().forEach((packageName) -> {
stream.putInt(writer.addString(packageName));
});
}
}
return stream.toArray();
}
public void writeTo(DataOutputStream out) throws IOException {
out.write(bytes, 0, bytes.length);
}
public int size() {
return bytes.length;
}
}

View File

@ -1,180 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static jdk.internal.jimage.PackageModuleMap.*;
public class ImageModules {
protected final Map<Loader, LoaderModuleData> loaders = new LinkedHashMap<>();
protected final Map<String, Set<String>> localPkgs = new HashMap<>();
protected ImageModules() {}
public ImageModules(Set<String> bootModules,
Set<String> extModules,
Set<String> appModules) throws IOException {
mapModulesToLoader(Loader.BOOT_LOADER, bootModules);
mapModulesToLoader(Loader.EXT_LOADER, extModules);
mapModulesToLoader(Loader.APP_LOADER, appModules);
}
public Map<String, Set<String>> packages() {
return localPkgs;
}
// ## FIXME: should be package-private
// When jlink legacy format support is removed, it should
// use the package table in the jimage.
public void setPackages(String mn, Set<String> pkgs) {
localPkgs.put(mn, pkgs);
}
/*
* Returns the name of modules mapped to a given class loader in the image
*/
public Set<String> getModules(Loader type) {
if (loaders.containsKey(type)) {
return loaders.get(type).modules();
} else {
return Collections.emptySet();
}
}
private void mapModulesToLoader(Loader loader, Set<String> modules) {
if (modules.isEmpty())
return;
// put java.base first
Set<String> mods = new LinkedHashSet<>();
modules.stream()
.filter(m -> m.equals("java.base"))
.forEach(mods::add);
modules.stream().sorted()
.filter(m -> !m.equals("java.base"))
.forEach(mods::add);
loaders.put(loader, new LoaderModuleData(loader, mods));
}
enum Loader {
BOOT_LOADER(0, "bootmodules"),
EXT_LOADER(1, "extmodules"),
APP_LOADER(2, "appmodules"); // ## may be more than 1 loader
final int id;
final String name;
Loader(int id, String name) {
this.id = id;
this.name = name;
}
String getName() {
return name;
}
static Loader get(int id) {
switch (id) {
case 0: return BOOT_LOADER;
case 1: return EXT_LOADER;
case 2: return APP_LOADER;
default:
throw new IllegalArgumentException("invalid loader id: " + id);
}
}
public int id() { return id; }
}
public class LoaderModuleData {
private final Loader loader;
private final Set<String> modules;
LoaderModuleData(Loader loader, Set<String> modules) {
this.loader = loader;
this.modules = Collections.unmodifiableSet(modules);
}
Set<String> modules() {
return modules;
}
Loader loader() { return loader; }
}
ModuleIndex buildModuleIndex(Loader type, BasicImageWriter writer) {
return new ModuleIndex(getModules(type), writer);
}
/*
* Generate module name table and the package map as resources
* in the modular image
*/
public class ModuleIndex {
final Map<String, Integer> moduleOffsets = new LinkedHashMap<>();
final Map<String, List<Integer>> packageOffsets = new HashMap<>();
final int size;
public ModuleIndex(Set<String> mods, BasicImageWriter writer) {
// module name offsets
writer.addLocation(MODULES_ENTRY, 0, 0, mods.size() * 4);
long offset = mods.size() * 4;
for (String mn : mods) {
moduleOffsets.put(mn, writer.addString(mn));
List<Integer> poffsets = localPkgs.get(mn).stream()
.map(pn -> pn.replace('.', '/'))
.map(writer::addString)
.collect(Collectors.toList());
// package name offsets per module
String entry = mn + "/" + PACKAGES_ENTRY;
int bytes = poffsets.size() * 4;
writer.addLocation(entry, offset, 0, bytes);
offset += bytes;
packageOffsets.put(mn, poffsets);
}
this.size = (int) offset;
}
void writeTo(DataOutputStream out) throws IOException {
for (int moffset : moduleOffsets.values()) {
out.writeInt(moffset);
}
for (String mn : moduleOffsets.keySet()) {
for (int poffset : packageOffsets.get(mn)) {
out.writeInt(poffset);
}
}
}
int size() {
return size;
}
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import sun.misc.JavaNioAccess;
import sun.misc.SharedSecrets;
final class ImageNativeSubstrate implements ImageSubstrate {
private static final JavaNioAccess NIOACCESS =
SharedSecrets.getJavaNioAccess();
private final long id;
private final long indexAddress;
private final long dataAddress;
native static long openImage(String imagePath, boolean bigEndian);
native static void closeImage(long id);
native static long getIndexAddress(long id);
native static long getDataAddress(long id);
native static boolean readCompressed(long id, long offset,
ByteBuffer compressedBuffer, long compressedSize,
ByteBuffer uncompressedBuffer, long uncompressedSize);
native static boolean read(long id, long offset,
ByteBuffer uncompressedBuffer, long uncompressedSize);
native static byte[] getStringBytes(long id, int offset);
native static long[] getAttributes(long id, int offset);
native static long[] findAttributes(long id, byte[] path);
native static int[] attributeOffsets(long id);
static ByteBuffer newDirectByteBuffer(long address, long capacity) {
assert capacity < Integer.MAX_VALUE;
return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null);
}
private ImageNativeSubstrate(long id) {
this.id = id;
this.indexAddress = getIndexAddress(id);
this.dataAddress = getDataAddress(id);
}
static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder)
throws IOException {
long id = openImage(imagePath, byteOrder == ByteOrder.BIG_ENDIAN);
if (id == 0) {
throw new IOException("Image not found \"" + imagePath + "\"");
}
return new ImageNativeSubstrate(id);
}
@Override
public void close() {
closeImage(id);
}
@Override
public ByteBuffer getIndexBuffer(long offset, long size) {
return newDirectByteBuffer(indexAddress + offset, size);
}
@Override
public ByteBuffer getDataBuffer(long offset, long size) {
return dataAddress != 0 ?
newDirectByteBuffer(dataAddress + offset, size) : null;
}
@Override
public boolean supportsDataBuffer() {
return dataAddress != 0;
}
@Override
public boolean read(long offset,
ByteBuffer compressedBuffer, long compressedSize,
ByteBuffer uncompressedBuffer, long uncompressedSize) {
return readCompressed(id, offset,
compressedBuffer, compressedSize,
uncompressedBuffer, uncompressedSize);
}
@Override
public boolean read(long offset,
ByteBuffer uncompressedBuffer, long uncompressedSize) {
return read(id, offset, uncompressedBuffer, uncompressedSize);
}
@Override
public byte[] getStringBytes(int offset) {
return getStringBytes(id, offset);
}
@Override
public long[] getAttributes(int offset) {
return getAttributes(id, offset);
}
@Override
public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) {
long[] attributes = findAttributes(id, name.getBytes());
return attributes != null ? new ImageLocation(attributes, strings) : null;
}
@Override
public int[] attributeOffsets() {
return attributeOffsets(id);
}
}

View File

@ -26,12 +26,10 @@ package jdk.internal.jimage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.file.Files;
import java.nio.file.FileSystem;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.nio.file.Paths;
@ -42,13 +40,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
import static jdk.internal.jimage.UTF8String.*;
public class ImageReader extends BasicImageReader {
// well-known strings needed for image file system.
static final UTF8String ROOT = new UTF8String("/");
static final UTF8String META_INF = new UTF8String("/META-INF");
static final UTF8String PACKAGES_OFFSETS = new UTF8String("packages.offsets");
static final UTF8String ROOT_STRING = UTF8String.SLASH_STRING;
// attributes of the .jimage file. jimage file does not contain
// attributes for the individual resources (yet). We use attributes
@ -56,15 +52,18 @@ public class ImageReader extends BasicImageReader {
// Iniitalized lazily, see {@link #imageFileAttributes()}.
private BasicFileAttributes imageFileAttributes;
private final Map<String, String> packageMap;
private final ImageModuleData moduleData;
// directory management implementation
private final Map<UTF8String, Node> nodes;
private volatile Directory rootDir;
private Directory packagesDir;
private Directory modulesDir;
ImageReader(String imagePath, ByteOrder byteOrder) throws IOException {
super(imagePath, byteOrder);
this.packageMap = PackageModuleMap.readFrom(this);
this.moduleData = new ImageModuleData(this);
this.nodes = Collections.synchronizedMap(new HashMap<>());
}
@ -89,11 +88,42 @@ public class ImageReader extends BasicImageReader {
clearNodes();
}
@Override
public ImageLocation findLocation(UTF8String name) {
ImageLocation location = super.findLocation(name);
// NOTE: This should be removed when module system is up in full.
if (location == null) {
int index = name.lastIndexOf('/');
if (index != -1) {
UTF8String packageName = name.substring(0, index);
UTF8String moduleName = moduleData.packageToModule(packageName);
if (moduleName != null) {
UTF8String fullName = UTF8String.SLASH_STRING.concat(moduleName,
UTF8String.SLASH_STRING, name);
location = super.findLocation(fullName);
}
} else {
// No package, try all modules.
for (String mod : moduleData.allModuleNames()) {
location = super.findLocation("/" + mod + "/" + name);
if (location != null) {
break;
}
}
}
}
return location;
}
/**
* Return the module name that contains the given package name.
*/
public String getModule(String pkg) {
return packageMap.get(pkg);
public String getModule(String packageName) {
return moduleData.packageToModule(packageName);
}
// jimage file does not store directory structure. We build nodes
@ -101,14 +131,13 @@ public class ImageReader extends BasicImageReader {
// Node can be a directory or a resource
public static abstract class Node {
private static final int ROOT_DIR = 0b0000_0000_0000_0001;
private static final int MODULE_DIR = 0b0000_0000_0000_0010;
private static final int METAINF_DIR = 0b0000_0000_0000_0100;
private static final int TOPLEVEL_PKG_DIR = 0b0000_0000_0000_1000;
private static final int HIDDEN = 0b0000_0000_0001_0000;
private static final int PACKAGES_DIR = 0b0000_0000_0000_0010;
private static final int MODULES_DIR = 0b0000_0000_0000_0100;
private int flags;
private final UTF8String name;
private final BasicFileAttributes fileAttrs;
private boolean completed;
Node(UTF8String name, BasicFileAttributes fileAttrs) {
assert name != null;
@ -117,6 +146,19 @@ public class ImageReader extends BasicImageReader {
this.fileAttrs = fileAttrs;
}
/**
* A node is completed when all its direct children have been built.
*
* @return
*/
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
public final void setIsRootDir() {
flags |= ROOT_DIR;
}
@ -125,40 +167,20 @@ public class ImageReader extends BasicImageReader {
return (flags & ROOT_DIR) != 0;
}
public final void setIsModuleDir() {
flags |= MODULE_DIR;
public final void setIsPackagesDir() {
flags |= PACKAGES_DIR;
}
public final boolean isModuleDir() {
return (flags & MODULE_DIR) != 0;
public final boolean isPackagesDir() {
return (flags & PACKAGES_DIR) != 0;
}
public final void setIsMetaInfDir() {
flags |= METAINF_DIR;
public final void setIsModulesDir() {
flags |= MODULES_DIR;
}
public final boolean isMetaInfDir() {
return (flags & METAINF_DIR) != 0;
}
public final void setIsTopLevelPackageDir() {
flags |= TOPLEVEL_PKG_DIR;
}
public final boolean isTopLevelPackageDir() {
return (flags & TOPLEVEL_PKG_DIR) != 0;
}
public final void setIsHidden() {
flags |= HIDDEN;
}
public final boolean isHidden() {
return (flags & HIDDEN) != 0;
}
public final boolean isVisible() {
return !isHidden();
public final boolean isModulesDir() {
return (flags & MODULES_DIR) != 0;
}
public final UTF8String getName() {
@ -169,6 +191,20 @@ public class ImageReader extends BasicImageReader {
return fileAttrs;
}
// resolve this Node (if this is a soft link, get underlying Node)
public final Node resolveLink() {
return resolveLink(false);
}
public Node resolveLink(boolean recursive) {
return this;
}
// is this a soft link Node?
public boolean isLink() {
return false;
}
public boolean isDirectory() {
return false;
}
@ -242,16 +278,20 @@ public class ImageReader extends BasicImageReader {
}
// directory node - directory has full path name without '/' at end.
public static final class Directory extends Node {
static final class Directory extends Node {
private final List<Node> children;
@SuppressWarnings("LeakingThisInConstructor")
Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) {
private Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) {
super(name, fileAttrs);
children = new ArrayList<>();
}
static Directory create(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) {
Directory dir = new Directory(parent, name, fileAttrs);
if (parent != null) {
parent.addChild(this);
parent.addChild(dir);
}
return dir;
}
@Override
@ -259,6 +299,7 @@ public class ImageReader extends BasicImageReader {
return true;
}
@Override
public List<Node> getChildren() {
return Collections.unmodifiableList(children);
}
@ -281,19 +322,33 @@ public class ImageReader extends BasicImageReader {
// "resource" is .class or any other resource (compressed/uncompressed) in a jimage.
// full path of the resource is the "name" of the resource.
public static class Resource extends Node {
static class Resource extends Node {
private final ImageLocation loc;
@SuppressWarnings("LeakingThisInConstructor")
Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
this(parent, ROOT.concat(loc.getFullname()), loc, fileAttrs);
private Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
this(parent, loc.getFullName(true), loc, fileAttrs);
}
@SuppressWarnings("LeakingThisInConstructor")
Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) {
private Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) {
super(name, fileAttrs);
this.loc = loc;
parent.addChild(this);
}
static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) {
Resource resource = new Resource(parent, loc, fileAttrs);
parent.addChild(resource);
return resource;
}
static Resource create(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) {
Resource resource = new Resource(parent, name, loc, fileAttrs);
parent.addChild(resource);
return resource;
}
@Override
public boolean isCompleted() {
return true;
}
@Override
@ -327,6 +382,37 @@ public class ImageReader extends BasicImageReader {
}
}
// represents a soft link to another Node
static class LinkNode extends Node {
private final Node link;
private LinkNode(Directory parent, UTF8String name, Node link) {
super(name, link.getFileAttributes());
this.link = link;
}
static LinkNode create(Directory parent, UTF8String name, Node link) {
LinkNode linkNode = new LinkNode(parent, name, link);
parent.addChild(linkNode);
return linkNode;
}
@Override
public boolean isCompleted() {
return true;
}
@Override
public Node resolveLink(boolean recursive) {
return recursive && (link instanceof LinkNode)? ((LinkNode)link).resolveLink(true) : link;
}
@Override
public boolean isLink() {
return true;
}
}
// directory management interface
public Directory getRootDirectory() {
return buildRootDirectory();
@ -340,9 +426,154 @@ public class ImageReader extends BasicImageReader {
return findNode(new UTF8String(name));
}
/**
* To visit sub tree resources.
*/
interface LocationVisitor {
void visit(ImageLocation loc);
}
/**
* Lazily build a node from a name.
*/
private final class NodeBuilder {
private static final int SIZE_OF_OFFSET = 4;
private final UTF8String name;
private NodeBuilder(UTF8String name) {
this.name = name;
}
private Node buildNode() {
Node n = null;
boolean isPackages = false;
boolean isModules = false;
String strName = name.toString();
if (strName.startsWith("" + PACKAGES_STRING)) {
isPackages = true;
} else {
if (strName.startsWith("" + MODULES_STRING)) {
isModules = true;
}
}
if (!isModules && !isPackages) {
return null;
}
ImageLocation loc = findLocation(name);
if (loc != null) { // A sub tree node
if (isPackages) {
n = handlePackages(strName, loc);
} else { // modules sub tree
n = handleModulesSubTree(strName, loc);
}
} else { // Asking for a resource? /modules/java.base/java/lang/Object.class
if (isModules) {
n = handleResource(strName, loc);
}
}
return n;
}
private void visitLocation(ImageLocation loc, LocationVisitor visitor) {
byte[] offsets = getResource(loc);
ByteBuffer buffer = ByteBuffer.wrap(offsets);
buffer.order(getByteOrder());
IntBuffer intBuffer = buffer.asIntBuffer();
for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) {
int offset = intBuffer.get(i);
ImageLocation pkgLoc = getLocation(offset);
visitor.visit(pkgLoc);
}
}
private Node handlePackages(String name, ImageLocation loc) {
long size = loc.getUncompressedSize();
Node n = null;
// Only possiblities are /packages, /packages/package/module
if (name.equals("" + PACKAGES_STRING)) {
visitLocation(loc, (childloc) -> {
findNode(childloc.getFullName());
});
packagesDir.setCompleted(true);
n = packagesDir;
} else {
if (size != 0) { // children are links to module
String pkgName = getBaseExt(loc);
Directory pkgDir = newDirectory(packagesDir,
packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName)));
visitLocation(loc, (childloc) -> {
findNode(childloc.getFullName());
});
pkgDir.setCompleted(true);
n = pkgDir;
} else { // Link to module
String pkgName = loc.getParentString();
String modName = getBaseExt(loc);
Node targetNode = findNode(MODULES_STRING + "/" + modName);
if (targetNode != null) {
UTF8String pkgDirName = packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName));
Directory pkgDir = (Directory) nodes.get(pkgDirName);
Node linkNode = newLinkNode(pkgDir,
pkgDir.getName().concat(SLASH_STRING, new UTF8String(modName)), targetNode);
n = linkNode;
}
}
}
return n;
}
private Node handleModulesSubTree(String name, ImageLocation loc) {
Node n;
Directory dir = makeDirectories(loc.getFullName());
visitLocation(loc, (childloc) -> {
String path = childloc.getFullNameString();
if (path.startsWith(MODULES_STRING.toString())) { // a package
makeDirectories(childloc.getFullName());
} else { // a resource
makeDirectories(childloc.buildName(true, true, false));
newResource(dir, childloc);
}
});
dir.setCompleted(true);
n = dir;
return n;
}
private Node handleResource(String name, ImageLocation loc) {
Node n = null;
String locationPath = name.substring((MODULES_STRING).length());
ImageLocation resourceLoc = findLocation(locationPath);
if (resourceLoc != null) {
Directory dir = makeDirectories(resourceLoc.buildName(true, true, false));
Resource res = newResource(dir, resourceLoc);
n = res;
}
return n;
}
private String getBaseExt(ImageLocation loc) {
String base = loc.getBaseString();
String ext = loc.getExtensionString();
if (ext != null && !ext.isEmpty()) {
base = base + "." + ext;
}
return base;
}
}
public synchronized Node findNode(UTF8String name) {
buildRootDirectory();
return nodes.get(name);
Node n = nodes.get(name);
if (n == null || !n.isCompleted()) {
NodeBuilder builder = new NodeBuilder(name);
n = builder.buildNode();
}
return n;
}
private synchronized void clearNodes() {
@ -375,65 +606,61 @@ public class ImageReader extends BasicImageReader {
// FIXME no time information per resource in jimage file (yet?)
// we use file attributes of jimage itself.
// root directory
rootDir = new Directory(null, ROOT, imageFileAttributes());
rootDir = newDirectory(null, ROOT_STRING);
rootDir.setIsRootDir();
nodes.put(rootDir.getName(), rootDir);
ImageLocation[] locs = getAllLocations(true);
for (ImageLocation loc : locs) {
UTF8String parent = loc.getParent();
// directory where this location goes as child
Directory dir;
if (parent == null || parent.isEmpty()) {
// top level entry under root
dir = rootDir;
} else {
int idx = parent.lastIndexOf('/');
assert idx != -1 : "invalid parent string";
UTF8String name = ROOT.concat(parent.substring(0, idx));
dir = (Directory) nodes.get(name);
if (dir == null) {
// make all parent directories (as needed)
dir = makeDirectories(parent);
}
}
Resource entry = new Resource(dir, loc, imageFileAttributes());
nodes.put(entry.getName(), entry);
}
// /packages dir
packagesDir = newDirectory(rootDir, PACKAGES_STRING);
packagesDir.setIsPackagesDir();
Node metaInf = nodes.get(META_INF);
if (metaInf instanceof Directory) {
metaInf.setIsMetaInfDir();
((Directory)metaInf).walk(Node::setIsHidden);
}
fillPackageModuleInfo();
// /modules dir
modulesDir = newDirectory(rootDir, MODULES_STRING);
modulesDir.setIsModulesDir();
rootDir.setCompleted(true);
return rootDir;
}
private Directory newDirectory(Directory parent, UTF8String name) {
Directory dir = new Directory(parent, name, imageFileAttributes());
Directory dir = Directory.create(parent, name, imageFileAttributes());
nodes.put(dir.getName(), dir);
return dir;
}
private Directory makeDirectories(UTF8String parent) {
assert !parent.isEmpty() : "non empty parent expected";
private Resource newResource(Directory parent, ImageLocation loc) {
Resource res = Resource.create(parent, loc, imageFileAttributes());
nodes.put(res.getName(), res);
return res;
}
int idx = parent.indexOf('/');
assert idx != -1 : "invalid parent string";
UTF8String name = ROOT.concat(parent.substring(0, idx));
Directory top = (Directory) nodes.get(name);
if (top == null) {
top = newDirectory(rootDir, name);
private LinkNode newLinkNode(Directory dir, UTF8String name, Node link) {
LinkNode linkNode = LinkNode.create(dir, name, link);
nodes.put(linkNode.getName(), linkNode);
return linkNode;
}
private List<UTF8String> dirs(UTF8String parent) {
List<UTF8String> splits = new ArrayList<>();
for (int i = 1; i < parent.length(); i++) {
if (parent.byteAt(i) == '/') {
splits.add(parent.substring(0, i));
}
}
Directory last = top;
while ((idx = parent.indexOf('/', idx + 1)) != -1) {
name = ROOT.concat(parent.substring(0, idx));
Directory nextDir = (Directory) nodes.get(name);
splits.add(parent);
return splits;
}
private Directory makeDirectories(UTF8String parent) {
Directory last = rootDir;
List<UTF8String> dirs = dirs(parent);
for (UTF8String dir : dirs) {
Directory nextDir = (Directory) nodes.get(dir);
if (nextDir == null) {
nextDir = newDirectory(last, name);
nextDir = newDirectory(last, dir);
}
last = nextDir;
}
@ -441,54 +668,6 @@ public class ImageReader extends BasicImageReader {
return last;
}
private void fillPackageModuleInfo() {
assert rootDir != null;
packageMap.entrySet().stream().sorted((x, y)->x.getKey().compareTo(y.getKey())).forEach((entry) -> {
UTF8String moduleName = new UTF8String("/" + entry.getValue());
UTF8String fullName = moduleName.concat(new UTF8String(entry.getKey() + "/"));
if (! nodes.containsKey(fullName)) {
Directory module = (Directory) nodes.get(moduleName);
assert module != null : "module directory missing " + moduleName;
module.setIsModuleDir();
// hide "packages.offsets" in module directories
Node packagesOffsets = nodes.get(moduleName.concat(ROOT, PACKAGES_OFFSETS));
if (packagesOffsets != null) {
packagesOffsets.setIsHidden();
}
// package name without front '/'
UTF8String pkgName = new UTF8String(entry.getKey() + "/");
int idx = -1;
Directory moduleSubDir = module;
while ((idx = pkgName.indexOf('/', idx + 1)) != -1) {
UTF8String subPkg = pkgName.substring(0, idx);
UTF8String moduleSubDirName = moduleName.concat(ROOT, subPkg);
Directory tmp = (Directory) nodes.get(moduleSubDirName);
if (tmp == null) {
moduleSubDir = newDirectory(moduleSubDir, moduleSubDirName);
} else {
moduleSubDir = tmp;
}
}
// copy pkgDir "resources"
Directory pkgDir = (Directory) nodes.get(ROOT.concat(pkgName.substring(0, pkgName.length() - 1)));
pkgDir.setIsTopLevelPackageDir();
pkgDir.walk(n -> n.setIsHidden());
for (Node child : pkgDir.getChildren()) {
if (child.isResource()) {
ImageLocation loc = child.getLocation();
BasicFileAttributes imageFileAttrs = child.getFileAttributes();
UTF8String rsName = moduleName.concat(child.getName());
Resource rs = new Resource(moduleSubDir, rsName, loc, imageFileAttrs);
nodes.put(rs.getName(), rs);
}
}
}
});
}
public byte[] getResource(Node node) throws IOException {
if (node.isResource()) {
return super.getResource(node.getLocation());

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
/**
* Factory to get ImageReader
*/
public class ImageReaderFactory {
private ImageReaderFactory() {}
private static final String JAVA_HOME = System.getProperty("java.home");
private static final Path BOOT_MODULES_JIMAGE =
Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage");
private static final Map<Path, ImageReader> readers = new ConcurrentHashMap<>();
/**
* Returns an {@code ImageReader} to read from the given image file
*/
public static ImageReader get(Path jimage) throws IOException {
ImageReader reader = readers.get(jimage);
if (reader != null) {
return reader;
}
reader = ImageReader.open(jimage.toString());
// potential race with other threads opening the same URL
ImageReader r = readers.putIfAbsent(jimage, reader);
if (r == null) {
return reader;
} else {
reader.close();
return r;
}
}
/**
* Returns the {@code ImageReader} to read the image file in this
* run-time image.
*
* @throws UncheckedIOException if an I/O error occurs
*/
public static ImageReader getImageReader() {
try {
return get(BOOT_MODULES_JIMAGE);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
}

View File

@ -0,0 +1,344 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* A class to build a sorted tree of Resource paths as a tree of ImageLocation.
*
*/
// XXX Public only due to the JImageTask / JImageTask code duplication
public final class ImageResourcesTree {
private static final String MODULES = "modules";
private static final String PACKAGES = "packages";
public static final String MODULES_STRING = UTF8String.MODULES_STRING.toString();
public static final String PACKAGES_STRING = UTF8String.PACKAGES_STRING.toString();
public static boolean isTreeInfoResource(String path) {
return path.startsWith(PACKAGES_STRING) || path.startsWith(MODULES_STRING);
}
/**
* Path item tree node.
*/
private static final class Node {
private final String name;
private final Map<String, Node> children = new TreeMap<>();
private final Node parent;
private ImageLocationWriter loc;
private Node(String name, Node parent) {
this.name = name;
this.parent = parent;
if (parent != null) {
parent.children.put(name, this);
}
}
public String getPath() {
if (parent == null) {
return "/";
}
return buildPath(this);
}
public String getName() {
return name;
}
public Node getChildren(String name) {
Node item = children.get(name);
return item;
}
private static String buildPath(Node item) {
if (item == null) {
return null;
}
String path = buildPath(item.parent);
if (path == null) {
return item.getName();
} else {
return path + "/" + item.getName();
}
}
}
/**
* Tree of nodes.
*/
private static final class Tree {
private final Map<String, Node> directAccess = new HashMap<>();
private final List<String> paths;
private final Node root;
private Node modules;
private Node packages;
private Tree(List<String> paths) {
this.paths = paths;
root = new Node("", null);
buildTree();
}
private void buildTree() {
modules = new Node(MODULES, root);
directAccess.put(modules.getPath(), modules);
Map<String, Set<String>> moduleToPackage = new TreeMap<>();
Map<String, Set<String>> packageToModule = new TreeMap<>();
for (String p : paths) {
if (!p.startsWith("/")) {
continue;
}
String[] split = p.split("/");
Node current = modules;
String module = null;
for (int i = 0; i < split.length; i++) {
String s = split[i];
if (!s.isEmpty()) {
if (module == null) {
module = s;
}
Node n = current.children.get(s);
if (n == null) {
n = new Node(s, current);
if (i == split.length - 1) { // Leaf
String pkg = toPackageName(n.parent);
if (pkg != null && !pkg.startsWith("META-INF")) {
Set<String> pkgs = moduleToPackage.get(module);
if (pkgs == null) {
pkgs = new TreeSet<>();
moduleToPackage.put(module, pkgs);
}
pkgs.add(pkg);
}
} else { // put only sub trees, no leaf
directAccess.put(n.getPath(), n);
String pkg = toPackageName(n);
if (pkg != null && !pkg.startsWith("META-INF")) {
Set<String> mods = packageToModule.get(pkg);
if (mods == null) {
mods = new TreeSet<>();
packageToModule.put(pkg, mods);
}
mods.add(module);
}
}
}
current = n;
}
}
}
packages = new Node(PACKAGES, root);
directAccess.put(packages.getPath(), packages);
for (Map.Entry<String, Set<String>> entry : moduleToPackage.entrySet()) {
for (String pkg : entry.getValue()) {
Node pkgNode = new Node(pkg, packages);
directAccess.put(pkgNode.getPath(), pkgNode);
Node modNode = new Node(entry.getKey(), pkgNode);
directAccess.put(modNode.getPath(), modNode);
}
}
for (Map.Entry<String, Set<String>> entry : packageToModule.entrySet()) {
Node pkgNode = new Node(entry.getKey(), packages);
directAccess.put(pkgNode.getPath(), pkgNode);
for (String module : entry.getValue()) {
Node modNode = new Node(module, pkgNode);
directAccess.put(modNode.getPath(), modNode);
}
}
}
public String toResourceName(Node node) {
if (!node.children.isEmpty()) {
throw new RuntimeException("Node is not a resource");
}
return removeRadical(node);
}
public String getModule(Node node) {
if (node.parent == null || node.getName().equals(MODULES) ||
node.getName().startsWith(PACKAGES)) {
return null;
}
String path = removeRadical(node);
// "/xxx/...";
path = path.substring(1);
int i = path.indexOf("/");
if (i == -1) {
return path;
} else {
return path.substring(0, i);
}
}
public String toPackageName(Node node) {
if (node.parent == null) {
return null;
}
String path = removeRadical(node.getPath(), "/" + MODULES + "/");
String module = getModule(node);
if (path.equals(module)) {
return null;
}
String pkg = removeRadical(path, module + "/");
return pkg.replaceAll("/", ".");
}
public String removeRadical(Node node) {
String s = node.getPath();
return removeRadical(node.getPath(), "/" + MODULES);
}
private String removeRadical(String path, String str) {
return path.substring(str.length());
}
public Node getRoot() {
return root;
}
public Map<String, Node> getMap() {
return directAccess;
}
private boolean isPackageNode(Node node) {
if (!node.children.isEmpty()) {
throw new RuntimeException("Node is not a package");
}
return node.getPath().startsWith("/" + PACKAGES);
}
}
private static final class LocationsAdder {
private long offset;
private final List<byte[]> content = new ArrayList<>();
private final BasicImageWriter writer;
private final Tree tree;
LocationsAdder(Tree tree, long offset, BasicImageWriter writer) {
this.tree = tree;
this.offset = offset;
this.writer = writer;
addLocations(tree.getRoot());
}
private int addLocations(Node current) {
int[] ret = new int[current.children.size()];
int i = 0;
for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
ret[i] = addLocations(entry.getValue());
i += 1;
}
if (current != tree.getRoot() && (ret.length > 0 || tree.isPackageNode(current))) {
int size = ret.length * 4;
writer.addLocation(current.getPath(), offset, 0, size);
offset += size;
}
return 0;
}
private List<byte[]> computeContent() {
// Map used to associate Tree item with locations offset.
Map<String, ImageLocationWriter> outLocations = new HashMap<>();
for (ImageLocationWriter wr : writer.getLocations()) {
outLocations.put(wr.getFullNameString(), wr);
}
// Attach location to node
for (Map.Entry<String, ImageLocationWriter> entry : outLocations.entrySet()) {
Node item = tree.getMap().get(entry.getKey());
if (item != null) {
item.loc = entry.getValue();
}
}
computeContent(tree.getRoot(), outLocations);
return content;
}
private int computeContent(Node current, Map<String, ImageLocationWriter> outLocations) {
int[] ret = new int[current.children.size()];
int i = 0;
for (java.util.Map.Entry<String, Node> entry : current.children.entrySet()) {
ret[i] = computeContent(entry.getValue(), outLocations);
i += 1;
}
if (ret.length > 0) {
int size = ret.length * 4;
ByteBuffer buff = ByteBuffer.allocate(size);
buff.order(writer.getByteOrder());
for (int val : ret) {
buff.putInt(val);
}
byte[] arr = buff.array();
content.add(arr);
} else {
if (tree.isPackageNode(current)) {
current.loc = outLocations.get(current.getPath());
} else {
String s = tree.toResourceName(current);
current.loc = outLocations.get(s);
}
}
return current == tree.getRoot() ? 0 : current.loc.getLocationOffset();
}
}
private final List<String> paths;
private final LocationsAdder adder;
public ImageResourcesTree(long offset, BasicImageWriter writer, List<String> paths) {
this.paths = new ArrayList<>();
this.paths.addAll(paths);
Collections.sort(this.paths);
Tree tree = new Tree(this.paths);
adder = new LocationsAdder(tree, offset, writer);
}
public void addContent(DataOutputStream out) throws IOException {
List<byte[]> content = adder.computeContent();
for (byte[] c : content) {
out.write(c, 0, c.length);
}
}
}

View File

@ -72,7 +72,7 @@ class ImageStream {
return this;
}
private void ensure(int needs) {
void ensure(int needs) {
assert 0 <= needs : "Negative needs";
if (needs > buffer.remaining()) {

View File

@ -25,83 +25,8 @@
package jdk.internal.jimage;
import java.nio.ByteBuffer;
import java.util.HashMap;
interface ImageStrings {
public UTF8String get(int offset);
class ImageStrings {
private static final int NOT_FOUND = -1;
static final int EMPTY_OFFSET = 0;
private final HashMap<UTF8String, Integer> stringToOffsetMap;
private final ImageStream stream;
ImageStrings() {
this.stringToOffsetMap = new HashMap<>();
this.stream = new ImageStream();
// Reserve 0 offset for empty string.
int offset = addString(UTF8String.EMPTY_STRING);
assert offset == 0 : "Empty string not zero offset";
// Reserve 1 offset for frequently used ".class".
addString(UTF8String.CLASS_STRING);
}
ImageStrings(ImageStream stream) {
this.stringToOffsetMap = new HashMap<>();
this.stream = stream;
}
private int addString(final UTF8String string) {
int offset = stream.getPosition();
string.writeTo(stream);
stream.put('\0');
stringToOffsetMap.put(string, offset);
return offset;
}
int add(final UTF8String string) {
int offset = find(string);
return offset == NOT_FOUND ? addString(string) : offset;
}
int find(final UTF8String string) {
Integer offset = stringToOffsetMap.get(string);
return offset != null ? offset : NOT_FOUND;
}
UTF8String get(int offset) {
ByteBuffer buffer = stream.getBuffer();
assert 0 <= offset && offset < buffer.capacity() : "String buffer offset out of range";
int zero = NOT_FOUND;
for (int i = offset; i < buffer.capacity(); i++) {
if (buffer.get(i) == '\0') {
zero = i;
break;
}
}
assert zero != UTF8String.NOT_FOUND;
int length = zero - offset;
byte[] bytes = new byte[length];
int mark = buffer.position();
buffer.position(offset);
buffer.get(bytes);
buffer.position(mark);
return new UTF8String(bytes, 0, length);
}
ImageStream getStream() {
return stream;
}
int getSize() {
return stream.getSize();
}
int getCount() {
return stringToOffsetMap.size();
}
public int add(final UTF8String string);
}

View File

@ -22,46 +22,23 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
/**
* Resource is a class or resource file.
*/
public class Resource {
private final String name;
private final long size;
private final long csize;
class ImageStringsReader implements ImageStrings {
private final BasicImageReader reader;
public Resource(String name, long size, long csize) {
this.name = name;
this.size = size;
this.csize = csize;
}
/**
* Returns the name of this entry.
*/
public String name() {
return name;
}
/**
* Returns the number of uncompressed bytes for this entry.
*/
public long size() {
return size;
}
/**
* Returns the number of compressed bytes for this entry; 0 if
* uncompressed.
*/
public long csize() {
return csize;
ImageStringsReader(BasicImageReader reader) {
this.reader = reader;
}
@Override
public String toString() {
return String.format("%s uncompressed size %d compressed size %d", name, size, csize);
public UTF8String get(int offset) {
return reader.getUTF8String(offset);
}
@Override
public int add(final UTF8String string) {
throw new InternalError("Can not add strings at runtime");
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.nio.ByteBuffer;
import java.util.HashMap;
class ImageStringsWriter implements ImageStrings {
private static final int NOT_FOUND = -1;
static final int EMPTY_OFFSET = 0;
static final UTF8String CLASS_STRING = new UTF8String("class");
private final HashMap<UTF8String, Integer> stringToOffsetMap;
private final ImageStream stream;
ImageStringsWriter() {
this.stringToOffsetMap = new HashMap<>();
this.stream = new ImageStream();
// Reserve 0 offset for empty string.
int offset = addString(UTF8String.EMPTY_STRING);
assert offset == 0 : "Empty string not zero offset";
// Reserve 1 offset for frequently used ".class".
addString(CLASS_STRING);
}
private int addString(final UTF8String string) {
int offset = stream.getPosition();
string.writeTo(stream);
stream.put('\0');
stringToOffsetMap.put(string, offset);
return offset;
}
@Override
public int add(final UTF8String string) {
int offset = find(string);
return offset == NOT_FOUND ? addString(string) : offset;
}
int find(final UTF8String string) {
Integer offset = stringToOffsetMap.get(string);
return offset != null ? offset : NOT_FOUND;
}
@Override
public UTF8String get(int offset) {
ByteBuffer buffer = stream.getBuffer();
assert 0 <= offset && offset < buffer.capacity() : "String buffer offset out of range";
int zero = NOT_FOUND;
for (int i = offset; i < buffer.capacity(); i++) {
if (buffer.get(i) == '\0') {
zero = i;
break;
}
}
assert zero != UTF8String.NOT_FOUND;
int length = zero - offset;
byte[] bytes = new byte[length];
int mark = buffer.position();
buffer.position(offset);
buffer.get(bytes);
buffer.position(mark);
return new UTF8String(bytes, 0, length);
}
ImageStream getStream() {
return stream;
}
int getSize() {
return stream.getSize();
}
int getCount() {
return stringToOffsetMap.size();
}
}

View File

@ -22,41 +22,24 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.IOException;
import java.io.Closeable;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// Utility to read module info from .jimage file.
public final class PackageModuleMap {
private PackageModuleMap() {}
public static final String MODULES_ENTRY = "module/modules.offsets";
public static final String PACKAGES_ENTRY = "packages.offsets";
/*
* Returns a package-to-module map.
*
* The package name is in binary name format.
*/
static Map<String,String> readFrom(ImageReader reader) throws IOException {
Map<String,String> result = new HashMap<>();
List<String> moduleNames = reader.getNames(MODULES_ENTRY);
for (String moduleName : moduleNames) {
List<String> packageNames = reader.getNames(moduleName + "/" + PACKAGES_ENTRY);
for (String packageName : packageNames) {
result.put(packageName, moduleName);
}
}
return result;
}
interface ImageSubstrate extends Closeable {
@Override
void close();
boolean supportsDataBuffer();
ByteBuffer getIndexBuffer(long offset, long size);
ByteBuffer getDataBuffer(long offset, long size);
boolean read(long offset,
ByteBuffer compressedBuffer, long compressedSize,
ByteBuffer uncompressedBuffer, long uncompressedSize);
boolean read(long offset,
ByteBuffer uncompressedBuffer, long uncompressedSize);
byte[] getStringBytes(int offset);
long[] getAttributes(int offset);
ImageLocation findLocation(UTF8String name, ImageStringsReader strings);
int[] attributeOffsets();
}

View File

@ -1,139 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.io.Closeable;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Supports reading a file from given positions (offsets) in the file.
*/
public abstract class PReader implements Closeable {
private final FileChannel fc;
protected PReader(FileChannel fc) {
this.fc = fc;
}
/**
* Returns the {@code FileChannel}.
*/
final FileChannel channel() {
return fc;
}
/**
* Closes this {@code PReader} and the underlying file.
*/
@Override
public final void close() throws IOException {
fc.close();
}
/**
* Returns {@code true} if this {@code PReader} and the underlying file is
* open.
*/
public final boolean isOpen() {
return fc.isOpen();
}
/**
* Returns {@code len} bytes from a given position in the file. The bytes
* are returned as a byte array.
*
* @throws IOException if an I/O error occurs
*/
public abstract byte[] read(int len, long position) throws IOException;
/**
* Opens the given file, returning a {@code PReader} to read from the file.
*
* @implNote Returns a {@code PReader} that supports concurrent pread operations
* if possible, otherwise a simple {@code PReader} that doesn't support
* concurrent operations.
*/
static PReader open(String file) throws IOException {
Class<?> clazz;
try {
clazz = Class.forName("jdk.internal.jimage.concurrent.ConcurrentPReader");
} catch (ClassNotFoundException e) {
return new SimplePReader(file);
}
try {
Constructor<?> ctor = clazz.getConstructor(String.class);
return (PReader) ctor.newInstance(file);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException)
throw (IOException) cause;
if (cause instanceof Error)
throw (Error) cause;
if (cause instanceof RuntimeException)
throw (RuntimeException) cause;
throw new Error(e);
} catch (NoSuchMethodException | IllegalAccessException |
InstantiationException e) {
throw new InternalError(e);
}
}
}
/**
* Simple PReader implementation based on {@code RandomAccessFile}.
*
* @implNote This class cannot use FileChannel read methods to do the
* positional reads because FileChannel is interruptible.
*/
class SimplePReader extends PReader {
private final RandomAccessFile raf;
private SimplePReader(RandomAccessFile raf) throws IOException {
super(raf.getChannel());
this.raf = raf;
}
SimplePReader(String file) throws IOException {
this(new RandomAccessFile(file, "r"));
}
@Override
public byte[] read(int len, long position) throws IOException {
synchronized (this) {
byte[] bytes = new byte[len];
raf.seek(position);
int n = raf.read(bytes);
if (n != len)
throw new InternalError("short read, not handled yet");
return bytes;
}
}
}

View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class PerfectHashBuilder<E> {
private final static int RETRY_LIMIT = 1000;
private Class<?> entryComponent;
private Class<?> bucketComponent;
private final Map<UTF8String, Entry<E>> map = new LinkedHashMap<>();
private int[] redirect;
private Entry<E>[] order;
private int count = 0;
@SuppressWarnings("EqualsAndHashcode")
public static class Entry<E> {
private final UTF8String key;
private final E value;
Entry() {
this("", null);
}
Entry(String key, E value) {
this(new UTF8String(key), value);
}
Entry(UTF8String key, E value) {
this.key = key;
this.value = value;
}
UTF8String getKey() {
return key;
}
E getValue() {
return value;
}
int hashCode(int seed) {
return key.hashCode(seed);
}
@Override
public int hashCode() {
return key.hashCode();
}
}
static class Bucket<E> implements Comparable<Bucket<E>> {
final List<Entry<E>> list = new ArrayList<>();
void add(Entry<E> entry) {
list.add(entry);
}
int getSize() {
return list.size();
}
List<Entry<E>> getList() {
return list;
}
Entry<E> getFirst() {
assert !list.isEmpty() : "bucket should never be empty";
return list.get(0);
}
@Override
public int hashCode() {
return getFirst().hashCode();
}
@Override
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
public boolean equals(Object obj) {
return this == obj;
}
@Override
public int compareTo(Bucket<E> o) {
return o.getSize() - getSize();
}
}
public PerfectHashBuilder(Class<?> entryComponent, Class<?> bucketComponent) {
this.entryComponent = entryComponent;
this.bucketComponent = bucketComponent;
}
public int getCount() {
return map.size();
}
public int[] getRedirect() {
return redirect;
}
public Entry<E>[] getOrder() {
return order;
}
public Entry<E> put(String key, E value) {
return put(new UTF8String(key), value);
}
public Entry<E> put(UTF8String key, E value) {
return put(new Entry<>(key, value));
}
public Entry<E> put(Entry<E> entry) {
Entry<E> old = map.put(entry.key, entry);
if (old == null) {
count++;
}
return old;
}
@SuppressWarnings("unchecked")
public void generate() {
boolean redo = count != 0;
while (redo) {
redo = false;
redirect = new int[count];
order = (Entry<E>[])Array.newInstance(entryComponent, count);
Bucket<E>[] sorted = createBuckets();
int free = 0;
for (Bucket<E> bucket : sorted) {
if (bucket.getSize() != 1) {
if (!collidedEntries(bucket, count)) {
redo = true;
break;
}
} else {
for ( ; free < count && order[free] != null; free++) {}
if (free >= count) {
redo = true;
break;
}
order[free] = bucket.getFirst();
redirect[bucket.hashCode() % count] = -1 - free;
free++;
}
}
if (redo) {
count = (count + 1) | 1;
}
}
}
@SuppressWarnings("unchecked")
private Bucket<E>[] createBuckets() {
Bucket<E>[] buckets = (Bucket<E>[])Array.newInstance(bucketComponent, count);
map.values().stream().forEach((entry) -> {
int index = entry.hashCode() % count;
Bucket<E> bucket = buckets[index];
if (bucket == null) {
buckets[index] = bucket = new Bucket<>();
}
bucket.add(entry);
});
Bucket<E>[] sorted = Arrays.asList(buckets).stream()
.filter((bucket) -> (bucket != null))
.sorted()
.toArray((length) -> {
return (Bucket<E>[])Array.newInstance(bucketComponent, length);
});
return sorted;
}
private boolean collidedEntries(Bucket<E> bucket, int count) {
List<Integer> undo = new ArrayList<>();
int seed = UTF8String.HASH_MULTIPLIER + 1;
int retry = 0;
redo:
while (true) {
for (Entry<E> entry : bucket.getList()) {
int index = entry.hashCode(seed) % count;
if (order[index] != null) {
if (++retry > RETRY_LIMIT) {
return false;
}
undo.stream().forEach((i) -> {
order[i] = null;
});
undo.clear();
seed++;
if (seed == 0) {
seed = 1;
}
continue redo;
}
order[index] = entry;
undo.add(index);
}
redirect[bucket.hashCode() % count] = seed;
break;
}
return true;
}
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import jdk.internal.jimage.decompressor.CompressedResourceHeader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Pool of resources. This class contain the content of a jimage file in the
* matter of Resource.
*/
public interface ResourcePool {
/**
* Resources visitor
*/
public interface Visitor {
/**
* Called for each visited Resource.
*
* @param resource The resource to deal with.
* @param order Byte order
* @param strings
* @return A resource or null if the passed resource is to be removed
* from the jimage.
* @throws Exception
*/
public Resource visit(Resource resource, ByteOrder order,
StringTable strings) throws Exception;
}
/**
* A JImage Resource. Fully identified by its path.
*/
public static class Resource {
private final String path;
private final ByteBuffer content;
private final String module;
public Resource(String path, ByteBuffer content) {
Objects.requireNonNull(path);
Objects.requireNonNull(content);
this.path = path;
this.content = content.asReadOnlyBuffer();
String[] split = ImageFileCreator.splitPath(path);
module = split[0];
}
public String getPath() {
return path;
}
public String getModule() {
return module;
}
/**
* The resource content.
*
* @return A read only buffer.
*/
public ByteBuffer getContent() {
return content;
}
public int getLength() {
return content.limit();
}
public byte[] getByteArray() {
content.rewind();
byte[] array = new byte[content.remaining()];
content.get(array);
return array;
}
@Override
public String toString() {
return getPath();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Resource)) {
return false;
}
Resource res = (Resource) obj;
return res.path.equals(path);
}
@Override
public int hashCode() {
int hash = 7;
hash = 53 * hash + Objects.hashCode(this.path);
return hash;
}
}
/**
* A resource that has been compressed.
*/
public static final class CompressedResource extends Resource {
private final long uncompressed_size;
private CompressedResource(String path, ByteBuffer content,
long uncompressed_size) {
super(path, content);
this.uncompressed_size = uncompressed_size;
}
public long getUncompressedSize() {
return uncompressed_size;
}
public static CompressedResource newCompressedResource(Resource original,
ByteBuffer compressed,
String plugin, String pluginConfig, StringTable strings,
ByteOrder order) throws Exception {
Objects.requireNonNull(original);
Objects.requireNonNull(compressed);
Objects.requireNonNull(plugin);
boolean isTerminal = !(original instanceof CompressedResource);
long uncompressed_size = original.getLength();
if (original instanceof CompressedResource) {
CompressedResource comp = (CompressedResource) original;
uncompressed_size = comp.getUncompressedSize();
}
int nameOffset = strings.addString(plugin);
int configOffset = -1;
if (pluginConfig != null) {
configOffset = strings.addString(plugin);
}
CompressedResourceHeader rh =
new CompressedResourceHeader(compressed.limit(), original.getLength(),
nameOffset, configOffset, isTerminal);
// Merge header with content;
byte[] h = rh.getBytes(order);
ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length);
bb.order(order);
bb.put(h);
bb.put(compressed);
ByteBuffer contentWithHeader = ByteBuffer.wrap(bb.array());
CompressedResource compressedResource =
new CompressedResource(original.getPath(),
contentWithHeader, uncompressed_size);
return compressedResource;
}
}
/**
* Read only state.
*
* @return true if readonly false otherwise.
*/
public boolean isReadOnly();
/**
* The byte order
*
* @return
*/
public ByteOrder getByteOrder();
/**
* Add a resource.
*
* @param resource The Resource to add.
* @throws java.lang.Exception If the pool is read only.
*/
public void addResource(Resource resource) throws Exception;
/**
* Check if a resource is contained in the pool.
*
* @param res The resource to check.
* @return true if res is contained, false otherwise.
*/
public boolean contains(Resource res);
/**
* Get all resources contained in this pool instance.
*
* @return The collection of resources;
*/
public Collection<Resource> getResources();
/**
* Get the resource for the passed path.
*
* @param path A resource path
* @return A Resource instance or null if the resource is not found
*/
public Resource getResource(String path);
/**
* The Image modules. It is computed based on the resources contained by
* this ResourcePool instance.
*
* @return The Image Modules.
*/
public Map<String, Set<String>> getModulePackages();
/**
* Check if this pool contains some resources.
*
* @return True if contains some resources.
*/
public boolean isEmpty();
/**
* Visit the resources contained in this ResourcePool.
*
* @param visitor The visitor
* @param output The pool to store resources.
* @param strings
* @throws Exception
*/
public void visit(Visitor visitor, ResourcePool output, StringTable strings)
throws Exception;
public void addTransformedResource(Resource original, ByteBuffer transformed)
throws Exception;
}

View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* Pool of resources. This class contain the content of a jimage file in the
* matter of Resource.
*/
public class ResourcePoolImpl implements ResourcePool {
private final Map<String, Resource> resources = new LinkedHashMap<>();
private final ByteOrder order;
private boolean isReadOnly;
public ResourcePoolImpl(ByteOrder order) {
Objects.requireNonNull(order);
this.order = order;
}
/**
* Make this Resources instance read-only. No resource can be added.
*/
public void setReadOnly() {
isReadOnly = true;
}
/**
* Read only state.
*
* @return true if readonly false otherwise.
*/
@Override
public boolean isReadOnly() {
return isReadOnly;
}
/**
* The byte order
*
* @return
*/
@Override
public ByteOrder getByteOrder() {
return order;
}
/**
* Add a resource.
*
* @param resource The Resource to add.
* @throws java.lang.Exception If the pool is read only.
*/
@Override
public void addResource(Resource resource) throws Exception {
if (isReadOnly()) {
throw new Exception("pool is readonly");
}
Objects.requireNonNull(resource);
if (resources.get(resource.getPath()) != null) {
throw new Exception("Resource" + resource.getPath() +
" already present");
}
resources.put(resource.getPath(), resource);
}
/**
* Check if a resource is contained in the pool.
*
* @param res The resource to check.
* @return true if res is contained, false otherwise.
*/
@Override
public boolean contains(Resource res) {
Objects.requireNonNull(res);
try {
getResource(res.getPath());
return true;
} catch (Exception ex) {
return false;
}
}
/**
* Get all resources contained in this pool instance.
*
* @return The collection of resources;
*/
@Override
public Collection<Resource> getResources() {
return Collections.unmodifiableCollection(resources.values());
}
/**
* Get the resource for the passed path.
*
* @param path A resource path
* @return A Resource instance or null if the resource is not found
*/
@Override
public Resource getResource(String path) {
Objects.requireNonNull(path);
return resources.get(path);
}
/**
* The Image modules. It is computed based on the resources contained by
* this ResourcePool instance.
*
* @return The Image Modules.
*/
@Override
public Map<String, Set<String>> getModulePackages() {
Map<String, Set<String>> moduleToPackage = new LinkedHashMap<>();
retrieveModulesPackages(moduleToPackage);
return moduleToPackage;
}
/**
* Check if this pool contains some resources.
*
* @return True if contains some resources.
*/
@Override
public boolean isEmpty() {
return resources.isEmpty();
}
/**
* Visit the resources contained in this ResourcePool.
*
* @param visitor The visitor
* @param strings
* @throws Exception
*/
@Override
public void visit(Visitor visitor, ResourcePool output, StringTable strings)
throws Exception {
for (Resource resource : getResources()) {
Resource res = visitor.visit(resource, order, strings);
if (res != null) {
output.addResource(res);
}
}
}
@Override
public void addTransformedResource(Resource original, ByteBuffer transformed)
throws Exception {
if (isReadOnly()) {
throw new Exception("Pool is readonly");
}
Objects.requireNonNull(original);
Objects.requireNonNull(transformed);
if (resources.get(original.getPath()) != null) {
throw new Exception("Resource already present");
}
Resource res = new Resource(original.getPath(), transformed);
addResource(res);
}
private void retrieveModulesPackages(Map<String, Set<String>> moduleToPackage) {
for (Resource res : resources.values()) {
Set<String> pkgs = moduleToPackage.get(res.getModule());
if (pkgs == null) {
pkgs = new HashSet<>();
moduleToPackage.put(res.getModule(), pkgs);
}
// Module metadata only contains packages with resource files
if (ImageFileCreator.isResourcePackage(res.getPath())) {
String[] split = ImageFileCreator.splitPath(res.getPath());
String pkg = split[1];
if (pkg != null && !pkg.isEmpty()) {
pkgs.add(pkg);
}
}
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage;
/**
* Added strings are stored in the jimage strings table.
*/
public interface StringTable {
/**
* Add a string to the jimage strings table.
* @param str The string to add.
* @return a String identifier.
*/
public int addString(String str);
/**
* Retrieve a string from the passed id.
* @param id The string id.
* @return The string referenced by the passed id.
*/
public String getString(int id);
}

View File

@ -29,14 +29,18 @@ import java.nio.charset.Charset;
import java.util.Arrays;
public final class UTF8String implements CharSequence {
// Same as StandardCharsets.UTF_8 without loading all of the standard charsets
static final Charset UTF_8 = Charset.forName("UTF-8");
static final int NOT_FOUND = -1;
static final int HASH_MULTIPLIER = 0x01000193;
static final UTF8String EMPTY_STRING = new UTF8String("");
static final UTF8String CLASS_STRING = new UTF8String(".class");
static final UTF8String EMPTY_STRING = new UTF8String("");
static final UTF8String SLASH_STRING = new UTF8String("/");
static final UTF8String DOT_STRING = new UTF8String(".");
// TODO This strings are implementation specific and should be defined elsewhere.
static final UTF8String MODULES_STRING = new UTF8String("/modules");
static final UTF8String PACKAGES_STRING = new UTF8String("/packages");
final byte[] bytes;
final int offset;
@ -160,8 +164,8 @@ public final class UTF8String implements CharSequence {
return seed & 0x7FFFFFFF;
}
int hashCode(int base) {
return hashCode(base, bytes, offset, count);
int hashCode(int seed) {
return hashCode(seed, bytes, offset, count);
}
@Override
@ -186,7 +190,7 @@ public final class UTF8String implements CharSequence {
return equals(this, (UTF8String)obj);
}
private static boolean equals(UTF8String a, UTF8String b) {
public static boolean equals(UTF8String a, UTF8String b) {
if (a == b) {
return true;
}
@ -211,6 +215,10 @@ public final class UTF8String implements CharSequence {
return true;
}
public byte[] getBytesCopy() {
return Arrays.copyOfRange(bytes, offset, offset + count);
}
byte[] getBytes() {
if (offset != 0 || bytes.length != count) {
return Arrays.copyOfRange(bytes, offset, offset + count);
@ -232,33 +240,11 @@ public final class UTF8String implements CharSequence {
public char charAt(int index) {
int ch = byteAt(index);
return (ch & 0x80) != 0 ? (char)ch : '\0';
return (ch & 0x80) == 0 ? (char)ch : '\0';
}
@Override
public CharSequence subSequence(int start, int end) {
return (CharSequence)substring(start, end - start);
}
static UTF8String match(UTF8String a, UTF8String b) {
int aCount = a.count;
int bCount = b.count;
if (aCount < bCount) {
return null;
}
byte[] aBytes = a.bytes;
byte[] bBytes = b.bytes;
int aOffset = a.offset;
int bOffset = b.offset;
for (int i = 0; i < bCount; i++) {
if (aBytes[aOffset + i] != bBytes[bOffset + i]) {
return null;
}
}
return new UTF8String(aBytes, aOffset + bCount, aCount - bCount);
}
}

View File

@ -1,149 +0,0 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.concurrent;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import jdk.internal.jimage.PReader;
import sun.misc.Unsafe;
/**
* A PReader implementation that supports concurrent pread operations.
*/
public class ConcurrentPReader extends PReader {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final long BA_OFFSET = (long) UNSAFE.arrayBaseOffset(byte[].class);
/**
* A temporary buffer that is cached on a per-thread basis.
*/
private static class TemporaryBuffer {
static final ThreadLocal<TemporaryBuffer> CACHED_BUFFER =
new ThreadLocal<TemporaryBuffer>() {
@Override
protected TemporaryBuffer initialValue() { return null; }
};
static final TemporaryBuffer NOT_AVAILABLE = new TemporaryBuffer(0L, 0);
final long address;
final int size;
TemporaryBuffer(long address, int size) {
this.address = address;
this.size = size;
}
long address() { return address; }
int size() { return size; }
/**
* Returns the {@code TemporaryBuffer} for the current thread. The buffer
* is guaranteed to be of at least the given size. Returns {@code null}
* if a buffer cannot be cached for this thread.
*/
static TemporaryBuffer get(int len) {
TemporaryBuffer buffer = CACHED_BUFFER.get();
// cached buffer large enough?
if (buffer != null && buffer.size() >= len) {
return buffer;
}
// if this is an InnocuousThread then don't return anything
if (buffer == NOT_AVAILABLE)
return null;
if (buffer != null) {
// replace buffer in cache with a larger buffer
long originalAddress = buffer.address();
long address = UNSAFE.allocateMemory(len);
buffer = new TemporaryBuffer(address, len);
CACHED_BUFFER.set(buffer);
UNSAFE.freeMemory(originalAddress);
} else {
// first usage.
if (Thread.currentThread() instanceof sun.misc.InnocuousThread) {
buffer = NOT_AVAILABLE;
} else {
long address = UNSAFE.allocateMemory(len);
buffer = new TemporaryBuffer(address, len);
}
CACHED_BUFFER.set(buffer);
}
return buffer;
}
}
private final FileDescriptor fd;
private ConcurrentPReader(FileInputStream fis) throws IOException {
super(fis.getChannel());
this.fd = fis.getFD();
}
public ConcurrentPReader(String file) throws IOException {
this(new FileInputStream(file));
}
@Override
public byte[] read(int len, long position) throws IOException {
// need a temporary area of memory to read into
TemporaryBuffer buffer = TemporaryBuffer.get(len);
long address;
if (buffer == null) {
address = UNSAFE.allocateMemory(len);
} else {
address = buffer.address();
}
try {
int n = pread(fd, address, len, position);
if (n != len)
throw new InternalError("short read, not handled yet");
byte[] result = new byte[n];
UNSAFE.copyMemory(null, address, result, BA_OFFSET, len);
return result;
} finally {
if (buffer == null) {
UNSAFE.freeMemory(address);
}
}
}
private static native int pread(FileDescriptor fd, long address, int len, long pos)
throws IOException;
private static native void initIDs();
static {
System.loadLibrary("java");
initIDs();
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider;
/**
*
* A resource header for compressed resource. This class is handled internally,
* you don't have to add header to the resource, headers are added automatically
* for compressed resources.
*/
public final class CompressedResourceHeader {
private static final int SIZE = 21;
public static final int MAGIC = 0xCAFEFAFA;
private final int uncompressedSize;
private final int compressedSize;
private final int decompressorNameOffset;
private final int contentOffset;
private final boolean isTerminal;
public CompressedResourceHeader(int compressedSize,
int uncompressedSize, int decompressorNameOffset, int contentOffset,
boolean isTerminal) {
this.compressedSize = compressedSize;
this.uncompressedSize = uncompressedSize;
this.decompressorNameOffset = decompressorNameOffset;
this.contentOffset = contentOffset;
this.isTerminal = isTerminal;
}
public boolean isTerminal() {
return isTerminal;
}
public int getDecompressorNameOffset() {
return decompressorNameOffset;
}
public int getContentOffset() {
return contentOffset;
}
public String getStoredContent(StringsProvider provider) {
Objects.nonNull(provider);
if(contentOffset == -1) {
return null;
}
return provider.getString(contentOffset);
}
public int getUncompressedSize() {
return uncompressedSize;
}
public int getResourceSize() {
return compressedSize;
}
public byte[] getBytes(ByteOrder order) {
Objects.requireNonNull(order);
ByteBuffer buffer = ByteBuffer.allocate(SIZE);
buffer.order(order);
buffer.putInt(MAGIC);
buffer.putInt(compressedSize);
buffer.putInt(uncompressedSize);
buffer.putInt(decompressorNameOffset);
buffer.putInt(contentOffset);
buffer.put(isTerminal ? (byte)1 : (byte)0);
return buffer.array();
}
public static int getSize() {
return SIZE;
}
public static CompressedResourceHeader readFromResource(ByteOrder order,
byte[] resource) {
Objects.requireNonNull(order);
Objects.requireNonNull(resource);
if (resource.length < getSize()) {
return null;
}
ByteBuffer buffer = ByteBuffer.wrap(resource, 0, SIZE);
buffer.order(order);
int magic = buffer.getInt();
if(magic != MAGIC) {
return null;
}
int size = buffer.getInt();
int uncompressedSize = buffer.getInt();
int decompressorNameOffset = buffer.getInt();
int contentIndex = buffer.getInt();
byte isTerminal = buffer.get();
return new CompressedResourceHeader(size, uncompressedSize,
decompressorNameOffset, contentIndex, isTerminal == 1);
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider;
/**
* Entry point to decompress resources.
*/
public final class Decompressor {
private final Map<Integer, ResourceDecompressor> pluginsCache = new HashMap<>();
public Decompressor() {
}
/**
* Decompress a resource.
* @param order Byte order.
* @param provider Strings provider
* @param content The resource content to uncompress.
* @return A fully uncompressed resource.
* @throws IOException
*/
public byte[] decompressResource(ByteOrder order, StringsProvider provider,
byte[] content) throws IOException {
Objects.requireNonNull(order);
Objects.requireNonNull(provider);
Objects.requireNonNull(content);
CompressedResourceHeader header;
do {
header = CompressedResourceHeader.readFromResource(order, content);
if (header != null) {
ResourceDecompressor decompressor =
pluginsCache.get(header.getDecompressorNameOffset());
if (decompressor == null) {
String pluginName =
provider.getString(header.getDecompressorNameOffset());
if (pluginName == null) {
throw new IOException("Plugin name not found");
}
String storedContent = header.getStoredContent(provider);
Properties props = new Properties();
if (storedContent != null) {
try (ByteArrayInputStream stream =
new ByteArrayInputStream(storedContent.getBytes());) {
props.loadFromXML(stream);
}
}
decompressor = ResourceDecompressorRepository.
newResourceDecompressor(props, pluginName);
if (decompressor == null) {
throw new IOException("Plugin not found: " + pluginName);
}
pluginsCache.put(header.getDecompressorNameOffset(), decompressor);
}
try {
content = decompressor.decompress(provider, content,
CompressedResourceHeader.getSize(), header.getUncompressedSize());
} catch (Exception ex) {
throw new IOException(ex);
}
}
} while (header != null);
return content;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
/**
*
* JImage Decompressor.
*/
public interface ResourceDecompressor {
public interface StringsProvider {
public String getString(int offset);
}
/**
* Decompressor unique name.
* @return The decompressor name.
*/
public String getName();
/**
* Decompress a resource.
* @param strings The String provider
* @param content The resource content
* @param offset Resource content offset
* @param originalSize Uncompressed size
* @return Uncompressed resource
* @throws Exception
*/
public byte[] decompress(StringsProvider strings, byte[] content, int offset,
int originalSize) throws Exception;
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.io.IOException;
import java.util.Properties;
/**
*
* JImage Resource Decompressor factory
*/
public abstract class ResourceDecompressorFactory {
private final String name;
private final String description;
private final String arguments;
protected ResourceDecompressorFactory(String name, String description,
String arguments) {
this.name = name;
this.description = description;
this.arguments = arguments;
}
/**
* The Factory name.
* @return The name.
*/
public String getName() {
return name;
}
/**
* The Factory description.
* @return The description.
*/
public String getDescription() {
return description;
}
/**
* The Factory arguments description.
* @return The arguments description.
*/
public String getArgumentsDescription() {
return arguments;
}
/**
* To build a new decompressor.
* @param properties Contains configuration.
* @return A new decompressor.
* @throws IOException
*/
public abstract ResourceDecompressor newDecompressor(Properties properties)
throws IOException;
}

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
*
* JImage Decompressors. All decompressors must be registered in the static
* initializer of this class.
*/
public final class ResourceDecompressorRepository {
private ResourceDecompressorRepository() {
}
private static final Map<String, ResourceDecompressorFactory> factories = new HashMap<>();
static {
registerReaderProvider(new ZipDecompressorFactory());
}
/**
* Build a new decompressor for the passed name.
* @param properties Contains plugin configuration.
* @param name The plugin name to build.
* @return A decompressor or null if not found
* @throws IOException
*/
public static ResourceDecompressor newResourceDecompressor(Properties properties,
String name) throws IOException {
ResourceDecompressorFactory fact = factories.get(name);
if (fact != null) {
return fact.newDecompressor(properties);
}
return null;
}
private static void registerReaderProvider(ResourceDecompressorFactory factory) {
factories.put(factory.getName(), factory);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
/**
*
* ZIP Decompressor
*/
final class ZipDecompressor implements ResourceDecompressor {
@Override
public String getName() {
return ZipDecompressorFactory.NAME;
}
static byte[] decompress(byte[] bytesIn, int offset) {
Inflater inflater = new Inflater();
inflater.setInput(bytesIn, offset, bytesIn.length - offset);
ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset);
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
int count;
try {
count = inflater.inflate(buffer);
} catch (DataFormatException ex) {
return null;
}
stream.write(buffer, 0, count);
}
try {
stream.close();
} catch (IOException ex) {
return null;
}
byte[] bytesOut = stream.toByteArray();
inflater.end();
return bytesOut;
}
@Override
public byte[] decompress(StringsProvider reader, byte[] content, int offset,
int originalSize) throws Exception {
byte[] decompressed = decompress(content, offset);
return decompressed;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.jimage.decompressor;
import java.io.IOException;
import java.util.Properties;
/**
*
* ZIP decompressor factory
*/
public final class ZipDecompressorFactory extends ResourceDecompressorFactory {
public static final String NAME = "zip";
public ZipDecompressorFactory() {
super(NAME, "ZIP Decompression", null);
}
@Override
public ResourceDecompressor newDecompressor(Properties properties)
throws IOException {
return new ZipDecompressor();
}
}

View File

@ -51,7 +51,7 @@ final class JrtDirectoryStream implements DirectoryStream<Path> {
this.jrtfs = jrtPath.getFileSystem();
this.path = jrtPath.getResolvedPath();
// sanity check
if (!jrtfs.isDirectory(path))
if (!jrtfs.isDirectory(path, true))
throw new NotDirectoryException(jrtPath.toString());
// absolute path and does not have funky chars in front like /./java.base

View File

@ -25,6 +25,7 @@
package jdk.internal.jrtfs;
import java.nio.file.LinkOption;
import java.nio.file.attribute.*;
import java.io.IOException;
import java.util.LinkedHashMap;
@ -48,30 +49,32 @@ final class JrtFileAttributeView implements BasicFileAttributeView
private final JrtPath path;
private final boolean isJrtView;
private final LinkOption[] options;
private JrtFileAttributeView(JrtPath path, boolean isJrtView) {
private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) {
this.path = path;
this.isJrtView = isJrtView;
this.options = options;
}
@SuppressWarnings("unchecked") // Cast to V
static <V extends FileAttributeView> V get(JrtPath path, Class<V> type) {
static <V extends FileAttributeView> V get(JrtPath path, Class<V> type, LinkOption... options) {
if (type == null)
throw new NullPointerException();
if (type == BasicFileAttributeView.class)
return (V)new JrtFileAttributeView(path, false);
return (V)new JrtFileAttributeView(path, false, options);
if (type == JrtFileAttributeView.class)
return (V)new JrtFileAttributeView(path, true);
return (V)new JrtFileAttributeView(path, true, options);
return null;
}
static JrtFileAttributeView get(JrtPath path, String type) {
static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) {
if (type == null)
throw new NullPointerException();
if (type.equals("basic"))
return new JrtFileAttributeView(path, false);
return new JrtFileAttributeView(path, false, options);
if (type.equals("jjrt"))
return new JrtFileAttributeView(path, true);
return new JrtFileAttributeView(path, true, options);
return null;
}
@ -83,7 +86,7 @@ final class JrtFileAttributeView implements BasicFileAttributeView
@Override
public JrtFileAttributes readAttributes() throws IOException
{
return path.getAttributes();
return path.getAttributes(options);
}
@Override

View File

@ -76,12 +76,12 @@ final class JrtFileAttributes implements BasicFileAttributes
@Override
public boolean isSymbolicLink() {
return false;
return node.isLink();
}
@Override
public Object fileKey() {
return null;
return node.resolveLink(true);
}
///////// jrt entry attributes ///////////

View File

@ -31,9 +31,9 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.file.AccessMode;
import java.nio.file.ClosedFileSystemException;
import java.nio.file.CopyOption;
import java.nio.file.LinkOption;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemException;
@ -45,16 +45,13 @@ import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.ReadOnlyFileSystemException;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.nio.file.WatchService;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.UserPrincipalLookupService;
import java.nio.file.spi.FileSystemProvider;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.ConcurrentHashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -63,8 +60,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
import jdk.internal.jimage.ImageReader;
import jdk.internal.jimage.ImageReader.Node;
import jdk.internal.jimage.UTF8String;
@ -74,6 +72,7 @@ import jdk.internal.jimage.UTF8String;
*/
class JrtFileSystem extends FileSystem {
private static final Charset UTF_8 = Charset.forName("UTF-8");
private final JrtFileSystemProvider provider;
// System image readers
private ImageReader bootImage;
@ -109,7 +108,8 @@ class JrtFileSystem extends FileSystem {
this.extImage = openImage(SystemImages.extImagePath);
this.appImage = openImage(SystemImages.appImagePath);
rootPath = new JrtPath(this, new byte[]{'/'});
byte[] root = new byte[] { '/' };
rootPath = new JrtPath(this, root);
isOpen = true;
}
@ -149,12 +149,12 @@ class JrtFileSystem extends FileSystem {
synchronized(this) {
isOpen = false;
// close all image readers and null out
// close all image reader and null out
bootImage.close();
extImage.close();
appImage.close();
bootImage = null;
extImage.close();
extImage = null;
appImage.close();
appImage = null;
}
}
@ -289,21 +289,52 @@ class JrtFileSystem extends FileSystem {
}
}
private NodeAndImage findNode(byte[] path) throws IOException {
ImageReader image = bootImage;
private NodeAndImage lookup(byte[] path) {
Node node = bootImage.findNode(path);
ImageReader image = bootImage;
if (node == null) {
image = extImage;
node = extImage.findNode(path);
image = extImage;
}
if (node == null) {
image = appImage;
node = appImage.findNode(path);
image = appImage;
}
if (node == null || node.isHidden()) {
throw new NoSuchFileException(getString(path));
return node != null? new NodeAndImage(node, image) : null;
}
private NodeAndImage lookupSymbolic(byte[] path) {
for (int i = 1; i < path.length; i++) {
if (path[i] == (byte)'/') {
byte[] prefix = Arrays.copyOfRange(path, 0, i);
NodeAndImage ni = lookup(prefix);
if (ni == null) {
break;
}
if (ni.node.isLink()) {
Node link = ni.node.resolveLink(true);
// resolved symbolic path concatenated to the rest of the path
UTF8String resPath = link.getName().concat(new UTF8String(path, i));
byte[] resPathBytes = resPath.getBytesCopy();
ni = lookup(resPathBytes);
return ni != null? ni : lookupSymbolic(resPathBytes);
}
}
}
return new NodeAndImage(node, image);
return null;
}
private NodeAndImage findNode(byte[] path) throws IOException {
NodeAndImage ni = lookup(path);
if (ni == null) {
ni = lookupSymbolic(path);
if (ni == null) {
throw new NoSuchFileException(getString(path));
}
}
return ni;
}
private NodeAndImage checkNode(byte[] path) throws IOException {
@ -321,10 +352,28 @@ class JrtFileSystem extends FileSystem {
return ni;
}
static boolean followLinks(LinkOption... options) {
if (options != null) {
for (LinkOption lo : options) {
if (lo == LinkOption.NOFOLLOW_LINKS) {
return false;
} else if (lo == null) {
throw new NullPointerException();
} else {
throw new AssertionError("should not reach here");
}
}
}
return true;
}
// package private helpers
JrtFileAttributes getFileAttributes(byte[] path)
JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options)
throws IOException {
NodeAndImage ni = checkNode(path);
if (ni.node.isLink() && followLinks(options)) {
return new JrtFileAttributes(ni.node.resolveLink(true));
}
return new JrtFileAttributes(ni.node);
}
@ -343,11 +392,13 @@ class JrtFileSystem extends FileSystem {
return true;
}
boolean isDirectory(byte[] path)
boolean isDirectory(byte[] path, boolean resolveLinks)
throws IOException {
ensureOpen();
NodeAndImage ni = checkNode(path);
return ni.node.isDirectory();
return resolveLinks && ni.node.isLink()?
ni.node.resolveLink(true).isDirectory() :
ni.node.isDirectory();
}
JrtPath toJrtPath(String path) {
@ -358,6 +409,28 @@ class JrtFileSystem extends FileSystem {
return new JrtPath(this, path);
}
boolean isSameFile(JrtPath p1, JrtPath p2) throws IOException {
NodeAndImage n1 = findNode(p1.getName());
NodeAndImage n2 = findNode(p2.getName());
return n1.node.equals(n2.node);
}
boolean isLink(JrtPath jrtPath) throws IOException {
return findNode(jrtPath.getName()).node.isLink();
}
JrtPath resolveLink(JrtPath jrtPath) throws IOException {
NodeAndImage ni = findNode(jrtPath.getName());
if (ni.node.isLink()) {
Node node = ni.node.resolveLink();
return toJrtPath(node.getName().getBytesCopy());
}
return jrtPath;
}
private Map<UTF8String, List<Node>> packagesTreeChildren = new ConcurrentHashMap<>();
/**
* returns the list of child paths of the given directory "path"
*
@ -369,49 +442,73 @@ class JrtFileSystem extends FileSystem {
Iterator<Path> iteratorOf(byte[] path, String childPrefix)
throws IOException {
NodeAndImage ni = checkNode(path);
if (!ni.node.isDirectory()) {
Node node = ni.node.resolveLink(true);
if (!node.isDirectory()) {
throw new NotDirectoryException(getString(path));
}
if (ni.node.isRootDir()) {
if (node.isRootDir()) {
return rootDirIterator(path, childPrefix);
} else if (node.isModulesDir()) {
return modulesDirIterator(path, childPrefix);
} else if (node.isPackagesDir()) {
return packagesDirIterator(path, childPrefix);
} else if (node.getNameString().startsWith("/packages/")) {
if (ni.image != appImage) {
UTF8String name = node.getName();
List<Node> children = packagesTreeChildren.get(name);
if (children != null) {
return nodesToIterator(toJrtPath(path), childPrefix, children);
}
children = new ArrayList<>();
children.addAll(node.getChildren());
Node tmpNode = null;
// found in boot
if (ni.image == bootImage) {
tmpNode = extImage.findNode(name);
if (tmpNode != null) {
children.addAll(tmpNode.getChildren());
}
}
// found in ext
tmpNode = appImage.findNode(name);
if (tmpNode != null) {
children.addAll(tmpNode.getChildren());
}
packagesTreeChildren.put(name, children);
return nodesToIterator(toJrtPath(path), childPrefix, children);
}
}
return nodesToIterator(toJrtPath(path), childPrefix, ni.node.getChildren());
return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren());
}
private Iterator<Path> nodesToIterator(Path path, String childPrefix, List<Node> childNodes) {
List<Path> childPaths;
if (childPrefix == null) {
childPaths = childNodes.stream()
.filter(Node::isVisible)
.map(child -> toJrtPath(child.getNameString()))
.collect(Collectors.toCollection(ArrayList::new));
} else {
childPaths = childNodes.stream()
.filter(Node::isVisible)
.map(child -> toJrtPath(childPrefix + child.getNameString().substring(1)))
.collect(Collectors.toCollection(ArrayList::new));
}
return childPaths.iterator();
Function<Node, Path> f = childPrefix == null
? child -> toJrtPath(child.getNameString())
: child -> toJrtPath(childPrefix + child.getNameString().substring(1));
return childNodes.stream().map(f).collect(toList()).iterator();
}
private List<Node> rootChildren;
private static void addRootDirContent(List<Node> dest, List<Node> src) {
for (Node n : src) {
// only module directories at the top level. Filter other stuff!
if (n.isModuleDir()) {
dest.add(n);
private void addRootDirContent(List<Node> children) {
for (Node child : children) {
if (!(child.isModulesDir() || child.isPackagesDir())) {
rootChildren.add(child);
}
}
}
private List<Node> rootChildren;
private synchronized void initRootChildren(byte[] path) {
if (rootChildren == null) {
rootChildren = new ArrayList<>();
addRootDirContent(rootChildren, bootImage.findNode(path).getChildren());
addRootDirContent(rootChildren, extImage.findNode(path).getChildren());
addRootDirContent(rootChildren, appImage.findNode(path).getChildren());
rootChildren.addAll(bootImage.findNode(path).getChildren());
addRootDirContent(extImage.findNode(path).getChildren());
addRootDirContent(appImage.findNode(path).getChildren());
}
}
@ -420,6 +517,35 @@ class JrtFileSystem extends FileSystem {
return nodesToIterator(rootPath, childPrefix, rootChildren);
}
private List<Node> modulesChildren;
private synchronized void initModulesChildren(byte[] path) {
if (modulesChildren == null) {
modulesChildren = new ArrayList<>();
modulesChildren.addAll(bootImage.findNode(path).getChildren());
modulesChildren.addAll(appImage.findNode(path).getChildren());
modulesChildren.addAll(extImage.findNode(path).getChildren());
}
}
private Iterator<Path> modulesDirIterator(byte[] path, String childPrefix) throws IOException {
initModulesChildren(path);
return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren);
}
private List<Node> packagesChildren;
private synchronized void initPackagesChildren(byte[] path) {
if (packagesChildren == null) {
packagesChildren = new ArrayList<>();
packagesChildren.addAll(bootImage.findNode(path).getChildren());
packagesChildren.addAll(extImage.findNode(path).getChildren());
packagesChildren.addAll(appImage.findNode(path).getChildren());
}
}
private Iterator<Path> packagesDirIterator(byte[] path, String childPrefix) throws IOException {
initPackagesChildren(path);
return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren);
}
void createDirectory(byte[] dir, FileAttribute<?>... attrs)
throws IOException {
throw readOnly();

View File

@ -145,6 +145,11 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
toJrtPath(path).checkAccess(modes);
}
@Override
public Path readSymbolicLink(Path link) throws IOException {
return toJrtPath(link).readSymbolicLink();
}
@Override
public void copy(Path src, Path target, CopyOption... options)
throws IOException
@ -169,7 +174,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
public <V extends FileAttributeView> V
getFileAttributeView(Path path, Class<V> type, LinkOption... options)
{
return JrtFileAttributeView.get(toJrtPath(path), type);
return JrtFileAttributeView.get(toJrtPath(path), type, options);
}
@Override
@ -250,7 +255,7 @@ public final class JrtFileSystemProvider extends FileSystemProvider {
throws IOException
{
if (type == BasicFileAttributes.class || type == JrtFileAttributes.class)
return (A)toJrtPath(path).getAttributes();
return (A)toJrtPath(path).getAttributes(options);
return null;
}

View File

@ -55,6 +55,10 @@ final class JrtPath implements Path {
this.path = normalize(path);
}
byte[] getName() {
return path;
}
@Override
public JrtPath getRoot() {
if (this.isAbsolute())
@ -140,10 +144,19 @@ final class JrtPath implements Path {
@Override
public JrtPath toRealPath(LinkOption... options) throws IOException {
JrtPath realPath = new JrtPath(jrtfs, getResolvedPath()).toAbsolutePath();
realPath = JrtFileSystem.followLinks(options)? jrtfs.resolveLink(this) : realPath;
realPath.checkAccess();
return realPath;
}
JrtPath readSymbolicLink() throws IOException {
if (! jrtfs.isLink(this)) {
throw new IOException("not a symbolic link");
}
return jrtfs.resolveLink(this);
}
boolean isHidden() {
return false;
}
@ -638,9 +651,9 @@ final class JrtPath implements Path {
jrtfs.deleteFile(getResolvedPath(), false);
}
JrtFileAttributes getAttributes() throws IOException
JrtFileAttributes getAttributes(LinkOption... options) throws IOException
{
JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath());
JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath(), options);
if (zfas == null)
throw new NoSuchFileException(toString());
return zfas;
@ -659,7 +672,7 @@ final class JrtPath implements Path {
type = attribute.substring(0, colonPos++);
attr = attribute.substring(colonPos);
}
JrtFileAttributeView view = JrtFileAttributeView.get(this, type);
JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options);
if (view == null)
throw new UnsupportedOperationException("view <" + view + "> is not supported");
view.setAttribute(attr, value);
@ -685,7 +698,7 @@ final class JrtPath implements Path {
view = attributes.substring(0, colonPos++);
attrs = attributes.substring(colonPos);
}
JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view);
JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options);
if (jrtfv == null) {
throw new UnsupportedOperationException("view not supported");
}
@ -706,9 +719,10 @@ final class JrtPath implements Path {
this.getFileSystem() != other.getFileSystem())
return false;
this.checkAccess();
((JrtPath)other).checkAccess();
return Arrays.equals(this.getResolvedPath(),
((JrtPath)other).getResolvedPath());
JrtPath path = (JrtPath)other;
path.checkAccess();
return Arrays.equals(this.getResolvedPath(), path.getResolvedPath()) ||
jrtfs.isSameFile(this, (JrtPath)other);
}
SeekableByteChannel newByteChannel(Set<? extends OpenOption> options,

View File

@ -42,6 +42,7 @@ final class SystemImages {
static final Path bootImagePath;
static final Path extImagePath;
static final Path appImagePath;
static {
PrivilegedAction<String> pa = SystemImages::findHome;
RUNTIME_HOME = AccessController.doPrivileged(pa);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,6 +48,11 @@ public class ManagedLocalsThread extends Thread {
eraseThreadLocals();
}
public ManagedLocalsThread(ThreadGroup group, Runnable target) {
super(group, target);
eraseThreadLocals();
}
public ManagedLocalsThread(Runnable target, String name) {
super(target, name);
eraseThreadLocals();

View File

@ -31,6 +31,8 @@ import java.security.ProtectionDomain;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import jdk.internal.HotSpotIntrinsicCandidate;
/**
* A collection of methods for performing low-level, unsafe operations.
@ -148,6 +150,7 @@ public final class Unsafe {
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
@HotSpotIntrinsicCandidate
public native int getInt(Object o, long offset);
/**
@ -170,12 +173,14 @@ public final class Unsafe {
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
@HotSpotIntrinsicCandidate
public native void putInt(Object o, long offset, int x);
/**
* Fetches a reference value from a given Java variable.
* @see #getInt(Object, long)
*/
@HotSpotIntrinsicCandidate
public native Object getObject(Object o, long offset);
/**
@ -188,35 +193,50 @@ public final class Unsafe {
* are updated.
* @see #putInt(Object, long, int)
*/
@HotSpotIntrinsicCandidate
public native void putObject(Object o, long offset, Object x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native boolean getBoolean(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putBoolean(Object o, long offset, boolean x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native byte getByte(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putByte(Object o, long offset, byte x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native short getShort(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putShort(Object o, long offset, short x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native char getChar(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putChar(Object o, long offset, char x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native long getLong(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putLong(Object o, long offset, long x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native float getFloat(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putFloat(Object o, long offset, float x);
/** @see #getInt(Object, long) */
@HotSpotIntrinsicCandidate
public native double getDouble(Object o, long offset);
/** @see #putInt(Object, long, int) */
@HotSpotIntrinsicCandidate
public native void putDouble(Object o, long offset, double x);
// These read VM internal data.
@ -257,6 +277,7 @@ public final class Unsafe {
*
* @see #allocateMemory
*/
@HotSpotIntrinsicCandidate
public native byte getByte(long address);
/**
@ -266,31 +287,44 @@ public final class Unsafe {
*
* @see #getByte(long)
*/
@HotSpotIntrinsicCandidate
public native void putByte(long address, byte x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native short getShort(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putShort(long address, short x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native char getChar(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putChar(long address, char x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native int getInt(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putInt(long address, int x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native long getLong(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putLong(long address, long x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native float getFloat(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putFloat(long address, float x);
/** @see #getByte(long) */
@HotSpotIntrinsicCandidate
public native double getDouble(long address);
/** @see #putByte(long, byte) */
@HotSpotIntrinsicCandidate
public native void putDouble(long address, double x);
/**
@ -307,6 +341,7 @@ public final class Unsafe {
*
* @see #allocateMemory
*/
@HotSpotIntrinsicCandidate
public native long getAddress(long address);
/**
@ -319,6 +354,7 @@ public final class Unsafe {
*
* @see #getAddress(long)
*/
@HotSpotIntrinsicCandidate
public native void putAddress(long address, long x);
/// wrappers for malloc, realloc, free:
@ -406,6 +442,7 @@ public final class Unsafe {
*
* @since 1.7
*/
@HotSpotIntrinsicCandidate
public native void copyMemory(Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes);
@ -651,6 +688,7 @@ public final class Unsafe {
* Allocates an instance but does not run any constructor.
* Initializes the class if it has not yet been.
*/
@HotSpotIntrinsicCandidate
public native Object allocateInstance(Class<?> cls)
throws InstantiationException;
@ -666,6 +704,7 @@ public final class Unsafe {
*
* @return {@code true} if successful
*/
@HotSpotIntrinsicCandidate
public final native boolean compareAndSwapObject(Object o, long offset,
Object expected,
Object x);
@ -679,6 +718,7 @@ public final class Unsafe {
*
* @return {@code true} if successful
*/
@HotSpotIntrinsicCandidate
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x);
@ -692,6 +732,7 @@ public final class Unsafe {
*
* @return {@code true} if successful
*/
@HotSpotIntrinsicCandidate
public final native boolean compareAndSwapLong(Object o, long offset,
long expected,
long x);
@ -700,60 +741,78 @@ public final class Unsafe {
* Fetches a reference value from a given Java variable, with volatile
* load semantics. Otherwise identical to {@link #getObject(Object, long)}
*/
@HotSpotIntrinsicCandidate
public native Object getObjectVolatile(Object o, long offset);
/**
* Stores a reference value into a given Java variable, with
* volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)}
*/
@HotSpotIntrinsicCandidate
public native void putObjectVolatile(Object o, long offset, Object x);
/** Volatile version of {@link #getInt(Object, long)} */
@HotSpotIntrinsicCandidate
public native int getIntVolatile(Object o, long offset);
/** Volatile version of {@link #putInt(Object, long, int)} */
@HotSpotIntrinsicCandidate
public native void putIntVolatile(Object o, long offset, int x);
/** Volatile version of {@link #getBoolean(Object, long)} */
@HotSpotIntrinsicCandidate
public native boolean getBooleanVolatile(Object o, long offset);
/** Volatile version of {@link #putBoolean(Object, long, boolean)} */
@HotSpotIntrinsicCandidate
public native void putBooleanVolatile(Object o, long offset, boolean x);
/** Volatile version of {@link #getByte(Object, long)} */
@HotSpotIntrinsicCandidate
public native byte getByteVolatile(Object o, long offset);
/** Volatile version of {@link #putByte(Object, long, byte)} */
@HotSpotIntrinsicCandidate
public native void putByteVolatile(Object o, long offset, byte x);
/** Volatile version of {@link #getShort(Object, long)} */
@HotSpotIntrinsicCandidate
public native short getShortVolatile(Object o, long offset);
/** Volatile version of {@link #putShort(Object, long, short)} */
@HotSpotIntrinsicCandidate
public native void putShortVolatile(Object o, long offset, short x);
/** Volatile version of {@link #getChar(Object, long)} */
@HotSpotIntrinsicCandidate
public native char getCharVolatile(Object o, long offset);
/** Volatile version of {@link #putChar(Object, long, char)} */
@HotSpotIntrinsicCandidate
public native void putCharVolatile(Object o, long offset, char x);
/** Volatile version of {@link #getLong(Object, long)} */
@HotSpotIntrinsicCandidate
public native long getLongVolatile(Object o, long offset);
/** Volatile version of {@link #putLong(Object, long, long)} */
@HotSpotIntrinsicCandidate
public native void putLongVolatile(Object o, long offset, long x);
/** Volatile version of {@link #getFloat(Object, long)} */
@HotSpotIntrinsicCandidate
public native float getFloatVolatile(Object o, long offset);
/** Volatile version of {@link #putFloat(Object, long, float)} */
@HotSpotIntrinsicCandidate
public native void putFloatVolatile(Object o, long offset, float x);
/** Volatile version of {@link #getDouble(Object, long)} */
@HotSpotIntrinsicCandidate
public native double getDoubleVolatile(Object o, long offset);
/** Volatile version of {@link #putDouble(Object, long, double)} */
@HotSpotIntrinsicCandidate
public native void putDoubleVolatile(Object o, long offset, double x);
/**
@ -765,12 +824,15 @@ public final class Unsafe {
*
* Corresponds to C11 atomic_store_explicit(..., memory_order_release).
*/
@HotSpotIntrinsicCandidate
public native void putOrderedObject(Object o, long offset, Object x);
/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */
@HotSpotIntrinsicCandidate
public native void putOrderedInt(Object o, long offset, int x);
/** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */
@HotSpotIntrinsicCandidate
public native void putOrderedLong(Object o, long offset, long x);
/**
@ -785,6 +847,7 @@ public final class Unsafe {
*
* @param thread the thread to unpark.
*/
@HotSpotIntrinsicCandidate
public native void unpark(Object thread);
/**
@ -798,6 +861,7 @@ public final class Unsafe {
* because {@code unpark} is, so it would be strange to place it
* elsewhere.
*/
@HotSpotIntrinsicCandidate
public native void park(boolean isAbsolute, long time);
/**
@ -831,6 +895,7 @@ public final class Unsafe {
* @return the previous value
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
@ -850,6 +915,7 @@ public final class Unsafe {
* @return the previous value
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {
long v;
do {
@ -869,6 +935,7 @@ public final class Unsafe {
* @return the previous value
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
@ -888,6 +955,7 @@ public final class Unsafe {
* @return the previous value
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public final long getAndSetLong(Object o, long offset, long newValue) {
long v;
do {
@ -907,6 +975,7 @@ public final class Unsafe {
* @return the previous value
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public final Object getAndSetObject(Object o, long offset, Object newValue) {
Object v;
do {
@ -928,6 +997,7 @@ public final class Unsafe {
* provide a LoadLoad barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public native void loadFence();
/**
@ -942,6 +1012,7 @@ public final class Unsafe {
* provide a StoreStore barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public native void storeFence();
/**
@ -953,6 +1024,7 @@ public final class Unsafe {
* Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
* @since 1.8
*/
@HotSpotIntrinsicCandidate
public native void fullFence();
/**
@ -1010,6 +1082,7 @@ public final class Unsafe {
* {@link NullPointerException}
* @since 1.9
*/
@HotSpotIntrinsicCandidate
public final long getLongUnaligned(Object o, long offset) {
if ((offset & 7) == 0) {
return getLong(o, offset);
@ -1048,6 +1121,7 @@ public final class Unsafe {
}
/** @see #getLongUnaligned(Object, long) */
@HotSpotIntrinsicCandidate
public final int getIntUnaligned(Object o, long offset) {
if ((offset & 3) == 0) {
return getInt(o, offset);
@ -1067,6 +1141,7 @@ public final class Unsafe {
}
/** @see #getLongUnaligned(Object, long) */
@HotSpotIntrinsicCandidate
public final short getShortUnaligned(Object o, long offset) {
if ((offset & 1) == 0) {
return getShort(o, offset);
@ -1081,9 +1156,11 @@ public final class Unsafe {
}
/** @see #getLongUnaligned(Object, long) */
@HotSpotIntrinsicCandidate
public final char getCharUnaligned(Object o, long offset) {
return (char)getShortUnaligned(o, offset);
}
/** @see #getLongUnaligned(Object, long, boolean) */
public final char getCharUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getCharUnaligned(o, offset));
@ -1117,6 +1194,7 @@ public final class Unsafe {
* {@link NullPointerException}
* @since 1.9
*/
@HotSpotIntrinsicCandidate
public final void putLongUnaligned(Object o, long offset, long x) {
if ((offset & 7) == 0) {
putLong(o, offset, x);
@ -1142,6 +1220,7 @@ public final class Unsafe {
(byte)(x >>> 56));
}
}
/**
* As {@link #putLongUnaligned(Object, long, long)} but with an additional
* argument which specifies the endianness of the value as stored in memory.
@ -1158,6 +1237,7 @@ public final class Unsafe {
}
/** @see #putLongUnaligned(Object, long, long) */
@HotSpotIntrinsicCandidate
public final void putIntUnaligned(Object o, long offset, int x) {
if ((offset & 3) == 0) {
putInt(o, offset, x);
@ -1179,6 +1259,7 @@ public final class Unsafe {
}
/** @see #putLongUnaligned(Object, long, long) */
@HotSpotIntrinsicCandidate
public final void putShortUnaligned(Object o, long offset, short x) {
if ((offset & 1) == 0) {
putShort(o, offset, x);
@ -1194,6 +1275,7 @@ public final class Unsafe {
}
/** @see #putLongUnaligned(Object, long, long) */
@HotSpotIntrinsicCandidate
public final void putCharUnaligned(Object o, long offset, char x) {
putShortUnaligned(o, offset, (short)x);
}

Some files were not shown because too many files have changed in this diff Show More