Merge
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 6868b86..7e94a3d 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -533,13 +533,23 @@
8f5ca46a90af013525cbdf3b023727450cdb8119 jdk8u72-b13
6cbd347daa9367b78e385f2e8eba222a30b3bea1 jdk8u72-b14
fff0c11d2811deb70bef213d6d8478b3e3796658 jdk8u72-b15
+928374287059bb10b87dade1c2d984f8c4df01b3 jdk8u72-b31
443abbc4e048b13e075486a86ddafca520257fdf jdk8u73-b00
fc0ed68cbc5cbdb2efdb75f3309b5de2a64f5a57 jdk8u73-b01
6aacbee7e4c84a30761faf58a682b07b8bdf54da jdk8u73-b02
87614decb34cd6076f136b6d51be83f13e3e6aed jdk8u74-b00
33b310c85259e0d7ed112ab2e01008228e263371 jdk8u74-b01
bee679b986f51fe4d65d6df11fea93d1543b6502 jdk8u74-b02
+fd813938f2dd5f8e9d7caa2c1628af6da6683831 jdk8u74-b31
+9d7c49d756f01acbcbe8d0d3c5d5d4e92a7cf119 jdk8u74-b32
928374287059bb10b87dade1c2d984f8c4df01b3 jdk8u72-b31
+443abbc4e048b13e075486a86ddafca520257fdf jdk8u73-b00
+fc0ed68cbc5cbdb2efdb75f3309b5de2a64f5a57 jdk8u73-b01
+6aacbee7e4c84a30761faf58a682b07b8bdf54da jdk8u73-b02
+87614decb34cd6076f136b6d51be83f13e3e6aed jdk8u74-b00
+33b310c85259e0d7ed112ab2e01008228e263371 jdk8u74-b01
+bee679b986f51fe4d65d6df11fea93d1543b6502 jdk8u74-b02
+fd813938f2dd5f8e9d7caa2c1628af6da6683831 jdk8u74-b31
ac4e9dfd23236821432786b27566fa2f800aa3d4 jdk8u75-b00
d63a77fb06149b75dbb043a175a9c4a906ac26ef jdk8u75-b01
320f984ac52b56da66aff581a2c4830eadc0404e jdk8u75-b02
@@ -552,6 +562,14 @@
22ba4f1ad75c80bf78539f4c80b9867d227184d3 jdk8u75-b09
9da1d3f8905be682e33579857dd7b176f847e938 jdk8u75-b10
d8708cd521ff11851b259cd1171e8f18b90564a1 jdk8u75-b12
+417ff12d11d60c7f2235b498fdea9ef85514fc75 jdk8u77-b00
+6683e1d7422d0b6fc6566a1454604ca1ba7e86d9 jdk8u77-b01
+7dd1be8bd46cd4c80526671607e8035c3c671c14 jdk8u77-b02
+3fbef9f4cddf934f9cc0e06f61e641b5b845b901 jdk8u77-b03
+08dc508915433fdf3d970ea4d2fd33b4dffd67ca jdk8u77-b31
+4c41657db1862352b0e107b910be32c86eb5b1ff jdk8u91-b00
+0c798868f18548af144de0f0ab69f09a4c968cd2 jdk8u91-b13
+5744173381186940733aecf7904053ba6e83180e jdk8u91-b14
e8bed1496ff254d91d52c8da7c6d8d361862d773 jdk8u76-b00
832508a6165c877aa1de03ca9b6520c7bfe5a28e jdk8u76-b01
0861105394355ad24c07cb2ff58a731ef91502a8 jdk8u76-b02
@@ -564,3 +582,7 @@
b5e3d2c78818af23d855cb10bac51fab5b7b2884 jdk8u76-b09
2377ea341a26d0a6875f148dc555811bdf2e9533 jdk8u76-b10
94746373e4d5590536bacb0df4a19188e4d1bdd8 jdk8u76-b11
+9f2404d26c945178219c4f826fee5a084896ba55 jdk8u76-b12
+118aba9e37f0264a7cadb20ac0438eaea4180998 jdk8u92-b00
+94158f2e5cbdff8956b8e643e0305ca178d856e3 jdk8u92-b13
+51f64c980bcdef152a6eb043aaa5d04cc08c6624 jdk8u92-b14
diff --git a/corba/.hgtags b/corba/.hgtags
index 1bc8128..3b64265 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -542,6 +542,19 @@
0ce690c17329bde61998e5cd30b1beec9872262f jdk8u74-b01
5eb60567655e15d7ba4c349658d707f5bde0c2b8 jdk8u74-b02
d82cbb7a4bfe21b146f7b91ce833ac5a579c94eb jdk8u72-b31
+e3b496b6ae52f2c018e9c628c31be984bb4907e7 jdk8u73-b00
+5e484ab4b05f1398e924ab90874f7fe2ddf20731 jdk8u73-b01
+0cfcffb354bb4c76cac46f52b16a50e3b57794b9 jdk8u73-b02
+9e88cf03fe09fbf33045f43489be6f9c00e80c35 jdk8u74-b00
+0ce690c17329bde61998e5cd30b1beec9872262f jdk8u74-b01
+5eb60567655e15d7ba4c349658d707f5bde0c2b8 jdk8u74-b02
+3d00f5689b6c6e71fb1a230b7a746b61569b90ec jdk8u74-b31
+0cec2665affa36496b906c566e22ba7048ae6087 jdk8u74-b32
+7b719c1dec62535c34030cf3457abe6f478f13a0 jdk8u77-b00
+cafc1648f432eff2c392040af2db4505c3d290b6 jdk8u77-b01
+0f0077ee5e53365562ff77a01aa97d0c7374f447 jdk8u77-b02
+e8dc6eb11c761f20b44d8c4b8acb0846268872f1 jdk8u77-b03
+af6ddd4cd94c9353cc053b888de6d42d4d0faf47 jdk8u77-b31
073b951904b3ee7c54fb79a169478fa66d925320 jdk8u75-b00
5b48f7defe40eab668fe554df0afd87d84d60722 jdk8u75-b01
0015f4a7f0d02a9bb79b7a0c737590f01feaabd4 jdk8u75-b02
@@ -554,6 +567,13 @@
1030aea873cdecfb6f55ab652abc67c901f61f60 jdk8u75-b09
964fe4bba121592325cb346e3a4fa677b277d0ec jdk8u75-b10
f7cfd44464c3c3efd6d6f29921fad4ed0de75d83 jdk8u75-b12
+7b719c1dec62535c34030cf3457abe6f478f13a0 jdk8u77-b00
+cafc1648f432eff2c392040af2db4505c3d290b6 jdk8u77-b01
+0f0077ee5e53365562ff77a01aa97d0c7374f447 jdk8u77-b02
+e8dc6eb11c761f20b44d8c4b8acb0846268872f1 jdk8u77-b03
+cd7cec8fd295c0462a813b5f54dc5457c2bade2d jdk8u91-b00
+4ea02753e66e348ee4639e157061bcbdef1d7ff3 jdk8u91-b13
+f8d0cfaa9900ebda679fa9df8319fb753858f283 jdk8u91-b14
7deeb4f70404e4f52306f9d0bcfc482fc5f16fb3 jdk8u76-b00
5786892e7c7d512ef9104a469ff7eafeaac12c38 jdk8u76-b01
239155e48af89968b62e695a3233d42bed1a3282 jdk8u76-b02
@@ -566,3 +586,7 @@
afb55372bcc787b75e24afd28b00cfaaa45bb77d jdk8u76-b09
d2f26e6433db89354b028fb75abcc6ca266d035f jdk8u76-b10
df2dcefb08f9e3c65a4cbea75e54600649d063d0 jdk8u76-b11
+94c775e05eb053b8440d82298927a144ed73f340 jdk8u76-b12
+e0fbd6a51e061025f2d6ad0311a587f7ce3c2b43 jdk8u92-b00
+8f0466c0dce60b1df3bc01785b01a7f09fa7b564 jdk8u92-b13
+5617f9bec354fb2c60bbb816d175f4cee7d2c56e jdk8u92-b14
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index 091c179..6165d68 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -801,12 +801,20 @@
a8e4754b89aecc388623394a20f6d43d4c58f083 jdk8u72-b13
dc2fdd4e0b8105268b8231040f761f27ab4523f2 jdk8u72-b14
d6670c5d49ba381405ec9f69a78ccc5b8b0c8473 jdk8u72-b15
+da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31
26b99cd20661a1fa05939d1856a9389311e01c4f jdk8u73-b00
931c31db01ae873525a1b2c306b01129eb431960 jdk8u73-b01
67566d815a66d958c1f817d65f1621ba1d2e5f33 jdk8u73-b02
451dda77f6c29bd3260e87f847a9eadae122a759 jdk8u74-b00
c1031a924f2c910fad078838b88a2f0146f2de98 jdk8u74-b01
ca9cae9aa9e989bbe6713c91d55c913edeaecce4 jdk8u74-b02
+a5b78b56841e97ce00463874f1b7f63c54d84934 jdk8u74-b31
+94ec11846b18111e73929b6caa9fbe7262e142c1 jdk8u74-b32
+1b6d4fd2730e58f17820930f797938dc182117c4 jdk8u77-b00
+ddd297e340b1170d3cec011ee64e729f8b493c86 jdk8u77-b01
+1b4072e4bb3ad54c4e894998486a8b33f0689160 jdk8u77-b02
+223b64a19e94222dd97b92bb40abcfbc0bf6ef1f jdk8u77-b03
+dd8507f51d786572dae18af8ffdc5a1ea34c755e jdk8u77-b31
da43260704c28b9f19cb652090ae65c258220fd6 jdk8u72-b31
c0242ea4bde19d72be5149feda112a39e8c89b0a jdk8u75-b00
ca3b8c8e390ab0540b0cc2e5def869b38e460d86 jdk8u75-b01
@@ -820,6 +828,13 @@
e97c45c377eb8d022cfe24b73737fa312107e0a5 jdk8u75-b09
d44c7e324682a30e064503ef9582d83a41f4173e jdk8u75-b10
cc78c97abff85062d6844fa253081e26a0a60150 jdk8u75-b12
+1b6d4fd2730e58f17820930f797938dc182117c4 jdk8u77-b00
+ddd297e340b1170d3cec011ee64e729f8b493c86 jdk8u77-b01
+1b4072e4bb3ad54c4e894998486a8b33f0689160 jdk8u77-b02
+223b64a19e94222dd97b92bb40abcfbc0bf6ef1f jdk8u77-b03
+bbbb05e91c629f8d9eef2ba43933767f68a898b0 jdk8u91-b00
+e36b6ade0499eadfd8673fe62ef0a613af2e6d67 jdk8u91-b13
+fa8991ccf6e5b74890a0b5672440b3c09d8d8732 jdk8u91-b14
d7b01fb81aa8a5437cb03bc36afe15cf0e55fb89 jdk8u76-b00
c1679cc87ba045219169cabb6b9b378c2b5cc578 jdk8u76-b01
218483967e52b419d885d34af4488a81c5133804 jdk8u76-b02
@@ -832,3 +847,7 @@
3bf0f5b8a892defd0bf9731b4e15926881fcda74 jdk8u76-b09
a2b0ee820059a44be558a2d435b7d85ed5a8b63a jdk8u76-b10
16aa1f621ec67db1a55ebf6527750164ab63088d jdk8u76-b11
+9a87701e22b3cae79fdfd8cdb732051e02a710fa jdk8u76-b12
+481dcde745b6aec035781ed9f6797cfc93719f71 jdk8u92-b00
+f3e1e734e2d29101a9537ddeb71ecad413fcd352 jdk8u92-b13
+24a09407d71bb2cc4848bfa21660c890b4d722b1 jdk8u92-b14
diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
index 8098e88..7cbc47d 100644
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp
@@ -2318,6 +2318,13 @@
emit_arith(0x0B, 0xC0, dst, src);
}
+void Assembler::orl(Address dst, Register src) {
+ InstructionMark im(this);
+ prefix(dst, src);
+ emit_int8(0x09);
+ emit_operand(src, dst);
+}
+
void Assembler::packuswb(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
@@ -5613,6 +5620,19 @@
}
}
+void Assembler::rcrq(Register dst, int imm8) {
+ assert(isShiftCount(imm8 >> 1), "illegal shift count");
+ int encode = prefixq_and_encode(dst->encoding());
+ if (imm8 == 1) {
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xD8 | encode));
+ } else {
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xD8 | encode));
+ emit_int8(imm8);
+ }
+}
+
void Assembler::rorq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp
index fc270db..341d9e3 100644
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp
@@ -1455,6 +1455,7 @@
void orl(Register dst, int32_t imm32);
void orl(Register dst, Address src);
void orl(Register dst, Register src);
+ void orl(Address dst, Register src);
void orq(Address dst, int32_t imm32);
void orq(Register dst, int32_t imm32);
@@ -1555,6 +1556,8 @@
void rclq(Register dst, int imm8);
+ void rcrq(Register dst, int imm8);
+
void rdtsc();
void ret(int imm16);
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
index b3a72ab..e2ea04b 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp
@@ -7769,6 +7769,503 @@
pop(tmp2);
pop(tmp1);
}
+
+//Helper functions for square_to_len()
+
+/**
+ * Store the squares of x[], right shifted one bit (divided by 2) into z[]
+ * Preserves x and z and modifies rest of the registers.
+ */
+
+void MacroAssembler::square_rshift(Register x, Register xlen, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg) {
+ // Perform square and right shift by 1
+ // Handle odd xlen case first, then for even xlen do the following
+ // jlong carry = 0;
+ // for (int j=0, i=0; j < xlen; j+=2, i+=4) {
+ // huge_128 product = x[j:j+1] * x[j:j+1];
+ // z[i:i+1] = (carry << 63) | (jlong)(product >>> 65);
+ // z[i+2:i+3] = (jlong)(product >>> 1);
+ // carry = (jlong)product;
+ // }
+
+ xorq(tmp5, tmp5); // carry
+ xorq(rdxReg, rdxReg);
+ xorl(tmp1, tmp1); // index for x
+ xorl(tmp4, tmp4); // index for z
+
+ Label L_first_loop, L_first_loop_exit;
+
+ testl(xlen, 1);
+ jccb(Assembler::zero, L_first_loop); //jump if xlen is even
+
+ // Square and right shift by 1 the odd element using 32 bit multiply
+ movl(raxReg, Address(x, tmp1, Address::times_4, 0));
+ imulq(raxReg, raxReg);
+ shrq(raxReg, 1);
+ adcq(tmp5, 0);
+ movq(Address(z, tmp4, Address::times_4, 0), raxReg);
+ incrementl(tmp1);
+ addl(tmp4, 2);
+
+ // Square and right shift by 1 the rest using 64 bit multiply
+ bind(L_first_loop);
+ cmpptr(tmp1, xlen);
+ jccb(Assembler::equal, L_first_loop_exit);
+
+ // Square
+ movq(raxReg, Address(x, tmp1, Address::times_4, 0));
+ rorq(raxReg, 32); // convert big-endian to little-endian
+ mulq(raxReg); // 64-bit multiply rax * rax -> rdx:rax
+
+ // Right shift by 1 and save carry
+ shrq(tmp5, 1); // rdx:rax:tmp5 = (tmp5:rdx:rax) >>> 1
+ rcrq(rdxReg, 1);
+ rcrq(raxReg, 1);
+ adcq(tmp5, 0);
+
+ // Store result in z
+ movq(Address(z, tmp4, Address::times_4, 0), rdxReg);
+ movq(Address(z, tmp4, Address::times_4, 8), raxReg);
+
+ // Update indices for x and z
+ addl(tmp1, 2);
+ addl(tmp4, 4);
+ jmp(L_first_loop);
+
+ bind(L_first_loop_exit);
+}
+
+
+/**
+ * Perform the following multiply add operation using BMI2 instructions
+ * carry:sum = sum + op1*op2 + carry
+ * op2 should be in rdx
+ * op2 is preserved, all other registers are modified
+ */
+void MacroAssembler::multiply_add_64_bmi2(Register sum, Register op1, Register op2, Register carry, Register tmp2) {
+ // assert op2 is rdx
+ mulxq(tmp2, op1, op1); // op1 * op2 -> tmp2:op1
+ addq(sum, carry);
+ adcq(tmp2, 0);
+ addq(sum, op1);
+ adcq(tmp2, 0);
+ movq(carry, tmp2);
+}
+
+/**
+ * Perform the following multiply add operation:
+ * carry:sum = sum + op1*op2 + carry
+ * Preserves op1, op2 and modifies rest of registers
+ */
+void MacroAssembler::multiply_add_64(Register sum, Register op1, Register op2, Register carry, Register rdxReg, Register raxReg) {
+ // rdx:rax = op1 * op2
+ movq(raxReg, op2);
+ mulq(op1);
+
+ // rdx:rax = sum + carry + rdx:rax
+ addq(sum, carry);
+ adcq(rdxReg, 0);
+ addq(sum, raxReg);
+ adcq(rdxReg, 0);
+
+ // carry:sum = rdx:sum
+ movq(carry, rdxReg);
+}
+
+/**
+ * Add 64 bit long carry into z[] with carry propogation.
+ * Preserves z and carry register values and modifies rest of registers.
+ *
+ */
+void MacroAssembler::add_one_64(Register z, Register zlen, Register carry, Register tmp1) {
+ Label L_fourth_loop, L_fourth_loop_exit;
+
+ movl(tmp1, 1);
+ subl(zlen, 2);
+ addq(Address(z, zlen, Address::times_4, 0), carry);
+
+ bind(L_fourth_loop);
+ jccb(Assembler::carryClear, L_fourth_loop_exit);
+ subl(zlen, 2);
+ jccb(Assembler::negative, L_fourth_loop_exit);
+ addq(Address(z, zlen, Address::times_4, 0), tmp1);
+ jmp(L_fourth_loop);
+ bind(L_fourth_loop_exit);
+}
+
+/**
+ * Shift z[] left by 1 bit.
+ * Preserves x, len, z and zlen registers and modifies rest of the registers.
+ *
+ */
+void MacroAssembler::lshift_by_1(Register x, Register len, Register z, Register zlen, Register tmp1, Register tmp2, Register tmp3, Register tmp4) {
+
+ Label L_fifth_loop, L_fifth_loop_exit;
+
+ // Fifth loop
+ // Perform primitiveLeftShift(z, zlen, 1)
+
+ const Register prev_carry = tmp1;
+ const Register new_carry = tmp4;
+ const Register value = tmp2;
+ const Register zidx = tmp3;
+
+ // int zidx, carry;
+ // long value;
+ // carry = 0;
+ // for (zidx = zlen-2; zidx >=0; zidx -= 2) {
+ // (carry:value) = (z[i] << 1) | carry ;
+ // z[i] = value;
+ // }
+
+ movl(zidx, zlen);
+ xorl(prev_carry, prev_carry); // clear carry flag and prev_carry register
+
+ bind(L_fifth_loop);
+ decl(zidx); // Use decl to preserve carry flag
+ decl(zidx);
+ jccb(Assembler::negative, L_fifth_loop_exit);
+
+ if (UseBMI2Instructions) {
+ movq(value, Address(z, zidx, Address::times_4, 0));
+ rclq(value, 1);
+ rorxq(value, value, 32);
+ movq(Address(z, zidx, Address::times_4, 0), value); // Store back in big endian form
+ }
+ else {
+ // clear new_carry
+ xorl(new_carry, new_carry);
+
+ // Shift z[i] by 1, or in previous carry and save new carry
+ movq(value, Address(z, zidx, Address::times_4, 0));
+ shlq(value, 1);
+ adcl(new_carry, 0);
+
+ orq(value, prev_carry);
+ rorq(value, 0x20);
+ movq(Address(z, zidx, Address::times_4, 0), value); // Store back in big endian form
+
+ // Set previous carry = new carry
+ movl(prev_carry, new_carry);
+ }
+ jmp(L_fifth_loop);
+
+ bind(L_fifth_loop_exit);
+}
+
+
+/**
+ * Code for BigInteger::squareToLen() intrinsic
+ *
+ * rdi: x
+ * rsi: len
+ * r8: z
+ * rcx: zlen
+ * r12: tmp1
+ * r13: tmp2
+ * r14: tmp3
+ * r15: tmp4
+ * rbx: tmp5
+ *
+ */
+void MacroAssembler::square_to_len(Register x, Register len, Register z, Register zlen, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg) {
+
+ Label L_second_loop, L_second_loop_exit, L_third_loop, L_third_loop_exit, fifth_loop, fifth_loop_exit, L_last_x, L_multiply;
+ push(tmp1);
+ push(tmp2);
+ push(tmp3);
+ push(tmp4);
+ push(tmp5);
+
+ // First loop
+ // Store the squares, right shifted one bit (i.e., divided by 2).
+ square_rshift(x, len, z, tmp1, tmp3, tmp4, tmp5, rdxReg, raxReg);
+
+ // Add in off-diagonal sums.
+ //
+ // Second, third (nested) and fourth loops.
+ // zlen +=2;
+ // for (int xidx=len-2,zidx=zlen-4; xidx > 0; xidx-=2,zidx-=4) {
+ // carry = 0;
+ // long op2 = x[xidx:xidx+1];
+ // for (int j=xidx-2,k=zidx; j >= 0; j-=2) {
+ // k -= 2;
+ // long op1 = x[j:j+1];
+ // long sum = z[k:k+1];
+ // carry:sum = multiply_add_64(sum, op1, op2, carry, tmp_regs);
+ // z[k:k+1] = sum;
+ // }
+ // add_one_64(z, k, carry, tmp_regs);
+ // }
+
+ const Register carry = tmp5;
+ const Register sum = tmp3;
+ const Register op1 = tmp4;
+ Register op2 = tmp2;
+
+ push(zlen);
+ push(len);
+ addl(zlen,2);
+ bind(L_second_loop);
+ xorq(carry, carry);
+ subl(zlen, 4);
+ subl(len, 2);
+ push(zlen);
+ push(len);
+ cmpl(len, 0);
+ jccb(Assembler::lessEqual, L_second_loop_exit);
+
+ // Multiply an array by one 64 bit long.
+ if (UseBMI2Instructions) {
+ op2 = rdxReg;
+ movq(op2, Address(x, len, Address::times_4, 0));
+ rorxq(op2, op2, 32);
+ }
+ else {
+ movq(op2, Address(x, len, Address::times_4, 0));
+ rorq(op2, 32);
+ }
+
+ bind(L_third_loop);
+ decrementl(len);
+ jccb(Assembler::negative, L_third_loop_exit);
+ decrementl(len);
+ jccb(Assembler::negative, L_last_x);
+
+ movq(op1, Address(x, len, Address::times_4, 0));
+ rorq(op1, 32);
+
+ bind(L_multiply);
+ subl(zlen, 2);
+ movq(sum, Address(z, zlen, Address::times_4, 0));
+
+ // Multiply 64 bit by 64 bit and add 64 bits lower half and upper 64 bits as carry.
+ if (UseBMI2Instructions) {
+ multiply_add_64_bmi2(sum, op1, op2, carry, tmp2);
+ }
+ else {
+ multiply_add_64(sum, op1, op2, carry, rdxReg, raxReg);
+ }
+
+ movq(Address(z, zlen, Address::times_4, 0), sum);
+
+ jmp(L_third_loop);
+ bind(L_third_loop_exit);
+
+ // Fourth loop
+ // Add 64 bit long carry into z with carry propogation.
+ // Uses offsetted zlen.
+ add_one_64(z, zlen, carry, tmp1);
+
+ pop(len);
+ pop(zlen);
+ jmp(L_second_loop);
+
+ // Next infrequent code is moved outside loops.
+ bind(L_last_x);
+ movl(op1, Address(x, 0));
+ jmp(L_multiply);
+
+ bind(L_second_loop_exit);
+ pop(len);
+ pop(zlen);
+ pop(len);
+ pop(zlen);
+
+ // Fifth loop
+ // Shift z left 1 bit.
+ lshift_by_1(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4);
+
+ // z[zlen-1] |= x[len-1] & 1;
+ movl(tmp3, Address(x, len, Address::times_4, -4));
+ andl(tmp3, 1);
+ orl(Address(z, zlen, Address::times_4, -4), tmp3);
+
+ pop(tmp5);
+ pop(tmp4);
+ pop(tmp3);
+ pop(tmp2);
+ pop(tmp1);
+}
+
+/**
+ * Helper function for mul_add()
+ * Multiply the in[] by int k and add to out[] starting at offset offs using
+ * 128 bit by 32 bit multiply and return the carry in tmp5.
+ * Only quad int aligned length of in[] is operated on in this function.
+ * k is in rdxReg for BMI2Instructions, for others it is in tmp2.
+ * This function preserves out, in and k registers.
+ * len and offset point to the appropriate index in "in" & "out" correspondingly
+ * tmp5 has the carry.
+ * other registers are temporary and are modified.
+ *
+ */
+void MacroAssembler::mul_add_128_x_32_loop(Register out, Register in,
+ Register offset, Register len, Register tmp1, Register tmp2, Register tmp3,
+ Register tmp4, Register tmp5, Register rdxReg, Register raxReg) {
+
+ Label L_first_loop, L_first_loop_exit;
+
+ movl(tmp1, len);
+ shrl(tmp1, 2);
+
+ bind(L_first_loop);
+ subl(tmp1, 1);
+ jccb(Assembler::negative, L_first_loop_exit);
+
+ subl(len, 4);
+ subl(offset, 4);
+
+ Register op2 = tmp2;
+ const Register sum = tmp3;
+ const Register op1 = tmp4;
+ const Register carry = tmp5;
+
+ if (UseBMI2Instructions) {
+ op2 = rdxReg;
+ }
+
+ movq(op1, Address(in, len, Address::times_4, 8));
+ rorq(op1, 32);
+ movq(sum, Address(out, offset, Address::times_4, 8));
+ rorq(sum, 32);
+ if (UseBMI2Instructions) {
+ multiply_add_64_bmi2(sum, op1, op2, carry, raxReg);
+ }
+ else {
+ multiply_add_64(sum, op1, op2, carry, rdxReg, raxReg);
+ }
+ // Store back in big endian from little endian
+ rorq(sum, 0x20);
+ movq(Address(out, offset, Address::times_4, 8), sum);
+
+ movq(op1, Address(in, len, Address::times_4, 0));
+ rorq(op1, 32);
+ movq(sum, Address(out, offset, Address::times_4, 0));
+ rorq(sum, 32);
+ if (UseBMI2Instructions) {
+ multiply_add_64_bmi2(sum, op1, op2, carry, raxReg);
+ }
+ else {
+ multiply_add_64(sum, op1, op2, carry, rdxReg, raxReg);
+ }
+ // Store back in big endian from little endian
+ rorq(sum, 0x20);
+ movq(Address(out, offset, Address::times_4, 0), sum);
+
+ jmp(L_first_loop);
+ bind(L_first_loop_exit);
+}
+
+/**
+ * Code for BigInteger::mulAdd() intrinsic
+ *
+ * rdi: out
+ * rsi: in
+ * r11: offs (out.length - offset)
+ * rcx: len
+ * r8: k
+ * r12: tmp1
+ * r13: tmp2
+ * r14: tmp3
+ * r15: tmp4
+ * rbx: tmp5
+ * Multiply the in[] by word k and add to out[], return the carry in rax
+ */
+void MacroAssembler::mul_add(Register out, Register in, Register offs,
+ Register len, Register k, Register tmp1, Register tmp2, Register tmp3,
+ Register tmp4, Register tmp5, Register rdxReg, Register raxReg) {
+
+ Label L_carry, L_last_in, L_done;
+
+// carry = 0;
+// for (int j=len-1; j >= 0; j--) {
+// long product = (in[j] & LONG_MASK) * kLong +
+// (out[offs] & LONG_MASK) + carry;
+// out[offs--] = (int)product;
+// carry = product >>> 32;
+// }
+//
+ push(tmp1);
+ push(tmp2);
+ push(tmp3);
+ push(tmp4);
+ push(tmp5);
+
+ Register op2 = tmp2;
+ const Register sum = tmp3;
+ const Register op1 = tmp4;
+ const Register carry = tmp5;
+
+ if (UseBMI2Instructions) {
+ op2 = rdxReg;
+ movl(op2, k);
+ }
+ else {
+ movl(op2, k);
+ }
+
+ xorq(carry, carry);
+
+ //First loop
+
+ //Multiply in[] by k in a 4 way unrolled loop using 128 bit by 32 bit multiply
+ //The carry is in tmp5
+ mul_add_128_x_32_loop(out, in, offs, len, tmp1, tmp2, tmp3, tmp4, tmp5, rdxReg, raxReg);
+
+ //Multiply the trailing in[] entry using 64 bit by 32 bit, if any
+ decrementl(len);
+ jccb(Assembler::negative, L_carry);
+ decrementl(len);
+ jccb(Assembler::negative, L_last_in);
+
+ movq(op1, Address(in, len, Address::times_4, 0));
+ rorq(op1, 32);
+
+ subl(offs, 2);
+ movq(sum, Address(out, offs, Address::times_4, 0));
+ rorq(sum, 32);
+
+ if (UseBMI2Instructions) {
+ multiply_add_64_bmi2(sum, op1, op2, carry, raxReg);
+ }
+ else {
+ multiply_add_64(sum, op1, op2, carry, rdxReg, raxReg);
+ }
+
+ // Store back in big endian from little endian
+ rorq(sum, 0x20);
+ movq(Address(out, offs, Address::times_4, 0), sum);
+
+ testl(len, len);
+ jccb(Assembler::zero, L_carry);
+
+ //Multiply the last in[] entry, if any
+ bind(L_last_in);
+ movl(op1, Address(in, 0));
+ movl(sum, Address(out, offs, Address::times_4, -4));
+
+ movl(raxReg, k);
+ mull(op1); //tmp4 * eax -> edx:eax
+ addl(sum, carry);
+ adcl(rdxReg, 0);
+ addl(sum, raxReg);
+ adcl(rdxReg, 0);
+ movl(carry, rdxReg);
+
+ movl(Address(out, offs, Address::times_4, -4), sum);
+
+ bind(L_carry);
+ //return tmp5/carry as carry in rax
+ movl(rax, carry);
+
+ bind(L_done);
+ pop(tmp5);
+ pop(tmp4);
+ pop(tmp3);
+ pop(tmp2);
+ pop(tmp1);
+}
#endif
/**
diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
index 69c9e8a..cc5e585 100644
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
@@ -1241,6 +1241,25 @@
Register carry2);
void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen,
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5);
+
+ void square_rshift(Register x, Register len, Register z, Register tmp1, Register tmp3,
+ Register tmp4, Register tmp5, Register rdxReg, Register raxReg);
+ void multiply_add_64_bmi2(Register sum, Register op1, Register op2, Register carry,
+ Register tmp2);
+ void multiply_add_64(Register sum, Register op1, Register op2, Register carry,
+ Register rdxReg, Register raxReg);
+ void add_one_64(Register z, Register zlen, Register carry, Register tmp1);
+ void lshift_by_1(Register x, Register len, Register z, Register zlen, Register tmp1, Register tmp2,
+ Register tmp3, Register tmp4);
+ void square_to_len(Register x, Register len, Register z, Register zlen, Register tmp1, Register tmp2,
+ Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg);
+
+ void mul_add_128_x_32_loop(Register out, Register in, Register offset, Register len, Register tmp1,
+ Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register rdxReg,
+ Register raxReg);
+ void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp1,
+ Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register rdxReg,
+ Register raxReg);
#endif
// CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic.
diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
index 86ce38d..a3eb504 100644
--- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp
@@ -23,6 +23,9 @@
*/
#include "precompiled.hpp"
+#ifndef _WINDOWS
+#include "alloca.h"
+#endif
#include "asm/macroAssembler.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "code/debugInfoRec.hpp"
@@ -3966,6 +3969,256 @@
}
+//------------------------------Montgomery multiplication------------------------
+//
+
+#ifndef _WINDOWS
+
+#define ASM_SUBTRACT
+
+#ifdef ASM_SUBTRACT
+// Subtract 0:b from carry:a. Return carry.
+static unsigned long
+sub(unsigned long a[], unsigned long b[], unsigned long carry, long len) {
+ long i = 0, cnt = len;
+ unsigned long tmp;
+ asm volatile("clc; "
+ "0: ; "
+ "mov (%[b], %[i], 8), %[tmp]; "
+ "sbb %[tmp], (%[a], %[i], 8); "
+ "inc %[i]; dec %[cnt]; "
+ "jne 0b; "
+ "mov %[carry], %[tmp]; sbb $0, %[tmp]; "
+ : [i]"+r"(i), [cnt]"+r"(cnt), [tmp]"=&r"(tmp)
+ : [a]"r"(a), [b]"r"(b), [carry]"r"(carry)
+ : "memory");
+ return tmp;
+}
+#else // ASM_SUBTRACT
+typedef int __attribute__((mode(TI))) int128;
+
+// Subtract 0:b from carry:a. Return carry.
+static unsigned long
+sub(unsigned long a[], unsigned long b[], unsigned long carry, int len) {
+ int128 tmp = 0;
+ int i;
+ for (i = 0; i < len; i++) {
+ tmp += a[i];
+ tmp -= b[i];
+ a[i] = tmp;
+ tmp >>= 64;
+ assert(-1 <= tmp && tmp <= 0, "invariant");
+ }
+ return tmp + carry;
+}
+#endif // ! ASM_SUBTRACT
+
+// Multiply (unsigned) Long A by Long B, accumulating the double-
+// length result into the accumulator formed of T0, T1, and T2.
+#define MACC(A, B, T0, T1, T2) \
+do { \
+ unsigned long hi, lo; \
+ asm volatile("mul %5; add %%rax, %2; adc %%rdx, %3; adc $0, %4" \
+ : "=&d"(hi), "=a"(lo), "+r"(T0), "+r"(T1), "+g"(T2) \
+ : "r"(A), "a"(B) : "cc"); \
+ } while(0)
+
+// As above, but add twice the double-length result into the
+// accumulator.
+#define MACC2(A, B, T0, T1, T2) \
+do { \
+ unsigned long hi, lo; \
+ asm volatile("mul %5; add %%rax, %2; adc %%rdx, %3; adc $0, %4;" \
+ "add %%rax, %2; adc %%rdx, %3; adc $0, %4" \
+ : "=&d"(hi), "=a"(lo), "+r"(T0), "+r"(T1), "+g"(T2) \
+ : "r"(A), "a"(B) : "cc"); \
+ } while(0)
+
+// Fast Montgomery multiplication. The derivation of the algorithm is
+// in A Cryptographic Library for the Motorola DSP56000,
+// Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237.
+
+static void __attribute__((noinline))
+montgomery_multiply(unsigned long a[], unsigned long b[], unsigned long n[],
+ unsigned long m[], unsigned long inv, int len) {
+ unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator
+ int i;
+
+ assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply");
+
+ for (i = 0; i < len; i++) {
+ int j;
+ for (j = 0; j < i; j++) {
+ MACC(a[j], b[i-j], t0, t1, t2);
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ MACC(a[i], b[0], t0, t1, t2);
+ m[i] = t0 * inv;
+ MACC(m[i], n[0], t0, t1, t2);
+
+ assert(t0 == 0, "broken Montgomery multiply");
+
+ t0 = t1; t1 = t2; t2 = 0;
+ }
+
+ for (i = len; i < 2*len; i++) {
+ int j;
+ for (j = i-len+1; j < len; j++) {
+ MACC(a[j], b[i-j], t0, t1, t2);
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ m[i-len] = t0;
+ t0 = t1; t1 = t2; t2 = 0;
+ }
+
+ while (t0)
+ t0 = sub(m, n, t0, len);
+}
+
+// Fast Montgomery squaring. This uses asymptotically 25% fewer
+// multiplies so it should be up to 25% faster than Montgomery
+// multiplication. However, its loop control is more complex and it
+// may actually run slower on some machines.
+
+static void __attribute__((noinline))
+montgomery_square(unsigned long a[], unsigned long n[],
+ unsigned long m[], unsigned long inv, int len) {
+ unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator
+ int i;
+
+ assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply");
+
+ for (i = 0; i < len; i++) {
+ int j;
+ int end = (i+1)/2;
+ for (j = 0; j < end; j++) {
+ MACC2(a[j], a[i-j], t0, t1, t2);
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ if ((i & 1) == 0) {
+ MACC(a[j], a[j], t0, t1, t2);
+ }
+ for (; j < i; j++) {
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ m[i] = t0 * inv;
+ MACC(m[i], n[0], t0, t1, t2);
+
+ assert(t0 == 0, "broken Montgomery square");
+
+ t0 = t1; t1 = t2; t2 = 0;
+ }
+
+ for (i = len; i < 2*len; i++) {
+ int start = i-len+1;
+ int end = start + (len - start)/2;
+ int j;
+ for (j = start; j < end; j++) {
+ MACC2(a[j], a[i-j], t0, t1, t2);
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ if ((i & 1) == 0) {
+ MACC(a[j], a[j], t0, t1, t2);
+ }
+ for (; j < len; j++) {
+ MACC(m[j], n[i-j], t0, t1, t2);
+ }
+ m[i-len] = t0;
+ t0 = t1; t1 = t2; t2 = 0;
+ }
+
+ while (t0)
+ t0 = sub(m, n, t0, len);
+}
+
+// Swap words in a longword.
+static unsigned long swap(unsigned long x) {
+ return (x << 32) | (x >> 32);
+}
+
+// Copy len longwords from s to d, word-swapping as we go. The
+// destination array is reversed.
+static void reverse_words(unsigned long *s, unsigned long *d, int len) {
+ d += len;
+ while(len-- > 0) {
+ d--;
+ *d = swap(*s);
+ s++;
+ }
+}
+
+// The threshold at which squaring is advantageous was determined
+// experimentally on an i7-3930K (Ivy Bridge) CPU @ 3.5GHz.
+#define MONTGOMERY_SQUARING_THRESHOLD 64
+
+void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints,
+ jint len, jlong inv,
+ jint *m_ints) {
+ assert(len % 2 == 0, "array length in montgomery_multiply must be even");
+ int longwords = len/2;
+
+ // Make very sure we don't use so much space that the stack might
+ // overflow. 512 jints corresponds to an 16384-bit integer and
+ // will use here a total of 8k bytes of stack space.
+ int total_allocation = longwords * sizeof (unsigned long) * 4;
+ guarantee(total_allocation <= 8192, "must be");
+ unsigned long *scratch = (unsigned long *)alloca(total_allocation);
+
+ // Local scratch arrays
+ unsigned long
+ *a = scratch + 0 * longwords,
+ *b = scratch + 1 * longwords,
+ *n = scratch + 2 * longwords,
+ *m = scratch + 3 * longwords;
+
+ reverse_words((unsigned long *)a_ints, a, longwords);
+ reverse_words((unsigned long *)b_ints, b, longwords);
+ reverse_words((unsigned long *)n_ints, n, longwords);
+
+ ::montgomery_multiply(a, b, n, m, (unsigned long)inv, longwords);
+
+ reverse_words(m, (unsigned long *)m_ints, longwords);
+}
+
+void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints,
+ jint len, jlong inv,
+ jint *m_ints) {
+ assert(len % 2 == 0, "array length in montgomery_square must be even");
+ int longwords = len/2;
+
+ // Make very sure we don't use so much space that the stack might
+ // overflow. 512 jints corresponds to an 16384-bit integer and
+ // will use here a total of 6k bytes of stack space.
+ int total_allocation = longwords * sizeof (unsigned long) * 3;
+ guarantee(total_allocation <= 8192, "must be");
+ unsigned long *scratch = (unsigned long *)alloca(total_allocation);
+
+ // Local scratch arrays
+ unsigned long
+ *a = scratch + 0 * longwords,
+ *n = scratch + 1 * longwords,
+ *m = scratch + 2 * longwords;
+
+ reverse_words((unsigned long *)a_ints, a, longwords);
+ reverse_words((unsigned long *)n_ints, n, longwords);
+
+ //montgomery_square fails to pass BigIntegerTest on solaris amd64
+ //on jdk7 and jdk8.
+#ifndef SOLARIS
+ if (len >= MONTGOMERY_SQUARING_THRESHOLD) {
+#else
+ if (0) {
+#endif
+ ::montgomery_square(a, n, m, (unsigned long)inv, longwords);
+ } else {
+ ::montgomery_multiply(a, a, n, m, (unsigned long)inv, longwords);
+ }
+
+ reverse_words(m, (unsigned long *)m_ints, longwords);
+}
+
+#endif // WINDOWS
+
#ifdef COMPILER2
// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame
//
diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
index 0bb6118..01fe4b8 100644
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp
@@ -3743,6 +3743,107 @@
return start;
}
+/**
+ * Arguments:
+ *
+ // Input:
+ // c_rarg0 - x address
+ // c_rarg1 - x length
+ // c_rarg2 - z address
+ // c_rarg3 - z lenth
+ *
+ */
+ address generate_squareToLen() {
+
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "squareToLen");
+
+ address start = __ pc();
+ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
+ // Unix: rdi, rsi, rdx, rcx (c_rarg0, c_rarg1, ...)
+ const Register x = rdi;
+ const Register len = rsi;
+ const Register z = r8;
+ const Register zlen = rcx;
+
+ const Register tmp1 = r12;
+ const Register tmp2 = r13;
+ const Register tmp3 = r14;
+ const Register tmp4 = r15;
+ const Register tmp5 = rbx;
+
+ BLOCK_COMMENT("Entry:");
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
+ // zlen => rcx
+ // r9 and r10 may be used to save non-volatile registers
+ __ movptr(r8, rdx);
+ __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
+
+ restore_arg_regs();
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+ /**
+ * Arguments:
+ *
+ * Input:
+ * c_rarg0 - out address
+ * c_rarg1 - in address
+ * c_rarg2 - offset
+ * c_rarg3 - len
+ * not Win64
+ * c_rarg4 - k
+ * Win64
+ * rsp+40 - k
+ */
+ address generate_mulAdd() {
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "mulAdd");
+
+ address start = __ pc();
+ // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
+ // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
+ const Register out = rdi;
+ const Register in = rsi;
+ const Register offset = r11;
+ const Register len = rcx;
+ const Register k = r8;
+
+ // Next registers will be saved on stack in mul_add().
+ const Register tmp1 = r12;
+ const Register tmp2 = r13;
+ const Register tmp3 = r14;
+ const Register tmp4 = r15;
+ const Register tmp5 = rbx;
+
+ BLOCK_COMMENT("Entry:");
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ setup_arg_regs(4); // out => rdi, in => rsi, offset => rdx
+ // len => rcx, k => r8
+ // r9 and r10 may be used to save non-volatile registers
+#ifdef _WIN64
+ // last argument is on stack on Win64
+ __ movl(k, Address(rsp, 6 * wordSize));
+#endif
+ __ movptr(r11, rdx); // move offset in rdx to offset(r11)
+ __ mul_add(out, in, offset, len, k, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
+
+ restore_arg_regs();
+
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+
#undef __
#define __ masm->
@@ -3987,7 +4088,24 @@
if (UseMultiplyToLenIntrinsic) {
StubRoutines::_multiplyToLen = generate_multiplyToLen();
}
-#endif
+ if (UseSquareToLenIntrinsic) {
+ StubRoutines::_squareToLen = generate_squareToLen();
+ }
+ if (UseMulAddIntrinsic) {
+ StubRoutines::_mulAdd = generate_mulAdd();
+ }
+
+#ifndef _WINDOWS
+ if (UseMontgomeryMultiplyIntrinsic) {
+ StubRoutines::_montgomeryMultiply
+ = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply);
+ }
+ if (UseMontgomerySquareIntrinsic) {
+ StubRoutines::_montgomerySquare
+ = CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square);
+ }
+#endif // WINDOWS
+#endif // COMPILER2
}
public:
diff --git a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp
index 205bce4..15922b8 100644
--- a/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp
+++ b/hotspot/src/cpu/x86/vm/stubRoutines_x86_64.hpp
@@ -33,7 +33,7 @@
enum platform_dependent_constants {
code_size1 = 19000, // simply increase if too small (assembler will crash if too small)
- code_size2 = 22000 // simply increase if too small (assembler will crash if too small)
+ code_size2 = 23000 // simply increase if too small (assembler will crash if too small)
};
class x86 {
diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
index adfdfd6..28aa48e 100644
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp
@@ -703,6 +703,18 @@
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
UseMultiplyToLenIntrinsic = true;
}
+ if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
+ UseSquareToLenIntrinsic = false;
+ }
+ if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
+ UseMulAddIntrinsic = false;
+ }
+ if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
+ UseMontgomeryMultiplyIntrinsic = false;
+ }
+ if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
+ UseMontgomerySquareIntrinsic = false;
+ }
#else
if (UseMultiplyToLenIntrinsic) {
if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
@@ -710,6 +722,30 @@
}
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
}
+ if (UseSquareToLenIntrinsic) {
+ if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
+ warning("squareToLen intrinsic is not available in 32-bit VM");
+ }
+ FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false);
+ }
+ if (UseMulAddIntrinsic) {
+ if (!FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
+ warning("mulAdd intrinsic is not available in 32-bit VM");
+ }
+ FLAG_SET_DEFAULT(UseMulAddIntrinsic, false);
+ }
+ if (UseMontgomeryMultiplyIntrinsic) {
+ if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
+ warning("montgomeryMultiply intrinsic is not available in 32-bit VM");
+ }
+ FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false);
+ }
+ if (UseMontgomerySquareIntrinsic) {
+ if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
+ warning("montgomerySquare intrinsic is not available in 32-bit VM");
+ }
+ FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false);
+ }
#endif
#endif // COMPILER2
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp
index 222d2b0..b857cb3 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp
@@ -793,10 +793,26 @@
do_signature(encodeISOArray_signature, "([CI[BII)I") \
\
do_class(java_math_BigInteger, "java/math/BigInteger") \
- do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_R) \
+ do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_S) \
do_name( multiplyToLen_name, "multiplyToLen") \
do_signature(multiplyToLen_signature, "([II[II[I)[I") \
\
+ do_intrinsic(_squareToLen, java_math_BigInteger, squareToLen_name, squareToLen_signature, F_S) \
+ do_name( squareToLen_name, "implSquareToLen") \
+ do_signature(squareToLen_signature, "([II[II)[I") \
+ \
+ do_intrinsic(_mulAdd, java_math_BigInteger, mulAdd_name, mulAdd_signature, F_S) \
+ do_name( mulAdd_name, "implMulAdd") \
+ do_signature(mulAdd_signature, "([I[IIII)I") \
+ \
+ do_intrinsic(_montgomeryMultiply, java_math_BigInteger, montgomeryMultiply_name, montgomeryMultiply_signature, F_S) \
+ do_name( montgomeryMultiply_name, "implMontgomeryMultiply") \
+ do_signature(montgomeryMultiply_signature, "([I[I[IIJ[I)[I") \
+ \
+ do_intrinsic(_montgomerySquare, java_math_BigInteger, montgomerySquare_name, montgomerySquare_signature, F_S) \
+ do_name( montgomerySquare_name, "implMontgomerySquare") \
+ do_signature(montgomerySquare_signature, "([I[IIJ[I)[I") \
+ \
/* java/lang/ref/Reference */ \
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
\
diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp
index fe1834b..3aab433 100644
--- a/hotspot/src/share/vm/opto/c2_globals.hpp
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp
@@ -662,6 +662,18 @@
product(bool, UseMultiplyToLenIntrinsic, false, \
"Enables intrinsification of BigInteger.multiplyToLen()") \
\
+ product(bool, UseSquareToLenIntrinsic, false, \
+ "Enables intrinsification of BigInteger.squareToLen()") \
+ \
+ product(bool, UseMulAddIntrinsic, false, \
+ "Enables intrinsification of BigInteger.mulAdd()") \
+ \
+ product(bool, UseMontgomeryMultiplyIntrinsic, false, \
+ "Enables intrinsification of BigInteger.montgomeryMultiply()") \
+ \
+ product(bool, UseMontgomerySquareIntrinsic, false, \
+ "Enables intrinsification of BigInteger.montgomerySquare()") \
+ \
product(bool, UseTypeSpeculation, true, \
"Speculatively propagate types from profiles") \
\
diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp
index 9473a62..b422215 100644
--- a/hotspot/src/share/vm/opto/compile.cpp
+++ b/hotspot/src/share/vm/opto/compile.cpp
@@ -412,6 +412,13 @@
remove_macro_node(n);
}
}
+ // Remove useless CastII nodes with range check dependency
+ for (int i = range_check_cast_count() - 1; i >= 0; i--) {
+ Node* cast = range_check_cast_node(i);
+ if (!useful.member(cast)) {
+ remove_range_check_cast(cast);
+ }
+ }
// Remove useless expensive node
for (int i = C->expensive_count()-1; i >= 0; i--) {
Node* n = C->expensive_node(i);
@@ -1148,6 +1155,7 @@
_macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
_predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
_expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
+ _range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8, 0, NULL);
register_library_intrinsics();
}
@@ -1876,6 +1884,22 @@
assert(predicate_count()==0, "should be clean!");
}
+void Compile::add_range_check_cast(Node* n) {
+ assert(n->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+ assert(!_range_check_casts->contains(n), "duplicate entry in range check casts");
+ _range_check_casts->append(n);
+}
+
+// Remove all range check dependent CastIINodes.
+void Compile::remove_range_check_casts(PhaseIterGVN &igvn) {
+ for (int i = range_check_cast_count(); i > 0; i--) {
+ Node* cast = range_check_cast_node(i-1);
+ assert(cast->isa_CastII()->has_range_check(), "CastII should have range check dependency");
+ igvn.replace_node(cast, cast->in(1));
+ }
+ assert(range_check_cast_count() == 0, "should be empty");
+}
+
// StringOpts and late inlining of string methods
void Compile::inline_string_calls(bool parse_time) {
{
@@ -2218,6 +2242,12 @@
PhaseIdealLoop::verify(igvn);
}
+ if (range_check_cast_count() > 0) {
+ // No more loop optimizations. Remove all range check dependent CastIINodes.
+ C->remove_range_check_casts(igvn);
+ igvn.optimize();
+ }
+
{
NOT_PRODUCT( TracePhase t2("macroExpand", &_t_macroExpand, TimeCompiler); )
PhaseMacroExpand mex(igvn);
@@ -2987,6 +3017,16 @@
#endif
+#ifdef ASSERT
+ case Op_CastII:
+ // Verify that all range check dependent CastII nodes were removed.
+ if (n->isa_CastII()->has_range_check()) {
+ n->dump(3);
+ assert(false, "Range check dependent CastII node was not removed");
+ }
+ break;
+#endif
+
case Op_ModI:
if (UseDivMod) {
// Check if a%b and a/b both exist
@@ -4024,6 +4064,24 @@
}
}
+// Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl) {
+ if (ctrl != NULL) {
+ // Express control dependency by a CastII node with a narrow type.
+ value = new (phase->C) CastIINode(value, itype, false, true /* range check dependency */);
+ // Make the CastII node dependent on the control input to prevent the narrowed ConvI2L
+ // node from floating above the range check during loop optimizations. Otherwise, the
+ // ConvI2L node may be eliminated independently of the range check, causing the data path
+ // to become TOP while the control path is still there (although it's unreachable).
+ value->set_req(0, ctrl);
+ // Save CastII node to remove it after loop optimizations.
+ phase->C->add_range_check_cast(value);
+ value = phase->transform(value);
+ }
+ const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen);
+ return phase->transform(new (phase->C) ConvI2LNode(value, ltype));
+}
+
// Auxiliary method to support randomized stressing/fuzzing.
//
// This method can be called the arbitrary number of times, with current count
diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp
index 570c99e..34028fc 100644
--- a/hotspot/src/share/vm/opto/compile.hpp
+++ b/hotspot/src/share/vm/opto/compile.hpp
@@ -75,6 +75,7 @@
class JVMState;
class Type;
class TypeData;
+class TypeInt;
class TypePtr;
class TypeOopPtr;
class TypeFunc;
@@ -334,6 +335,7 @@
GrowableArray<Node*>* _macro_nodes; // List of nodes which need to be expanded before matching.
GrowableArray<Node*>* _predicate_opaqs; // List of Opaque1 nodes for the loop predicates.
GrowableArray<Node*>* _expensive_nodes; // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
+ GrowableArray<Node*>* _range_check_casts; // List of CastII nodes with a range check dependency
ConnectionGraph* _congraph;
#ifndef PRODUCT
IdealGraphPrinter* _printer;
@@ -669,7 +671,7 @@
void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;}
void add_macro_node(Node * n) {
//assert(n->is_macro(), "must be a macro node");
- assert(!_macro_nodes->contains(n), " duplicate entry in expand list");
+ assert(!_macro_nodes->contains(n), "duplicate entry in expand list");
_macro_nodes->append(n);
}
void remove_macro_node(Node * n) {
@@ -689,10 +691,23 @@
}
}
void add_predicate_opaq(Node * n) {
- assert(!_predicate_opaqs->contains(n), " duplicate entry in predicate opaque1");
+ assert(!_predicate_opaqs->contains(n), "duplicate entry in predicate opaque1");
assert(_macro_nodes->contains(n), "should have already been in macro list");
_predicate_opaqs->append(n);
}
+
+ // Range check dependent CastII nodes that can be removed after loop optimizations
+ void add_range_check_cast(Node* n);
+ void remove_range_check_cast(Node* n) {
+ if (_range_check_casts->contains(n)) {
+ _range_check_casts->remove(n);
+ }
+ }
+ Node* range_check_cast_node(int idx) const { return _range_check_casts->at(idx); }
+ int range_check_cast_count() const { return _range_check_casts->length(); }
+ // Remove all range check dependent CastIINodes.
+ void remove_range_check_casts(PhaseIterGVN &igvn);
+
// remove the opaque nodes that protect the predicates so that the unused checks and
// uncommon traps will be eliminated from the graph.
void cleanup_loop_predicates(PhaseIterGVN &igvn);
@@ -1201,6 +1216,9 @@
// Definitions of pd methods
static void pd_compiler2_init();
+ // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
+ static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
+
// Auxiliary method for randomized fuzzing/stressing
static bool randomized_select(int count);
};
diff --git a/hotspot/src/share/vm/opto/connode.cpp b/hotspot/src/share/vm/opto/connode.cpp
index bfebd1c..00aee51 100644
--- a/hotspot/src/share/vm/opto/connode.cpp
+++ b/hotspot/src/share/vm/opto/connode.cpp
@@ -535,6 +535,9 @@
if (_carry_dependency) {
st->print(" carry dependency");
}
+ if (_range_check_dependency) {
+ st->print(" range check dependency");
+ }
}
#endif
@@ -994,7 +997,8 @@
}
#ifdef _LP64
- // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) ,
+ // Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) or
+ // ConvI2L(CastII(AddI(x, y))) to AddL(ConvI2L(CastII(x)), ConvI2L(CastII(y))),
// but only if x and y have subranges that cannot cause 32-bit overflow,
// under the assumption that x+y is in my own subrange this->type().
@@ -1018,6 +1022,13 @@
Node* z = in(1);
int op = z->Opcode();
+ Node* ctrl = NULL;
+ if (op == Op_CastII && z->as_CastII()->has_range_check()) {
+ // Skip CastII node but save control dependency
+ ctrl = z->in(0);
+ z = z->in(1);
+ op = z->Opcode();
+ }
if (op == Op_AddI || op == Op_SubI) {
Node* x = z->in(1);
Node* y = z->in(2);
@@ -1075,9 +1086,10 @@
rylo = -ryhi;
ryhi = -rylo0;
}
-
- Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) );
- Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) );
+ assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow");
+ assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow");
+ Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), ctrl);
+ Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), ctrl);
switch (op) {
case Op_AddI: return new (phase->C) AddLNode(cx, cy);
case Op_SubI: return new (phase->C) SubLNode(cx, cy);
diff --git a/hotspot/src/share/vm/opto/connode.hpp b/hotspot/src/share/vm/opto/connode.hpp
index 5558028..21c2276 100644
--- a/hotspot/src/share/vm/opto/connode.hpp
+++ b/hotspot/src/share/vm/opto/connode.hpp
@@ -244,19 +244,31 @@
private:
// Can this node be removed post CCP or does it carry a required dependency?
const bool _carry_dependency;
+ // Is this node dependent on a range check?
+ const bool _range_check_dependency;
protected:
virtual uint cmp( const Node &n ) const;
virtual uint size_of() const;
public:
- CastIINode(Node *n, const Type *t, bool carry_dependency = false)
- : ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {}
+ CastIINode(Node *n, const Type *t, bool carry_dependency = false, bool range_check_dependency = false)
+ : ConstraintCastNode(n,t), _carry_dependency(carry_dependency), _range_check_dependency(range_check_dependency) {
+ init_class_id(Class_CastII);
+ }
virtual int Opcode() const;
virtual uint ideal_reg() const { return Op_RegI; }
virtual Node *Identity( PhaseTransform *phase );
virtual const Type *Value( PhaseTransform *phase ) const;
virtual Node *Ideal_DU_postCCP( PhaseCCP * );
+ const bool has_range_check() {
+ #ifdef _LP64
+ return _range_check_dependency;
+ #else
+ assert(!_range_check_dependency, "Should not have range check dependency");
+ return false;
+ #endif
+ }
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
#endif
diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp
index b5e1f6b..bcd2e78 100644
--- a/hotspot/src/share/vm/opto/escape.cpp
+++ b/hotspot/src/share/vm/opto/escape.cpp
@@ -958,8 +958,12 @@
strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 ||
strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 ||
strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 ||
- strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0)
- ))) {
+ strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "mulAdd") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "montgomery_multiply") == 0 ||
+ strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0)
+ ))) {
call->dump();
fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name));
}
diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp
index 4300aae..38e0ce2 100644
--- a/hotspot/src/share/vm/opto/graphKit.cpp
+++ b/hotspot/src/share/vm/opto/graphKit.cpp
@@ -1645,7 +1645,7 @@
//-------------------------array_element_address-------------------------
Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
- const TypeInt* sizetype) {
+ const TypeInt* sizetype, Node* ctrl) {
uint shift = exact_log2(type2aelembytes(elembt));
uint header = arrayOopDesc::base_offset_in_bytes(elembt);
@@ -1670,9 +1670,9 @@
// number. (The prior range check has ensured this.)
// This assertion is used by ConvI2LNode::Ideal.
int index_max = max_jint - 1; // array size is max_jint, index is one less
- if (sizetype != NULL) index_max = sizetype->_hi - 1;
- const TypeLong* lidxtype = TypeLong::make(CONST64(0), index_max, Type::WidenMax);
- idx = _gvn.transform( new (C) ConvI2LNode(idx, lidxtype) );
+ if (sizetype != NULL) index_max = sizetype->_hi - 1;
+ const TypeInt* iidxtype = TypeInt::make(0, index_max, Type::WidenMax);
+ idx = C->constrained_convI2L(&_gvn, idx, iidxtype, ctrl);
#endif
Node* scale = _gvn.transform( new (C) LShiftXNode(idx, intcon(shift)) );
return basic_plus_adr(ary, base, scale);
@@ -3491,10 +3491,6 @@
Node* initial_slow_cmp = _gvn.transform( new (C) CmpUNode( length, intcon( fast_size_limit ) ) );
Node* initial_slow_test = _gvn.transform( new (C) BoolNode( initial_slow_cmp, BoolTest::gt ) );
- if (initial_slow_test->is_Bool()) {
- // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
- initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
- }
// --- Size Computation ---
// array_size = round_to_heap(array_header + (length << elem_shift));
@@ -3540,13 +3536,35 @@
Node* lengthx = ConvI2X(length);
Node* headerx = ConvI2X(header_size);
#ifdef _LP64
- { const TypeLong* tllen = _gvn.find_long_type(lengthx);
- if (tllen != NULL && tllen->_lo < 0) {
+ { const TypeInt* tilen = _gvn.find_int_type(length);
+ if (tilen != NULL && tilen->_lo < 0) {
// Add a manual constraint to a positive range. Cf. array_element_address.
- jlong size_max = arrayOopDesc::max_array_length(T_BYTE);
- if (size_max > tllen->_hi) size_max = tllen->_hi;
- const TypeLong* tlcon = TypeLong::make(CONST64(0), size_max, Type::WidenMin);
- lengthx = _gvn.transform( new (C) ConvI2LNode(length, tlcon));
+ jlong size_max = fast_size_limit;
+ if (size_max > tilen->_hi) size_max = tilen->_hi;
+ const TypeInt* tlcon = TypeInt::make(0, size_max, Type::WidenMin);
+
+ // Only do a narrow I2L conversion if the range check passed.
+ IfNode* iff = new (C) IfNode(control(), initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
+ _gvn.transform(iff);
+ RegionNode* region = new (C) RegionNode(3);
+ _gvn.set_type(region, Type::CONTROL);
+ lengthx = new (C) PhiNode(region, TypeLong::LONG);
+ _gvn.set_type(lengthx, TypeLong::LONG);
+
+ // Range check passed. Use ConvI2L node with narrow type.
+ Node* passed = IfFalse(iff);
+ region->init_req(1, passed);
+ // Make I2L conversion control dependent to prevent it from
+ // floating above the range check during loop optimizations.
+ lengthx->init_req(1, C->constrained_convI2L(&_gvn, length, tlcon, passed));
+
+ // Range check failed. Use ConvI2L with wide type because length may be invalid.
+ region->init_req(2, IfTrue(iff));
+ lengthx->init_req(2, ConvI2X(length));
+
+ set_control(region);
+ record_for_igvn(region);
+ record_for_igvn(lengthx);
}
}
#endif
@@ -3577,6 +3595,11 @@
Node *mem = reset_memory();
set_all_memory(mem); // Create new memory state
+ if (initial_slow_test->is_Bool()) {
+ // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
+ initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
+ }
+
// Create the AllocateArrayNode and its result projections
AllocateArrayNode* alloc
= new (C) AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp
index a5437e7..d7c32b3 100644
--- a/hotspot/src/share/vm/opto/graphKit.hpp
+++ b/hotspot/src/share/vm/opto/graphKit.hpp
@@ -626,7 +626,9 @@
// Return addressing for an array element.
Node* array_element_address(Node* ary, Node* idx, BasicType elembt,
// Optional constraint on the array size:
- const TypeInt* sizetype = NULL);
+ const TypeInt* sizetype = NULL,
+ // Optional control dependency (for example, on range check)
+ Node* ctrl = NULL);
// Return a load of array element at idx.
Node* load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype);
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index b234d8b..243cf74 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -324,6 +324,10 @@
bool inline_updateBytesCRC32();
bool inline_updateByteBufferCRC32();
bool inline_multiplyToLen();
+ bool inline_squareToLen();
+ bool inline_mulAdd();
+ bool inline_montgomeryMultiply();
+ bool inline_montgomerySquare();
bool inline_profileBoolean();
};
@@ -527,6 +531,21 @@
if (!UseMultiplyToLenIntrinsic) return NULL;
break;
+ case vmIntrinsics::_squareToLen:
+ if (!UseSquareToLenIntrinsic) return NULL;
+ break;
+
+ case vmIntrinsics::_mulAdd:
+ if (!UseMulAddIntrinsic) return NULL;
+ break;
+
+ case vmIntrinsics::_montgomeryMultiply:
+ if (!UseMontgomeryMultiplyIntrinsic) return NULL;
+ break;
+ case vmIntrinsics::_montgomerySquare:
+ if (!UseMontgomerySquareIntrinsic) return NULL;
+ break;
+
case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
if (!UseAESIntrinsics) return NULL;
@@ -927,6 +946,17 @@
case vmIntrinsics::_multiplyToLen:
return inline_multiplyToLen();
+ case vmIntrinsics::_squareToLen:
+ return inline_squareToLen();
+
+ case vmIntrinsics::_mulAdd:
+ return inline_mulAdd();
+
+ case vmIntrinsics::_montgomeryMultiply:
+ return inline_montgomeryMultiply();
+ case vmIntrinsics::_montgomerySquare:
+ return inline_montgomerySquare();
+
case vmIntrinsics::_encodeISOArray:
return inline_encodeISOArray();
@@ -5767,11 +5797,12 @@
assert(callee()->signature()->size() == 5, "multiplyToLen has 5 parameters");
- Node* x = argument(1);
- Node* xlen = argument(2);
- Node* y = argument(3);
- Node* ylen = argument(4);
- Node* z = argument(5);
+ // no receiver because it is a static method
+ Node* x = argument(0);
+ Node* xlen = argument(1);
+ Node* y = argument(2);
+ Node* ylen = argument(3);
+ Node* z = argument(4);
const Type* x_type = x->Value(&_gvn);
const Type* y_type = y->Value(&_gvn);
@@ -5856,6 +5887,215 @@
return true;
}
+//-------------inline_squareToLen------------------------------------
+bool LibraryCallKit::inline_squareToLen() {
+ assert(UseSquareToLenIntrinsic, "not implementated on this platform");
+
+ address stubAddr = StubRoutines::squareToLen();
+ if (stubAddr == NULL) {
+ return false; // Intrinsic's stub is not implemented on this platform
+ }
+ const char* stubName = "squareToLen";
+
+ assert(callee()->signature()->size() == 4, "implSquareToLen has 4 parameters");
+
+ Node* x = argument(0);
+ Node* len = argument(1);
+ Node* z = argument(2);
+ Node* zlen = argument(3);
+
+ const Type* x_type = x->Value(&_gvn);
+ const Type* z_type = z->Value(&_gvn);
+ const TypeAryPtr* top_x = x_type->isa_aryptr();
+ const TypeAryPtr* top_z = z_type->isa_aryptr();
+ if (top_x == NULL || top_x->klass() == NULL ||
+ top_z == NULL || top_z->klass() == NULL) {
+ // failed array check
+ return false;
+ }
+
+ BasicType x_elem = x_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType z_elem = z_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ if (x_elem != T_INT || z_elem != T_INT) {
+ return false;
+ }
+
+
+ Node* x_start = array_element_address(x, intcon(0), x_elem);
+ Node* z_start = array_element_address(z, intcon(0), z_elem);
+
+ Node* call = make_runtime_call(RC_LEAF|RC_NO_FP,
+ OptoRuntime::squareToLen_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ x_start, len, z_start, zlen);
+
+ set_result(z);
+ return true;
+}
+
+//-------------inline_mulAdd------------------------------------------
+bool LibraryCallKit::inline_mulAdd() {
+ assert(UseMulAddIntrinsic, "not implementated on this platform");
+
+ address stubAddr = StubRoutines::mulAdd();
+ if (stubAddr == NULL) {
+ return false; // Intrinsic's stub is not implemented on this platform
+ }
+ const char* stubName = "mulAdd";
+
+ assert(callee()->signature()->size() == 5, "mulAdd has 5 parameters");
+
+ Node* out = argument(0);
+ Node* in = argument(1);
+ Node* offset = argument(2);
+ Node* len = argument(3);
+ Node* k = argument(4);
+
+ const Type* out_type = out->Value(&_gvn);
+ const Type* in_type = in->Value(&_gvn);
+ const TypeAryPtr* top_out = out_type->isa_aryptr();
+ const TypeAryPtr* top_in = in_type->isa_aryptr();
+ if (top_out == NULL || top_out->klass() == NULL ||
+ top_in == NULL || top_in->klass() == NULL) {
+ // failed array check
+ return false;
+ }
+
+ BasicType out_elem = out_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType in_elem = in_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ if (out_elem != T_INT || in_elem != T_INT) {
+ return false;
+ }
+
+ Node* outlen = load_array_length(out);
+ Node* new_offset = _gvn.transform(new (C) SubINode(outlen, offset));
+ Node* out_start = array_element_address(out, intcon(0), out_elem);
+ Node* in_start = array_element_address(in, intcon(0), in_elem);
+
+ Node* call = make_runtime_call(RC_LEAF|RC_NO_FP,
+ OptoRuntime::mulAdd_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ out_start,in_start, new_offset, len, k);
+ Node* result = _gvn.transform(new (C) ProjNode(call, TypeFunc::Parms));
+ set_result(result);
+ return true;
+}
+
+//-------------inline_montgomeryMultiply-----------------------------------
+bool LibraryCallKit::inline_montgomeryMultiply() {
+ address stubAddr = StubRoutines::montgomeryMultiply();
+ if (stubAddr == NULL) {
+ return false; // Intrinsic's stub is not implemented on this platform
+ }
+
+ assert(UseMontgomeryMultiplyIntrinsic, "not implemented on this platform");
+ const char* stubName = "montgomery_square";
+
+ assert(callee()->signature()->size() == 7, "montgomeryMultiply has 7 parameters");
+
+ Node* a = argument(0);
+ Node* b = argument(1);
+ Node* n = argument(2);
+ Node* len = argument(3);
+ Node* inv = argument(4);
+ Node* m = argument(6);
+
+ const Type* a_type = a->Value(&_gvn);
+ const TypeAryPtr* top_a = a_type->isa_aryptr();
+ const Type* b_type = b->Value(&_gvn);
+ const TypeAryPtr* top_b = b_type->isa_aryptr();
+ const Type* n_type = a->Value(&_gvn);
+ const TypeAryPtr* top_n = n_type->isa_aryptr();
+ const Type* m_type = a->Value(&_gvn);
+ const TypeAryPtr* top_m = m_type->isa_aryptr();
+ if (top_a == NULL || top_a->klass() == NULL ||
+ top_b == NULL || top_b->klass() == NULL ||
+ top_n == NULL || top_n->klass() == NULL ||
+ top_m == NULL || top_m->klass() == NULL) {
+ // failed array check
+ return false;
+ }
+
+ BasicType a_elem = a_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType b_elem = b_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType n_elem = n_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType m_elem = m_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ if (a_elem != T_INT || b_elem != T_INT || n_elem != T_INT || m_elem != T_INT) {
+ return false;
+ }
+
+ // Make the call
+ {
+ Node* a_start = array_element_address(a, intcon(0), a_elem);
+ Node* b_start = array_element_address(b, intcon(0), b_elem);
+ Node* n_start = array_element_address(n, intcon(0), n_elem);
+ Node* m_start = array_element_address(m, intcon(0), m_elem);
+
+ Node* call = make_runtime_call(RC_LEAF,
+ OptoRuntime::montgomeryMultiply_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ a_start, b_start, n_start, len, inv, top(),
+ m_start);
+ set_result(m);
+ }
+
+ return true;
+}
+
+bool LibraryCallKit::inline_montgomerySquare() {
+ address stubAddr = StubRoutines::montgomerySquare();
+ if (stubAddr == NULL) {
+ return false; // Intrinsic's stub is not implemented on this platform
+ }
+
+ assert(UseMontgomerySquareIntrinsic, "not implemented on this platform");
+ const char* stubName = "montgomery_square";
+
+ assert(callee()->signature()->size() == 6, "montgomerySquare has 6 parameters");
+
+ Node* a = argument(0);
+ Node* n = argument(1);
+ Node* len = argument(2);
+ Node* inv = argument(3);
+ Node* m = argument(5);
+
+ const Type* a_type = a->Value(&_gvn);
+ const TypeAryPtr* top_a = a_type->isa_aryptr();
+ const Type* n_type = a->Value(&_gvn);
+ const TypeAryPtr* top_n = n_type->isa_aryptr();
+ const Type* m_type = a->Value(&_gvn);
+ const TypeAryPtr* top_m = m_type->isa_aryptr();
+ if (top_a == NULL || top_a->klass() == NULL ||
+ top_n == NULL || top_n->klass() == NULL ||
+ top_m == NULL || top_m->klass() == NULL) {
+ // failed array check
+ return false;
+ }
+
+ BasicType a_elem = a_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType n_elem = n_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ BasicType m_elem = m_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+ if (a_elem != T_INT || n_elem != T_INT || m_elem != T_INT) {
+ return false;
+ }
+
+ // Make the call
+ {
+ Node* a_start = array_element_address(a, intcon(0), a_elem);
+ Node* n_start = array_element_address(n, intcon(0), n_elem);
+ Node* m_start = array_element_address(m, intcon(0), m_elem);
+
+ Node* call = make_runtime_call(RC_LEAF,
+ OptoRuntime::montgomerySquare_Type(),
+ stubAddr, stubName, TypePtr::BOTTOM,
+ a_start, n_start, len, inv, top(),
+ m_start);
+ set_result(m);
+ }
+
+ return true;
+}
+
/**
* Calculate CRC32 for byte.
diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp
index a6a7ab0..171032d 100644
--- a/hotspot/src/share/vm/opto/loopTransform.cpp
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp
@@ -2438,7 +2438,7 @@
//=============================================================================
// Process all the loops in the loop tree and replace any fill
-// patterns with an intrisc version.
+// patterns with an intrinsic version.
bool PhaseIdealLoop::do_intrinsify_fill() {
bool changed = false;
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
@@ -2536,8 +2536,9 @@
}
// Make sure the address expression can be handled. It should be
- // head->phi * elsize + con. head->phi might have a ConvI2L.
+ // head->phi * elsize + con. head->phi might have a ConvI2L(CastII()).
Node* elements[4];
+ Node* cast = NULL;
Node* conv = NULL;
bool found_index = false;
int count = store->in(MemNode::Address)->as_AddP()->unpack_offsets(elements, ARRAY_SIZE(elements));
@@ -2552,6 +2553,12 @@
conv = value;
value = value->in(1);
}
+ if (value->Opcode() == Op_CastII &&
+ value->as_CastII()->has_range_check()) {
+ // Skip range check dependent CastII nodes
+ cast = value;
+ value = value->in(1);
+ }
#endif
if (value != head->phi()) {
msg = "unhandled shift in address";
@@ -2564,9 +2571,16 @@
}
}
} else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
- if (n->in(1) == head->phi()) {
+ conv = n;
+ n = n->in(1);
+ if (n->Opcode() == Op_CastII &&
+ n->as_CastII()->has_range_check()) {
+ // Skip range check dependent CastII nodes
+ cast = n;
+ n = n->in(1);
+ }
+ if (n == head->phi()) {
found_index = true;
- conv = n;
} else {
msg = "unhandled input to ConvI2L";
}
@@ -2625,6 +2639,7 @@
// Address elements are ok
if (con) ok.set(con->_idx);
if (shift) ok.set(shift->_idx);
+ if (cast) ok.set(cast->_idx);
if (conv) ok.set(conv->_idx);
for (uint i = 0; msg == NULL && i < lpt->_body.size(); i++) {
diff --git a/hotspot/src/share/vm/opto/loopopts.cpp b/hotspot/src/share/vm/opto/loopopts.cpp
index 217effd..062daec 100644
--- a/hotspot/src/share/vm/opto/loopopts.cpp
+++ b/hotspot/src/share/vm/opto/loopopts.cpp
@@ -772,6 +772,9 @@
#ifdef _LP64
if (m->Opcode() == Op_ConvI2L)
return false;
+ if (m->is_CastII() && m->isa_CastII()->has_range_check()) {
+ return false;
+ }
#endif
}
}
diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp
index 26435b9..c4f6c16 100644
--- a/hotspot/src/share/vm/opto/node.cpp
+++ b/hotspot/src/share/vm/opto/node.cpp
@@ -521,6 +521,11 @@
C->add_macro_node(n);
if (is_expensive())
C->add_expensive_node(n);
+ // If the cloned node is a range check dependent CastII, add it to the list.
+ CastIINode* cast = n->isa_CastII();
+ if (cast != NULL && cast->has_range_check()) {
+ C->add_range_check_cast(cast);
+ }
n->set_idx(C->next_unique()); // Get new unique index as well
debug_only( n->verify_construction() );
@@ -649,6 +654,11 @@
if (is_expensive()) {
compile->remove_expensive_node(this);
}
+ CastIINode* cast = isa_CastII();
+ if (cast != NULL && cast->has_range_check()) {
+ compile->remove_range_check_cast(cast);
+ }
+
if (is_SafePoint()) {
as_SafePoint()->delete_replaced_nodes();
}
@@ -1344,6 +1354,10 @@
if (dead->is_expensive()) {
igvn->C->remove_expensive_node(dead);
}
+ CastIINode* cast = dead->isa_CastII();
+ if (cast != NULL && cast->has_range_check()) {
+ igvn->C->remove_range_check_cast(cast);
+ }
igvn->C->record_dead_node(dead->_idx);
// Kill all inputs to the dead guy
for (uint i=0; i < dead->req(); i++) {
diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp
index ffb096e..cba8fa8 100644
--- a/hotspot/src/share/vm/opto/node.hpp
+++ b/hotspot/src/share/vm/opto/node.hpp
@@ -54,6 +54,7 @@
class CatchNode;
class CatchProjNode;
class CheckCastPPNode;
+class CastIINode;
class ClearArrayNode;
class CmpNode;
class CodeBuffer;
@@ -603,6 +604,7 @@
DEFINE_CLASS_ID(Type, Node, 2)
DEFINE_CLASS_ID(Phi, Type, 0)
DEFINE_CLASS_ID(ConstraintCast, Type, 1)
+ DEFINE_CLASS_ID(CastII, ConstraintCast, 0)
DEFINE_CLASS_ID(CheckCastPP, Type, 2)
DEFINE_CLASS_ID(CMove, Type, 3)
DEFINE_CLASS_ID(SafePointScalarObject, Type, 4)
@@ -727,6 +729,7 @@
DEFINE_CLASS_QUERY(Catch)
DEFINE_CLASS_QUERY(CatchProj)
DEFINE_CLASS_QUERY(CheckCastPP)
+ DEFINE_CLASS_QUERY(CastII)
DEFINE_CLASS_QUERY(ConstraintCast)
DEFINE_CLASS_QUERY(ClearArray)
DEFINE_CLASS_QUERY(CMove)
diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp
index 71837d8..8bdd5b5 100644
--- a/hotspot/src/share/vm/opto/parse2.cpp
+++ b/hotspot/src/share/vm/opto/parse2.cpp
@@ -158,7 +158,9 @@
// Check for always knowing you are throwing a range-check exception
if (stopped()) return top();
- Node* ptr = array_element_address(ary, idx, type, sizetype);
+ // Make array address computation control dependent to prevent it
+ // from floating above the range check during loop optimizations.
+ Node* ptr = array_element_address(ary, idx, type, sizetype, control());
if (result2 != NULL) *result2 = elemtype;
@@ -461,9 +463,12 @@
#ifdef _LP64
// Clean the 32-bit int into a real 64-bit offset.
// Otherwise, the jint value 0 might turn into an offset of 0x0800000000.
- const TypeLong* lkeytype = TypeLong::make(CONST64(0), num_cases-1, Type::WidenMin);
- key_val = _gvn.transform( new (C) ConvI2LNode(key_val, lkeytype) );
+ const TypeInt* ikeytype = TypeInt::make(0, num_cases-1, Type::WidenMin);
+ // Make I2L conversion control dependent to prevent it from
+ // floating above the range check during loop optimizations.
+ key_val = C->constrained_convI2L(&_gvn, key_val, ikeytype, control());
#endif
+
// Shift the value by wordsize so we have an index into the table, rather
// than a switch value
Node *shiftWord = _gvn.MakeConX(wordSize);
diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp
index 2c42f9a..f090fcc 100644
--- a/hotspot/src/share/vm/opto/phaseX.cpp
+++ b/hotspot/src/share/vm/opto/phaseX.cpp
@@ -1339,6 +1339,10 @@
if (dead->is_expensive()) {
C->remove_expensive_node(dead);
}
+ CastIINode* cast = dead->isa_CastII();
+ if (cast != NULL && cast->has_range_check()) {
+ C->remove_range_check_cast(cast);
+ }
}
} // while (_stack.is_nonempty())
}
diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp
index 2b62a99..861f599 100644
--- a/hotspot/src/share/vm/opto/runtime.cpp
+++ b/hotspot/src/share/vm/opto/runtime.cpp
@@ -956,6 +956,94 @@
return TypeFunc::make(domain, range);
}
+const TypeFunc* OptoRuntime::squareToLen_Type() {
+ // create input type (domain)
+ int num_args = 4;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // x
+ fields[argp++] = TypeInt::INT; // len
+ fields[argp++] = TypePtr::NOTNULL; // z
+ fields[argp++] = TypeInt::INT; // zlen
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // no result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = NULL;
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
+ return TypeFunc::make(domain, range);
+}
+
+// for mulAdd calls, 2 pointers and 3 ints, returning int
+const TypeFunc* OptoRuntime::mulAdd_Type() {
+ // create input type (domain)
+ int num_args = 5;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // out
+ fields[argp++] = TypePtr::NOTNULL; // in
+ fields[argp++] = TypeInt::INT; // offset
+ fields[argp++] = TypeInt::INT; // len
+ fields[argp++] = TypeInt::INT; // k
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // returning carry (int)
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = TypeInt::INT;
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms+1, fields);
+ return TypeFunc::make(domain, range);
+}
+
+const TypeFunc* OptoRuntime::montgomeryMultiply_Type() {
+ // create input type (domain)
+ int num_args = 7;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // a
+ fields[argp++] = TypePtr::NOTNULL; // b
+ fields[argp++] = TypePtr::NOTNULL; // n
+ fields[argp++] = TypeInt::INT; // len
+ fields[argp++] = TypeLong::LONG; // inv
+ fields[argp++] = Type::HALF;
+ fields[argp++] = TypePtr::NOTNULL; // result
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = TypePtr::NOTNULL;
+
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
+ return TypeFunc::make(domain, range);
+}
+
+const TypeFunc* OptoRuntime::montgomerySquare_Type() {
+ // create input type (domain)
+ int num_args = 6;
+ int argcnt = num_args;
+ const Type** fields = TypeTuple::fields(argcnt);
+ int argp = TypeFunc::Parms;
+ fields[argp++] = TypePtr::NOTNULL; // a
+ fields[argp++] = TypePtr::NOTNULL; // n
+ fields[argp++] = TypeInt::INT; // len
+ fields[argp++] = TypeLong::LONG; // inv
+ fields[argp++] = Type::HALF;
+ fields[argp++] = TypePtr::NOTNULL; // result
+ assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
+ const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
+
+ // result type needed
+ fields = TypeTuple::fields(1);
+ fields[TypeFunc::Parms+0] = TypePtr::NOTNULL;
+
+ const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
+ return TypeFunc::make(domain, range);
+}
//------------- Interpreter state access for on stack replacement
diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp
index 3258c36..99f03f4 100644
--- a/hotspot/src/share/vm/opto/runtime.hpp
+++ b/hotspot/src/share/vm/opto/runtime.hpp
@@ -305,6 +305,12 @@
static const TypeFunc* multiplyToLen_Type();
+ static const TypeFunc* squareToLen_Type();
+
+ static const TypeFunc* mulAdd_Type();
+ static const TypeFunc* montgomeryMultiply_Type();
+ static const TypeFunc* montgomerySquare_Type();
+
static const TypeFunc* updateBytesCRC32_Type();
// leaf on stack replacement interpreter accessor types
diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp
index 785b8bb..f005ef4 100644
--- a/hotspot/src/share/vm/opto/superword.cpp
+++ b/hotspot/src/share/vm/opto/superword.cpp
@@ -2388,6 +2388,11 @@
return true;
}
} else if (opc == Op_ConvI2L) {
+ if (n->in(1)->Opcode() == Op_CastII &&
+ n->in(1)->as_CastII()->has_range_check()) {
+ // Skip range check dependent CastII nodes
+ n = n->in(1);
+ }
if (scaled_iv_plus_offset(n->in(1))) {
return true;
}
diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp
index 17b0e03..2167eb8 100644
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp
@@ -145,6 +145,12 @@
static double dsqrt(double f);
#endif
+ // Montgomery multiplication
+ static void montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints,
+ jint len, jlong inv, jint *m_ints);
+ static void montgomery_square(jint *a_ints, jint *n_ints,
+ jint len, jlong inv, jint *m_ints);
+
#ifdef __SOFTFP__
// C++ compiler generates soft float instructions as well as passing
// float and double in registers.
diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp
index f35cce9..eb30640 100644
--- a/hotspot/src/share/vm/runtime/stubRoutines.cpp
+++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp
@@ -136,6 +136,10 @@
address StubRoutines::_crc_table_adr = NULL;
address StubRoutines::_multiplyToLen = NULL;
+address StubRoutines::_squareToLen = NULL;
+address StubRoutines::_mulAdd = NULL;
+address StubRoutines::_montgomeryMultiply = NULL;
+address StubRoutines::_montgomerySquare = NULL;
double (* StubRoutines::_intrinsic_log )(double) = NULL;
double (* StubRoutines::_intrinsic_log10 )(double) = NULL;
diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp
index 819b9c4..42808a4 100644
--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp
+++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp
@@ -209,6 +209,10 @@
static address _crc_table_adr;
static address _multiplyToLen;
+ static address _squareToLen;
+ static address _mulAdd;
+ static address _montgomeryMultiply;
+ static address _montgomerySquare;
// These are versions of the java.lang.Math methods which perform
// the same operations as the intrinsic version. They are used for
@@ -367,6 +371,10 @@
static address crc_table_addr() { return _crc_table_adr; }
static address multiplyToLen() {return _multiplyToLen; }
+ static address squareToLen() {return _squareToLen; }
+ static address mulAdd() {return _mulAdd; }
+ static address montgomeryMultiply() { return _montgomeryMultiply; }
+ static address montgomerySquare() { return _montgomerySquare; }
static address select_fill_function(BasicType t, bool aligned, const char* &name);
diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp
index f1200e3..80b0115 100644
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp
@@ -813,6 +813,8 @@
static_field(StubRoutines, _updateBytesCRC32, address) \
static_field(StubRoutines, _crc_table_adr, address) \
static_field(StubRoutines, _multiplyToLen, address) \
+ static_field(StubRoutines, _squareToLen, address) \
+ static_field(StubRoutines, _mulAdd, address) \
\
/*****************/ \
/* SharedRuntime */ \
diff --git a/hotspot/test/compiler/intrinsics/montgomerymultiply/MontgomeryMultiplyTest.java b/hotspot/test/compiler/intrinsics/montgomerymultiply/MontgomeryMultiplyTest.java
new file mode 100644
index 0000000..5ddca7a
--- /dev/null
+++ b/hotspot/test/compiler/intrinsics/montgomerymultiply/MontgomeryMultiplyTest.java
@@ -0,0 +1,284 @@
+//
+// Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2015, Red Hat Inc. 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.
+//
+// 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.
+//
+//
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * @test
+ * @bug 8130150
+ * @library /testlibrary
+ * @requires (os.simpleArch == "x64") & (os.family != "windows")
+ * @summary Verify that the Montgomery multiply intrinsic works and correctly checks its arguments.
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseMontgomerySquareIntrinsic
+ * -XX:+UseMontgomeryMultiplyIntrinsic MontgomeryMultiplyTest
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseMontgomerySquareIntrinsic
+ * -XX:-UseMontgomeryMultiplyIntrinsic MontgomeryMultiplyTest
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseMontgomerySquareIntrinsic
+ * -XX:+UseMontgomeryMultiplyIntrinsic MontgomeryMultiplyTest
+ */
+
+public class MontgomeryMultiplyTest {
+
+ static final MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+ static final MethodHandle montgomeryMultiplyHandle, montgomerySquareHandle;
+ static final MethodHandle bigIntegerConstructorHandle;
+ static final Field bigIntegerMagField;
+
+ static {
+ // Use reflection to gain access to the methods we want to test.
+ try {
+ Method m = BigInteger.class.getDeclaredMethod("montgomeryMultiply",
+ /*a*/int[].class, /*b*/int[].class, /*n*/int[].class, /*len*/int.class,
+ /*inv*/long.class, /*product*/int[].class);
+ m.setAccessible(true);
+ montgomeryMultiplyHandle = lookup.unreflect(m);
+
+ m = BigInteger.class.getDeclaredMethod("montgomerySquare",
+ /*a*/int[].class, /*n*/int[].class, /*len*/int.class,
+ /*inv*/long.class, /*product*/int[].class);
+ m.setAccessible(true);
+ montgomerySquareHandle = lookup.unreflect(m);
+
+ Constructor c
+ = BigInteger.class.getDeclaredConstructor(int.class, int[].class);
+ c.setAccessible(true);
+ bigIntegerConstructorHandle = lookup.unreflectConstructor(c);
+
+ bigIntegerMagField = BigInteger.class.getDeclaredField("mag");
+ bigIntegerMagField.setAccessible(true);
+
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // Invoke either BigInteger.montgomeryMultiply or BigInteger.montgomerySquare.
+ int[] montgomeryMultiply(int[] a, int[] b, int[] n, int len, long inv,
+ int[] product) throws Throwable {
+ int[] result =
+ (a == b) ? (int[]) montgomerySquareHandle.invokeExact(a, n, len, inv, product)
+ : (int[]) montgomeryMultiplyHandle.invokeExact(a, b, n, len, inv, product);
+ return Arrays.copyOf(result, len);
+ }
+
+ // Invoke the private constructor BigInteger(int[]).
+ BigInteger newBigInteger(int[] val) throws Throwable {
+ return (BigInteger) bigIntegerConstructorHandle.invokeExact(1, val);
+ }
+
+ // Get the private field BigInteger.mag
+ int[] mag(BigInteger n) {
+ try {
+ return (int[]) bigIntegerMagField.get(n);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // Montgomery multiplication
+ // Calculate a * b * r^-1 mod n)
+ //
+ // R is a power of the word size
+ // N' = R^-1 mod N
+ //
+ // T := ab
+ // m := (T mod R)N' mod R [so 0 <= m < R]
+ // t := (T + mN)/R
+ // if t >= N then return t - N else return t
+ //
+ BigInteger montgomeryMultiply(BigInteger a, BigInteger b, BigInteger N,
+ int len, BigInteger n_prime)
+ throws Throwable {
+ BigInteger T = a.multiply(b);
+ BigInteger R = BigInteger.ONE.shiftLeft(len*32);
+ BigInteger mask = R.subtract(BigInteger.ONE);
+ BigInteger m = (T.and(mask)).multiply(n_prime);
+ m = m.and(mask); // i.e. m.mod(R)
+ T = T.add(m.multiply(N));
+ T = T.shiftRight(len*32); // i.e. T.divide(R)
+ if (T.compareTo(N) > 0) {
+ T = T.subtract(N);
+ }
+ return T;
+ }
+
+ // Call the Montgomery multiply intrinsic.
+ BigInteger montgomeryMultiply(int[] a_words, int[] b_words, int[] n_words,
+ int len, BigInteger inv)
+ throws Throwable {
+ BigInteger t = montgomeryMultiply(
+ newBigInteger(a_words),
+ newBigInteger(b_words),
+ newBigInteger(n_words),
+ len, inv);
+ return t;
+ }
+
+ // Check that the Montgomery multiply intrinsic returns the same
+ // result as the longhand calculation.
+ void check(int[] a_words, int[] b_words, int[] n_words, int len, BigInteger inv)
+ throws Throwable {
+ BigInteger n = newBigInteger(n_words);
+ BigInteger slow = montgomeryMultiply(a_words, b_words, n_words, len, inv);
+ BigInteger fast
+ = newBigInteger(montgomeryMultiply
+ (a_words, b_words, n_words, len, inv.longValue(), null));
+ // The intrinsic may not return the same value as the longhand
+ // calculation but they must have the same residue mod N.
+ if (!slow.mod(n).equals(fast.mod(n))) {
+ throw new RuntimeException();
+ }
+ }
+
+ Random rnd = new Random(0);
+
+ // Return a random value of length <= bits in an array of even length
+ int[] random_val(int bits) {
+ int len = (bits+63)/64; // i.e. length in longs
+ int[] val = new int[len*2];
+ for (int i = 0; i < val.length; i++)
+ val[i] = rnd.nextInt();
+ int leadingZeros = 64 - (bits & 64);
+ if (leadingZeros >= 32) {
+ val[0] = 0;
+ val[1] &= ~(-1l << (leadingZeros & 31));
+ } else {
+ val[0] &= ~(-1l << leadingZeros);
+ }
+ return val;
+ }
+
+ void testOneLength(int lenInBits, int lenInInts) throws Throwable {
+ BigInteger mod = new BigInteger(lenInBits, 2, rnd);
+ BigInteger r = BigInteger.ONE.shiftLeft(lenInInts * 32);
+ BigInteger n_prime = mod.modInverse(r).negate();
+
+ // Make n.length even, padding with a zero if necessary
+ int[] n = mag(mod);
+ if (n.length < lenInInts) {
+ int[] x = new int[lenInInts];
+ System.arraycopy(n, 0, x, lenInInts-n.length, n.length);
+ n = x;
+ }
+
+ for (int i = 0; i < 10000; i++) {
+ // multiply
+ check(random_val(lenInBits), random_val(lenInBits), n, lenInInts, n_prime);
+ // square
+ int[] tmp = random_val(lenInBits);
+ check(tmp, tmp, n, lenInInts, n_prime);
+ }
+ }
+
+ // Test the Montgomery multiply intrinsic with a bunch of random
+ // values of varying lengths. Do this for long enough that the
+ // caller of the intrinsic is C2-compiled.
+ void testResultValues() throws Throwable {
+ // Test a couple of interesting edge cases.
+ testOneLength(1024, 32);
+ testOneLength(1025, 34);
+ for (int j = 10; j > 0; j--) {
+ // Construct a random prime whose length in words is even
+ int lenInBits = rnd.nextInt(2048) + 64;
+ int lenInInts = (lenInBits + 63)/64*2;
+ testOneLength(lenInBits, lenInInts);
+ }
+ }
+
+ // Range checks
+ void testOneMontgomeryMultiplyCheck(int[] a, int[] b, int[] n, int len, long inv,
+ int[] product, Class klass) {
+ try {
+ montgomeryMultiply(a, b, n, len, inv, product);
+ } catch (Throwable ex) {
+ if (klass.isAssignableFrom(ex.getClass()))
+ return;
+ throw new RuntimeException(klass + " expected, " + ex + " was thrown");
+ }
+ throw new RuntimeException(klass + " expected, was not thrown");
+ }
+
+ void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
+ Class klass) {
+ testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), null, klass);
+ }
+
+ void testOneMontgomeryMultiplyCheck(int[] a, int[] b, BigInteger n, int len, BigInteger inv,
+ int[] product, Class klass) {
+ testOneMontgomeryMultiplyCheck(a, b, mag(n), len, inv.longValue(), product, klass);
+ }
+
+ void testMontgomeryMultiplyChecks() {
+ int[] blah = random_val(40);
+ int[] small = random_val(39);
+ BigInteger mod = new BigInteger(40*32 , 2, rnd);
+ BigInteger r = BigInteger.ONE.shiftLeft(40*32);
+ BigInteger n_prime = mod.modInverse(r).negate();
+
+ // Length out of range: square
+ testOneMontgomeryMultiplyCheck(blah, blah, mod, 41, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah, mod, 0, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah, mod, -1, n_prime, IllegalArgumentException.class);
+ // As above, but for multiply
+ testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 41, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 0, n_prime, IllegalArgumentException.class);
+
+ // Length odd
+ testOneMontgomeryMultiplyCheck(small, small, mod, 39, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, small, mod, 0, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, small, mod, -1, n_prime, IllegalArgumentException.class);
+ // As above, but for multiply
+ testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 39, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, small.clone(), mod, 0, n_prime, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, small.clone(), mod, -1, n_prime, IllegalArgumentException.class);
+
+ // array too small
+ testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah.clone(), mod, 40, n_prime, small, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, blah, mod, 40, n_prime, blah, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(blah, blah, mod, 40, n_prime, small, IllegalArgumentException.class);
+ testOneMontgomeryMultiplyCheck(small, small, mod, 40, n_prime, blah, IllegalArgumentException.class);
+ }
+
+ public static void main(String args[]) {
+ try {
+ new MontgomeryMultiplyTest().testMontgomeryMultiplyChecks();
+ new MontgomeryMultiplyTest().testResultValues();
+ } catch (Throwable ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java b/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java
new file mode 100644
index 0000000..1c58908
--- /dev/null
+++ b/hotspot/test/compiler/intrinsics/muladd/TestMulAdd.java
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @test
+ * @bug 8081778
+ * @summary Add C2 x86 intrinsic for BigInteger::mulAdd() method
+ *
+ * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:-UseSquareToLenIntrinsic -XX:-UseMultiplyToLenIntrinsic
+ * -XX:+UseMulAddIntrinsic
+ * -XX:CompileCommand=dontinline,TestMulAdd::main
+ * -XX:CompileCommand=option,TestMulAdd::base_multiply,ccstr,DisableIntrinsic,_mulAdd
+ * -XX:CompileCommand=option,java.math.BigInteger::multiply,ccstr,DisableIntrinsic,_mulAdd
+ * -XX:CompileCommand=option,java.math.BigInteger::square,ccstr,DisableIntrinsic,_mulAdd
+ * -XX:CompileCommand=option,java.math.BigInteger::squareToLen,ccstr,DisableIntrinsic,_mulAdd
+ * -XX:CompileCommand=option,java.math.BigInteger::mulAdd,ccstr,DisableIntrinsic,_mulAdd
+ * -XX:CompileCommand=inline,java.math.BigInteger::multiply
+ * -XX:CompileCommand=inline,java.math.BigInteger::square
+ * -XX:CompileCommand=inline,java.math.BigInteger::squareToLen
+ * -XX:CompileCommand=inline,java.math.BigInteger::mulAdd TestMulAdd
+ */
+
+import java.util.Random;
+import java.math.*;
+
+public class TestMulAdd {
+
+ // Avoid intrinsic by preventing inlining multiply() and mulAdd().
+ public static BigInteger base_multiply(BigInteger op1) {
+ return op1.multiply(op1);
+ }
+
+ // Generate mulAdd() intrinsic by inlining multiply().
+ public static BigInteger new_multiply(BigInteger op1) {
+ return op1.multiply(op1);
+ }
+
+ public static boolean bytecompare(BigInteger b1, BigInteger b2) {
+ byte[] data1 = b1.toByteArray();
+ byte[] data2 = b2.toByteArray();
+ if (data1.length != data2.length)
+ return false;
+ for (int i = 0; i < data1.length; i++) {
+ if (data1[i] != data2[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static String stringify(BigInteger b) {
+ String strout= "";
+ byte [] data = b.toByteArray();
+ for (int i = 0; i < data.length; i++) {
+ strout += (String.format("%02x",data[i]) + " ");
+ }
+ return strout;
+ }
+
+ public static void main(String args[]) throws Exception {
+
+ BigInteger oldsum = new BigInteger("0");
+ BigInteger newsum = new BigInteger("0");
+
+ BigInteger b1, b2, oldres, newres;
+
+ Random rand = new Random();
+ long seed = System.nanoTime();
+ Random rand1 = new Random();
+ long seed1 = System.nanoTime();
+ rand.setSeed(seed);
+ rand1.setSeed(seed1);
+
+ for (int j = 0; j < 100000; j++) {
+ int rand_int = rand1.nextInt(3136)+32;
+ b1 = new BigInteger(rand_int, rand);
+
+ oldres = base_multiply(b1);
+ newres = new_multiply(b1);
+
+ oldsum = oldsum.add(oldres);
+ newsum = newsum.add(newres);
+
+ if (!bytecompare(oldres,newres)) {
+ System.out.print("mismatch for:b1:" + stringify(b1) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres));
+ System.out.println(b1);
+ throw new Exception("Failed");
+ }
+ }
+ if (!bytecompare(oldsum,newsum)) {
+ System.out.println("Failure: oldsum:" + stringify(oldsum) + " newsum:" + stringify(newsum));
+ throw new Exception("Failed");
+ } else {
+ System.out.println("Success");
+ }
+ }
+}
diff --git a/hotspot/test/compiler/intrinsics/squaretolen/TestSquareToLen.java b/hotspot/test/compiler/intrinsics/squaretolen/TestSquareToLen.java
new file mode 100644
index 0000000..47c1e47
--- /dev/null
+++ b/hotspot/test/compiler/intrinsics/squaretolen/TestSquareToLen.java
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @test
+ * @bug 8081778
+ * @summary Add C2 x86 intrinsic for BigInteger::squareToLen() method
+ *
+ * @run main/othervm/timeout=600 -XX:-TieredCompilation -Xbatch
+ * -XX:+IgnoreUnrecognizedVMOptions
+ * -XX:+UseSquareToLenIntrinsic
+ * -XX:CompileCommand=exclude,TestSquareToLen::main
+ * -XX:CompileCommand=option,TestSquareToLen::base_multiply,ccstr,DisableIntrinsic,_squareToLen
+ * -XX:CompileCommand=option,java.math.BigInteger::multiply,ccstr,DisableIntrinsic,_squareToLen
+ * -XX:CompileCommand=option,java.math.BigInteger::square,ccstr,DisableIntrinsic,_squareToLen
+ * -XX:CompileCommand=option,java.math.BigInteger::squareToLen,ccstr,DisableIntrinsic,_squareToLen
+ * -XX:CompileCommand=inline,java.math.BigInteger::multiply
+ * -XX:CompileCommand=inline,java.math.BigInteger::square
+ * -XX:CompileCommand=inline,java.math.BigInteger::squareToLen TestSquareToLen
+ */
+
+import java.util.Random;
+import java.math.*;
+
+public class TestSquareToLen {
+
+ // Avoid intrinsic by preventing inlining multiply() and squareToLen().
+ public static BigInteger base_multiply(BigInteger op1) {
+ return op1.multiply(op1);
+ }
+
+ // Generate squareToLen() intrinsic by inlining multiply().
+ public static BigInteger new_multiply(BigInteger op1) {
+ return op1.multiply(op1);
+ }
+
+ public static boolean bytecompare(BigInteger b1, BigInteger b2) {
+ byte[] data1 = b1.toByteArray();
+ byte[] data2 = b2.toByteArray();
+ if (data1.length != data2.length)
+ return false;
+ for (int i = 0; i < data1.length; i++) {
+ if (data1[i] != data2[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static String stringify(BigInteger b) {
+ String strout= "";
+ byte [] data = b.toByteArray();
+ for (int i = 0; i < data.length; i++) {
+ strout += (String.format("%02x",data[i]) + " ");
+ }
+ return strout;
+ }
+
+ public static void main(String args[]) throws Exception {
+
+ BigInteger oldsum = new BigInteger("0");
+ BigInteger newsum = new BigInteger("0");
+
+ BigInteger b1, b2, oldres, newres;
+
+ Random rand = new Random();
+ long seed = System.nanoTime();
+ Random rand1 = new Random();
+ long seed1 = System.nanoTime();
+ rand.setSeed(seed);
+ rand1.setSeed(seed1);
+
+ for (int j = 0; j < 100000; j++) {
+ int rand_int = rand1.nextInt(3136)+32;
+ b1 = new BigInteger(rand_int, rand);
+
+ oldres = base_multiply(b1);
+ newres = new_multiply(b1);
+
+ oldsum = oldsum.add(oldres);
+ newsum = newsum.add(newres);
+
+ if (!bytecompare(oldres,newres)) {
+ System.out.print("mismatch for:b1:" + stringify(b1) + " :oldres:" + stringify(oldres) + " :newres:" + stringify(newres));
+ System.out.println(b1);
+ throw new Exception("Failed");
+ }
+ }
+ if (!bytecompare(oldsum,newsum)) {
+ System.out.println("Failure: oldsum:" + stringify(oldsum) + " newsum:" + stringify(newsum));
+ throw new Exception("Failed");
+ } else {
+ System.out.println("Success");
+ }
+ }
+}
diff --git a/hotspot/test/compiler/loopopts/TestLoopPeeling.java b/hotspot/test/compiler/loopopts/TestLoopPeeling.java
new file mode 100644
index 0000000..d2d2e3d
--- /dev/null
+++ b/hotspot/test/compiler/loopopts/TestLoopPeeling.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8078262
+ * @summary Tests correct dominator information after loop peeling.
+ * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestLoopPeeling::test* TestLoopPeeling
+ */
+public class TestLoopPeeling {
+
+ public int[] array = new int[100];
+
+ public static void main(String args[]) {
+ TestLoopPeeling test = new TestLoopPeeling();
+ try {
+ test.testArrayAccess(0, 1);
+ test.testArrayAllocation(0, 1);
+ } catch (Exception e) {
+ // Ignore exceptions
+ }
+ }
+
+ public void testArrayAccess(int index, int inc) {
+ int storeIndex = -1;
+
+ for (; index < 10; index += inc) {
+ // This loop invariant check triggers loop peeling because it can
+ // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+ if (inc == 42) return;
+
+ // This loop variant usage of LShiftL( ConvI2L( Phi(storeIndex) ) )
+ // prevents the split if optimization that would otherwise clone the
+ // LShiftL and ConvI2L nodes and assign them to their corresponding array
+ // address computation (see 'PhaseIdealLoop::split_if_with_blocks_post').
+ if (storeIndex > 0 && array[storeIndex] == 42) return;
+
+ if (index == 42) {
+ // This store and the corresponding range check are moved out of the
+ // loop and both used after old loop and the peeled iteration exit.
+ // For the peeled iteration, storeIndex is always -1 and the ConvI2L
+ // is replaced by TOP. However, the range check is not folded because
+ // we don't do the split if optimization in PhaseIdealLoop2.
+ // As a result, we have a (dead) control path from the peeled iteration
+ // to the StoreI but the data path is removed.
+ array[storeIndex] = 1;
+ return;
+ }
+
+ storeIndex++;
+ }
+ }
+
+ public byte[] testArrayAllocation(int index, int inc) {
+ int allocationCount = -1;
+ byte[] result;
+
+ for (; index < 10; index += inc) {
+ // This loop invariant check triggers loop peeling because it can
+ // be moved out of the loop (see 'IdealLoopTree::policy_peeling').
+ if (inc == 42) return null;
+
+ if (index == 42) {
+ // This allocation and the corresponding size check are moved out of the
+ // loop and both used after old loop and the peeled iteration exit.
+ // For the peeled iteration, allocationCount is always -1 and the ConvI2L
+ // is replaced by TOP. However, the size check is not folded because
+ // we don't do the split if optimization in PhaseIdealLoop2.
+ // As a result, we have a (dead) control path from the peeled iteration
+ // to the allocation but the data path is removed.
+ result = new byte[allocationCount];
+ return result;
+ }
+
+ allocationCount++;
+ }
+ return null;
+ }
+}
+
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index 046ae7b..4d8bb66 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -544,6 +544,19 @@
aa9485a887b7e983f9743c9c114de2055055300d jdk8u74-b01
b3325c0526621f9ddf82738373cc8f8947dab195 jdk8u74-b02
2b3d0e6f3cd179e2346679af2a8881bb6b20f968 jdk8u72-b31
+aeecbaa27f807ce0656a108cd0e81669724b8d1b jdk8u73-b00
+9009a8b2b55256764dd304902b04a3dea2597684 jdk8u73-b01
+7a021985ef009c3a88a206d6f295f17e382f98b9 jdk8u73-b02
+2e7b89c7f79794b872e73708fdaa3ed9331ec45d jdk8u74-b00
+aa9485a887b7e983f9743c9c114de2055055300d jdk8u74-b01
+b3325c0526621f9ddf82738373cc8f8947dab195 jdk8u74-b02
+c583ac51e2c78d6c59786b447986baf7b961518d jdk8u74-b31
+4c8fd0814bf0bcbc9666a29e1daa35c64c7bb57a jdk8u74-b32
+8cc52edbb741c42e09f4b132ca0a759d3de6f848 jdk8u77-b00
+8f0ed89698a28138065b6b941769650627636745 jdk8u77-b01
+27f1130320a55b6b89024cb8baa93c8767c516d2 jdk8u77-b02
+1c71899e85662239085fab94ad5c26441e7a80cd jdk8u77-b03
+a49d8c7db1e5b3ab84561069bd4ae63579139878 jdk8u77-b31
eca165c0654ac2e1926b50655e5ed5e9b73ca674 jdk8u75-b00
06cdf5dc679e0fef7c8e37c5c712b2c5891c1444 jdk8u75-b01
26c297e9f11b78b55cdefd22849ae4fe55042a5b jdk8u75-b02
@@ -556,6 +569,13 @@
1b3ef7edccbcee10699c647da23b98cfe7ec1ed7 jdk8u75-b09
e926cbc930ff727229191242a145ac625ddd7fa0 jdk8u75-b10
ce9b845453027a7a6309398b1ca2f32cf1534ae5 jdk8u75-b12
+8cc52edbb741c42e09f4b132ca0a759d3de6f848 jdk8u77-b00
+8f0ed89698a28138065b6b941769650627636745 jdk8u77-b01
+27f1130320a55b6b89024cb8baa93c8767c516d2 jdk8u77-b02
+1c71899e85662239085fab94ad5c26441e7a80cd jdk8u77-b03
+6b0d1f04c4808aaab32771e0892ac83e66714ecb jdk8u91-b00
+817898d53814da42f567995c921f3ea90016dccc jdk8u91-b13
+f6bda5729ff86e9691cd51f04261c3942974cecc jdk8u91-b14
acbcb6682c9b3e66f9cc61a6a62e8cb5f24c75d3 jdk8u76-b00
b3c914ad842d61818e0c5850409f77478b13acc6 jdk8u76-b01
7711933ec18462ece8a1b9a9527ec873c520b1ab jdk8u76-b02
@@ -568,3 +588,7 @@
2e5841f57df44b0f49e49ef3b827a7babf51bca7 jdk8u76-b09
8c4b258892025ee4d5df4109f974ba4665ee1208 jdk8u76-b10
6afc87bdaa7b93855e152aad437305ce0a42251a jdk8u76-b11
+233768376a3649b3f1f4653fe1c433271fc776ee jdk8u76-b12
+7e43e115dfafee70152a01b99aa9de25b4410570 jdk8u92-b00
+1bce84411d37ecf9a4335d1348f4b2f0b7ab6e08 jdk8u92-b13
+fb9f98ed6ef2505a424864f0a9468e59298fede6 jdk8u92-b14
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 7244326..f74c74b 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -531,12 +531,20 @@
4c28352ce19bc25be5de681868a8cddb3f3644a8 jdk8u72-b13
1a523f4b8cc77ef9dfb6d8191742dcd616cd9093 jdk8u72-b14
2f840ac0adf079f0d2f0bac7a9c3fae6ea651271 jdk8u72-b15
+744fab401c4b326f142f5110ad523b1b22f973c8 jdk8u72-b31
8da626c14c138dd41d4c685800351bf675048628 jdk8u73-b00
dfc9feacece48fa8450b997e463afae2c1539ac3 jdk8u73-b01
06fb882f8ed7ff3e58f7aa57e526e55c25ae9992 jdk8u73-b02
4a5f76111c0b056357d4bdd3e015d649de2db591 jdk8u74-b00
621e4ac137cd4a04ac1279e75d7fd0625765fd03 jdk8u74-b01
6cfef18571fd35f45bada34cf4da4b1492ddb878 jdk8u74-b02
+e2d83c243af551722c88fe2dd391364373e2bd3a jdk8u74-b31
+62291bde8b5ea2288c0729982681baec7cd0451f jdk8u74-b32
+a2f8a45d70b21e450fac7ae7d5ca71ce853cf3d0 jdk8u77-b00
+dd34713088c23b7c6ef1adc071dd635bc7bda744 jdk8u77-b01
+7c319d6e0d4c59ebde91b88ba1391ace165b2f01 jdk8u77-b02
+c6f67bea4466783433b1bf1f83a4eb6784a5eb55 jdk8u77-b03
+bedbb9b6cf59d5da68478a4b49bb2fdfc43a4f2c jdk8u77-b31
744fab401c4b326f142f5110ad523b1b22f973c8 jdk8u72-b31
7d7b3488f44e77bedbbcbdee5a4415e5a5bd930c jdk8u75-b00
d0161a6ecd3bf8c9953e979db8318177e4f2aa86 jdk8u75-b01
@@ -550,6 +558,13 @@
c302ec60295cd1a5b57e43c28e387556980d1350 jdk8u75-b09
945844568e956b9b68003f2b0f0528521b578d98 jdk8u75-b10
ee0c5d0875a3c6022fde6855c6353b68f746f6cd jdk8u75-b12
+a2f8a45d70b21e450fac7ae7d5ca71ce853cf3d0 jdk8u77-b00
+dd34713088c23b7c6ef1adc071dd635bc7bda744 jdk8u77-b01
+7c319d6e0d4c59ebde91b88ba1391ace165b2f01 jdk8u77-b02
+c6f67bea4466783433b1bf1f83a4eb6784a5eb55 jdk8u77-b03
+f66ee2329cd21c3485de1b8e0588f55882a56e0d jdk8u91-b00
+be5935ee38f1bc5132cf318f7badb61af86e2396 jdk8u91-b13
+e71f424e2c966a495b1d47693317288f291a794a jdk8u91-b14
6aba0f814a15966e47aeab61b466894b82c03c70 jdk8u76-b00
60789eebd1fe440255fd3f504221dc8b5553b8c2 jdk8u76-b01
8c7d476c446940edd913ba5a3ca36975febdac28 jdk8u76-b02
@@ -562,3 +577,7 @@
c50275b7bb7aa23ab6c83423f3b1d8e02f604854 jdk8u76-b09
9a7ea7a7ab734047e6bae7c354f503e7b71bf4c2 jdk8u76-b10
f31ede81ad1e14724b49c71bae8183e8e36986d0 jdk8u76-b11
+fad3981b329a0d309f4922bbca7335973e32e50f jdk8u76-b12
+451d700ba30ee0d3d201090a9d5dd606b988820e jdk8u92-b00
+008547c7dd3e324c46c2711b54285ca99e2ae0b9 jdk8u92-b13
+759ba92444a9e85434cb381f437aba65e3c9f780 jdk8u92-b14
diff --git a/jdk/.hgtags b/jdk/.hgtags
index bf7c770..74e17a5 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -534,12 +534,15 @@
d841d3fdae44f120883dab0a3a809a054cd0274b jdk8u72-b13
f6d24d424cd2af4d2612f7737d3d9a25f58b882d jdk8u72-b14
f3e86cc607260bae368b52d88d7bc8883ee767e3 jdk8u72-b15
+1d4b343084874b1afa1cdd504b9b1e50bab7f121 jdk8u72-b31
892eb9ab179650b89b7bab6bc42f079391c98624 jdk8u73-b00
9b77d3ca0d66a117c3cc0e0a74b8059545b22f0e jdk8u73-b01
2ab13901d6f14bab0dcf4823d5e378a421fba7e2 jdk8u73-b02
9a843dc6f959f62c61014a3a71ec9aa329f1daf1 jdk8u74-b00
e829ab80dfd828803aa8837411900faeaa1254a5 jdk8u74-b01
32c49f4a16599e376e4e46bb33c7bcc486e52ff3 jdk8u74-b02
+9c828e688240362b6f1b761b619cdaa070462c4e jdk8u74-b31
+6968ca30f8fdc9429fcd56187e16f46b215b474b jdk8u74-b32
1d4b343084874b1afa1cdd504b9b1e50bab7f121 jdk8u72-b31
7cfd2c51c501df909833aa0fb6e40c50c61621ed jdk8u75-b00
9e00a43602f87930c2318b2567002871ad9c59dd jdk8u75-b01
@@ -553,6 +556,14 @@
e6f4eb91a1fa895c2f4520e4cca0ae6f2ca14fbb jdk8u75-b09
93ea7fd6a5a26940d5a2b020c4e9012a85685a5a jdk8u75-b10
748ca164767d268e1739748f4df02b623397446c jdk8u75-b12
+02e1209648050922a5a9f2789d9d359795f6f834 jdk8u77-b00
+f08584a0fde9344b0aa4766984266ca68b9a5018 jdk8u77-b01
+1a3e81c05703bb36def80a57681e1692c866f621 jdk8u77-b02
+c44179bce874a97e93ffd7b76a226af417e017a4 jdk8u77-b03
+8c3f4e540348daed7263bae092b0e5f212478b00 jdk8u77-b31
+71f59a00df6c8f3bd5c6d6631a4988a431adab56 jdk8u91-b00
+7ade7a1ab10ff893f62cce9440b4a839aa19c250 jdk8u91-b13
+f8725698a870b6be82fad578e78a55910b259975 jdk8u91-b14
39baa472e20c13c0eb1243eb5dce589e82f78143 jdk8u76-b00
6ea3aea950d19d803475b3f4d704a2942e71b302 jdk8u76-b01
4de4cffb5988cd68959ce4bbd14c6d4547078c91 jdk8u76-b02
@@ -565,3 +576,7 @@
cbafa4c725f9d80fd369dd7979dd97682ae284e6 jdk8u76-b09
8274df0f06623726ff62324671a4ea24a4c3bfc5 jdk8u76-b10
17f5065e3873fe409bff8c026fa5fe6349b08157 jdk8u76-b11
+0ca25fdd520a0a74f0a488de263641d9f76b8664 jdk8u76-b12
+ea965fea71f612d65013192aa637d88e05915b10 jdk8u92-b00
+cc8d0d6c6f9543120836e70e0aa3fa9c9b6fe0f3 jdk8u92-b13
+4f06a20cdc59ce9742e6538ff4b9040baba0778a jdk8u92-b14
diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java
index 9bf5736..842af56 100644
--- a/jdk/src/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java
@@ -653,6 +653,9 @@
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);
+ // Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
+ // relies on the fact that spoofing is impossible if a class has a name
+ // of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
diff --git a/jdk/src/share/classes/java/lang/invoke/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java
index d0c6e42..bcc08e7 100644
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java
@@ -783,7 +783,7 @@
assert(isResolved() == isResolved);
}
- void checkForTypeAlias() {
+ void checkForTypeAlias(Class<?> refc) {
if (isInvocable()) {
MethodType type;
if (this.type instanceof MethodType)
@@ -791,16 +791,16 @@
else
this.type = type = getMethodType();
if (type.erase() == type) return;
- if (VerifyAccess.isTypeVisible(type, clazz)) return;
- throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
+ if (VerifyAccess.isTypeVisible(type, refc)) return;
+ throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
} else {
Class<?> type;
if (this.type instanceof Class<?>)
type = (Class<?>) this.type;
else
this.type = type = getFieldType();
- if (VerifyAccess.isTypeVisible(type, clazz)) return;
- throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
+ if (VerifyAccess.isTypeVisible(type, refc)) return;
+ throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
}
}
@@ -959,10 +959,25 @@
MemberName m = ref.clone(); // JVM will side-effect the ref
assert(refKind == m.getReferenceKind());
try {
+ // There are 4 entities in play here:
+ // * LC: lookupClass
+ // * REFC: symbolic reference class (MN.clazz before resolution);
+ // * DEFC: resolved method holder (MN.clazz after resolution);
+ // * PTYPES: parameter types (MN.type)
+ //
+ // What we care about when resolving a MemberName is consistency between DEFC and PTYPES.
+ // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM
+ // finishes the resolution, so do TA checks right after MHN.resolve() is over.
+ //
+ // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation,
+ // so it is safe to call a MH from any context.
+ //
+ // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
+ // participate in method selection.
m = MethodHandleNatives.resolve(m, lookupClass);
- m.checkForTypeAlias();
+ m.checkForTypeAlias(m.getDeclaringClass());
m.resolution = null;
- } catch (LinkageError ex) {
+ } catch (ClassNotFoundException | LinkageError ex) {
// JVM reports that the "bytecode behavior" would get an error
assert(!m.isResolved());
m.resolution = ex;
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
index 0f5169e..ecc1460 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
@@ -45,7 +45,7 @@
static native void init(MemberName self, Object ref);
static native void expand(MemberName self);
- static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
+ static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
static native int getMembers(Class<?> defc, String matchName, String matchSig,
int matchFlags, Class<?> caller, int skip, MemberName[] results);
diff --git a/jdk/src/share/classes/java/math/BigInteger.java b/jdk/src/share/classes/java/math/BigInteger.java
index 6fa5d42..e35c723 100644
--- a/jdk/src/share/classes/java/math/BigInteger.java
+++ b/jdk/src/share/classes/java/math/BigInteger.java
@@ -276,6 +276,15 @@
*/
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
/**
@@ -1573,7 +1582,7 @@
* 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) {
int xstart = xlen - 1;
int ystart = ylen - 1;
@@ -1897,6 +1906,43 @@
* int array z. The contents of x are not changed.
*/
private static final int[] squareToLen(int[] x, int len, int[] z) {
+ int zlen = len << 1;
+ if (z == null || z.length < zlen)
+ z = new int[zlen];
+
+ // Execute checks before calling intrinsified method.
+ implSquareToLenChecks(x, len, z, zlen);
+ return implSquareToLen(x, len, z, zlen);
+ }
+
+ /**
+ * Parameters validation.
+ */
+ private static void implSquareToLenChecks(int[] x, int len, int[] z, int zlen) throws RuntimeException {
+ if (len < 1) {
+ throw new IllegalArgumentException("invalid input length: " + len);
+ }
+ if (len > x.length) {
+ throw new IllegalArgumentException("input length out of bound: " +
+ len + " > " + x.length);
+ }
+ if (len * 2 > z.length) {
+ throw new IllegalArgumentException("input length out of bound: " +
+ (len * 2) + " > " + z.length);
+ }
+ if (zlen < 1) {
+ throw new IllegalArgumentException("invalid input length: " + zlen);
+ }
+ if (zlen > z.length) {
+ throw new IllegalArgumentException("input length out of bound: " +
+ len + " > " + z.length);
+ }
+ }
+
+ /**
+ * Java Runtime may use intrinsic for this method.
+ */
+ 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.
* Technique: Consider the partial products in the multiplication
@@ -1931,9 +1977,6 @@
* again. The low bit is simply a copy of the low bit of the
* input, so it doesn't need special care.
*/
- int zlen = len << 1;
- if (z == null || z.length < zlen)
- z = new int[zlen];
// Store the squares, right shifted one bit (i.e., divided by 2)
int lastProductLowWord = 0;
@@ -2501,6 +2544,75 @@
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.
+ 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);
+ }
+ 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
@@ -2579,6 +2691,17 @@
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);
@@ -2597,8 +2720,10 @@
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);
@@ -2606,6 +2731,8 @@
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();
@@ -2614,22 +2741,19 @@
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
@@ -2700,8 +2824,7 @@
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;
}
}
@@ -2713,8 +2836,7 @@
// 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;
}
}
@@ -2723,7 +2845,7 @@
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);
@@ -2791,6 +2913,32 @@
* Multiply an array by one word k and add to result, return the carry
*/
static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
+ implMulAddCheck(out, in, offset, len, k);
+ return implMulAdd(out, in, offset, len, k);
+ }
+
+ /**
+ * Parameters validation.
+ */
+ private static void implMulAddCheck(int[] out, int[] in, int offset, int len, int k) {
+ if (len > in.length) {
+ throw new IllegalArgumentException("input length is out of bound: " + len + " > " + in.length);
+ }
+ if (offset < 0) {
+ throw new IllegalArgumentException("input offset is invalid: " + offset);
+ }
+ if (offset > (out.length - 1)) {
+ throw new IllegalArgumentException("input offset is out of bound: " + offset + " > " + (out.length - 1));
+ }
+ if (len > (out.length - offset)) {
+ throw new IllegalArgumentException("input len is out of bound: " + len + " > " + (out.length - offset));
+ }
+ }
+
+ /**
+ * Java Runtime may use intrinsic for this method.
+ */
+ private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
long kLong = k & LONG_MASK;
long carry = 0;
diff --git a/jdk/src/share/classes/java/math/MutableBigInteger.java b/jdk/src/share/classes/java/math/MutableBigInteger.java
index 00e95aa..73a244f 100644
--- a/jdk/src/share/classes/java/math/MutableBigInteger.java
+++ b/jdk/src/share/classes/java/math/MutableBigInteger.java
@@ -2065,6 +2065,21 @@
}
/**
+ * 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.
*/
static MutableBigInteger modInverseBP2(MutableBigInteger mod, int k) {
diff --git a/jdk/src/share/classes/javax/swing/TimerQueue.java b/jdk/src/share/classes/javax/swing/TimerQueue.java
index a6791d6..7092b45 100644
--- a/jdk/src/share/classes/javax/swing/TimerQueue.java
+++ b/jdk/src/share/classes/javax/swing/TimerQueue.java
@@ -93,6 +93,9 @@
void startIfNeeded() {
if (! running) {
runningLock.lock();
+ if (running) {
+ return;
+ }
try {
final ThreadGroup threadGroup =
AppContext.getAppContext().getThreadGroup();
@@ -168,15 +171,17 @@
try {
while (running) {
try {
- Timer timer = queue.take().getTimer();
+ DelayedTimer runningTimer = queue.take();
+ Timer timer = runningTimer.getTimer();
timer.getLock().lock();
try {
DelayedTimer delayedTimer = timer.delayedTimer;
- if (delayedTimer != null) {
+ if (delayedTimer == runningTimer) {
/*
- * Timer is not removed after we get it from
- * the queue and before the lock on the timer is
- * acquired
+ * Timer is not removed (delayedTimer != null)
+ * or not removed and added (runningTimer == delayedTimer)
+ * after we get it from the queue and before the
+ * lock on the timer is acquired
*/
timer.post(); // have timer post an event
timer.delayedTimer = null;
diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
index 190b94b..f134ad1 100644
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -870,18 +870,13 @@
int orientation = SwingConstants.VERTICAL;
// find which scrollbar to scroll, or return if none
- if (toScroll == null || !toScroll.isVisible()) {
+ if (toScroll == null || !toScroll.isVisible()
+ || e.isShiftDown()) {
toScroll = scrollpane.getHorizontalScrollBar();
if (toScroll == null || !toScroll.isVisible()) {
return;
}
orientation = SwingConstants.HORIZONTAL;
- } else if(e.isShiftDown()){
- JScrollBar hScroll = scrollpane.getHorizontalScrollBar();
- if (hScroll != null && hScroll.isVisible()) {
- toScroll = hScroll;
- orientation = SwingConstants.HORIZONTAL;
- }
}
e.consume();
diff --git a/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
index fc870fc..532fa00 100644
--- a/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
+++ b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
@@ -185,22 +185,66 @@
* @param refc the class attempting to make the reference
*/
public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
- if (type == refc) return true; // easy check
+ if (type == refc) {
+ return true; // easy check
+ }
while (type.isArray()) type = type.getComponentType();
- if (type.isPrimitive() || type == Object.class) return true;
- ClassLoader parent = type.getClassLoader();
- if (parent == null) return true;
- ClassLoader child = refc.getClassLoader();
- if (child == null) return false;
- if (parent == child || loadersAreRelated(parent, child, true))
+ if (type.isPrimitive() || type == Object.class) {
return true;
- // Do it the hard way: Look up the type name from the refc loader.
- try {
- Class<?> res = child.loadClass(type.getName());
- return (type == res);
- } catch (ClassNotFoundException ex) {
+ }
+ ClassLoader typeLoader = type.getClassLoader();
+ ClassLoader refcLoader = refc.getClassLoader();
+ if (typeLoader == refcLoader) {
+ return true;
+ }
+ if (refcLoader == null && typeLoader != null) {
return false;
}
+ if (typeLoader == null && type.getName().startsWith("java.")) {
+ // Note: The API for actually loading classes, ClassLoader.defineClass,
+ // guarantees that classes with names beginning "java." cannot be aliased,
+ // because class loaders cannot load them directly.
+ return true;
+ }
+
+ // Do it the hard way: Look up the type name from the refc loader.
+ //
+ // Force the refc loader to report and commit to a particular binding for this type name (type.getName()).
+ //
+ // In principle, this query might force the loader to load some unrelated class,
+ // which would cause this query to fail (and the original caller to give up).
+ // This would be wasted effort, but it is expected to be very rare, occurring
+ // only when an attacker is attempting to create a type alias.
+ // In the normal case, one class loader will simply delegate to the other,
+ // and the same type will be visible through both, with no extra loading.
+ //
+ // It is important to go through Class.forName instead of ClassLoader.loadClass
+ // because Class.forName goes through the JVM system dictionary, which records
+ // the class lookup once for all. This means that even if a not-well-behaved class loader
+ // would "change its mind" about the meaning of the name, the Class.forName request
+ // will use the result cached in the JVM system dictionary. Note that the JVM system dictionary
+ // will record the first successful result. Unsuccessful results are not stored.
+ //
+ // We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary
+ // class loader about the binding of the proposed name (type.getName()).
+ // The looked up type ("res") is compared for equality against the proposed
+ // type ("type") and then is discarded. Thus, the worst that can happen to
+ // the "child" class loader is that it is bothered to load and report a class
+ // that differs from "type"; this happens once due to JVM system dictionary
+ // memoization. And the caller never gets to look at the alternate type binding
+ // ("res"), whether it exists or not.
+ final String name = type.getName();
+ Class<?> res = java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Class>() {
+ public Class<?> run() {
+ try {
+ return Class.forName(name, false, refcLoader);
+ } catch (ClassNotFoundException | LinkageError e) {
+ return null; // Assume the class is not found
+ }
+ }
+ });
+ return (type == res);
}
/**
diff --git a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java
index fdc295c..19211ae 100644
--- a/jdk/src/share/classes/sun/security/pkcs/PKCS7.java
+++ b/jdk/src/share/classes/sun/security/pkcs/PKCS7.java
@@ -802,7 +802,8 @@
byte[] content,
String signatureAlgorithm,
URI tsaURI,
- String tSAPolicyID)
+ String tSAPolicyID,
+ String tSADigestAlg)
throws CertificateException, IOException, NoSuchAlgorithmException
{
@@ -811,7 +812,8 @@
if (tsaURI != null) {
// Timestamp the signature
HttpTimestamper tsa = new HttpTimestamper(tsaURI);
- byte[] tsToken = generateTimestampToken(tsa, tSAPolicyID, signature);
+ byte[] tsToken = generateTimestampToken(
+ tsa, tSAPolicyID, tSADigestAlg, signature);
// Insert the timestamp token into the PKCS #7 signer info element
// (as an unsigned attribute)
@@ -869,6 +871,7 @@
*/
private static byte[] generateTimestampToken(Timestamper tsa,
String tSAPolicyID,
+ String tSADigestAlg,
byte[] toBeTimestamped)
throws IOException, CertificateException
{
@@ -876,11 +879,10 @@
MessageDigest messageDigest = null;
TSRequest tsQuery = null;
try {
- // SHA-1 is always used.
- messageDigest = MessageDigest.getInstance("SHA-1");
+ messageDigest = MessageDigest.getInstance(tSADigestAlg);
tsQuery = new TSRequest(tSAPolicyID, toBeTimestamped, messageDigest);
} catch (NoSuchAlgorithmException e) {
- // ignore
+ throw new IllegalArgumentException(e);
}
// Generate a nonce
@@ -908,9 +910,13 @@
PKCS7 tsToken = tsReply.getToken();
TimestampToken tst = tsReply.getTimestampToken();
- if (!tst.getHashAlgorithm().getName().equals("SHA-1")) {
- throw new IOException("Digest algorithm not SHA-1 in "
- + "timestamp token");
+ try {
+ if (!tst.getHashAlgorithm().equals(AlgorithmId.get(tSADigestAlg))) {
+ throw new IOException("Digest algorithm not " + tSADigestAlg + " in "
+ + "timestamp token");
+ }
+ } catch (NoSuchAlgorithmException nase) {
+ throw new IllegalArgumentException(); // should have been caught before
}
if (!MessageDigest.isEqual(tst.getHashedMessage(),
tsQuery.getHashedMessage())) {
diff --git a/jdk/src/share/classes/sun/security/tools/jarsigner/JarSignerParameters.java b/jdk/src/share/classes/sun/security/tools/jarsigner/JarSignerParameters.java
new file mode 100644
index 0000000..fe75f9d
--- /dev/null
+++ b/jdk/src/share/classes/sun/security/tools/jarsigner/JarSignerParameters.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016, 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 sun.security.tools.jarsigner;
+
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.net.URI;
+import java.util.zip.*;
+
+import com.sun.jarsigner.ContentSignerParameters;
+
+class JarSignerParameters implements ContentSignerParameters {
+
+ private String[] args;
+ private URI tsa;
+ private X509Certificate tsaCertificate;
+ private byte[] signature;
+ private String signatureAlgorithm;
+ private X509Certificate[] signerCertificateChain;
+ private byte[] content;
+ private ZipFile source;
+ private String tSAPolicyID;
+ private String tSADigestAlg;
+
+ /**
+ * Create a new object.
+ */
+ JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
+ String tSAPolicyID, String tSADigestAlg,
+ byte[] signature, String signatureAlgorithm,
+ X509Certificate[] signerCertificateChain, byte[] content,
+ ZipFile source) {
+
+ if (signature == null || signatureAlgorithm == null ||
+ signerCertificateChain == null || tSADigestAlg == null) {
+ throw new NullPointerException();
+ }
+ this.args = args;
+ this.tsa = tsa;
+ this.tsaCertificate = tsaCertificate;
+ this.tSAPolicyID = tSAPolicyID;
+ this.tSADigestAlg = tSADigestAlg;
+ this.signature = signature;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signerCertificateChain = signerCertificateChain;
+ this.content = content;
+ this.source = source;
+ }
+
+ /**
+ * Retrieves the command-line arguments.
+ *
+ * @return The command-line arguments. May be null.
+ */
+ public String[] getCommandLine() {
+ return args;
+ }
+
+ /**
+ * Retrieves the identifier for a Timestamping Authority (TSA).
+ *
+ * @return The TSA identifier. May be null.
+ */
+ public URI getTimestampingAuthority() {
+ return tsa;
+ }
+
+ /**
+ * Retrieves the certificate for a Timestamping Authority (TSA).
+ *
+ * @return The TSA certificate. May be null.
+ */
+ public X509Certificate getTimestampingAuthorityCertificate() {
+ return tsaCertificate;
+ }
+
+ public String getTSAPolicyID() {
+ return tSAPolicyID;
+ }
+
+ public String getTSADigestAlg() {
+ return tSADigestAlg;
+ }
+
+ /**
+ * Retrieves the signature.
+ *
+ * @return The non-null signature bytes.
+ */
+ public byte[] getSignature() {
+ return signature;
+ }
+
+ /**
+ * Retrieves the name of the signature algorithm.
+ *
+ * @return The non-null string name of the signature algorithm.
+ */
+ public String getSignatureAlgorithm() {
+ return signatureAlgorithm;
+ }
+
+ /**
+ * Retrieves the signer's X.509 certificate chain.
+ *
+ * @return The non-null array of X.509 public-key certificates.
+ */
+ public X509Certificate[] getSignerCertificateChain() {
+ return signerCertificateChain;
+ }
+
+ /**
+ * Retrieves the content that was signed.
+ *
+ * @return The content bytes. May be null.
+ */
+ public byte[] getContent() {
+ return content;
+ }
+
+ /**
+ * Retrieves the original source ZIP file before it was signed.
+ *
+ * @return The original ZIP file. May be null.
+ */
+ public ZipFile getSource() {
+ return source;
+ }
+}
diff --git a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java
index 35f33c8..37b04c9 100644
--- a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java
+++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java
@@ -139,6 +139,7 @@
String tsaAlias; // alias for the Timestamping Authority's certificate
String altCertChain; // file to read alternative cert chain from
String tSAPolicyID;
+ String tSADigestAlg = "SHA-256";
boolean verify = false; // verify the jar
String verbose = null; // verbose output when signing/verifying
boolean showcerts = false; // show certs when verifying
@@ -342,6 +343,9 @@
} else if (collator.compare(flags, "-tsapolicyid") ==0) {
if (++n == args.length) usageNoArg();
tSAPolicyID = args[n];
+ } else if (collator.compare(flags, "-tsadigestalg") ==0) {
+ if (++n == args.length) usageNoArg();
+ tSADigestAlg = args[n];
} else if (collator.compare(flags, "-debug") ==0) {
debug = true;
} else if (collator.compare(flags, "-keypass") ==0) {
@@ -536,6 +540,9 @@
(".tsapolicyid.tsapolicyid.for.Timestamping.Authority"));
System.out.println();
System.out.println(rb.getString
+ (".tsadigestalg.algorithm.of.digest.data.in.timestamping.request"));
+ System.out.println();
+ System.out.println(rb.getString
(".altsigner.class.class.name.of.an.alternative.signing.mechanism"));
System.out.println();
System.out.println(rb.getString
@@ -1270,8 +1277,8 @@
try {
block =
sf.generateBlock(privateKey, sigalg, certChain,
- externalSF, tsaUrl, tsaCert, tSAPolicyID, signingMechanism, args,
- zipFile);
+ externalSF, tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg,
+ signingMechanism, args, zipFile);
} catch (SocketTimeoutException e) {
// Provide a helpful message when TSA is beyond a firewall
error(rb.getString("unable.to.sign.jar.") +
@@ -2268,13 +2275,14 @@
boolean externalSF, String tsaUrl,
X509Certificate tsaCert,
String tSAPolicyID,
+ String tSADigestAlg,
ContentSigner signingMechanism,
String[] args, ZipFile zipFile)
throws NoSuchAlgorithmException, InvalidKeyException, IOException,
SignatureException, CertificateException
{
return new Block(this, privateKey, sigalg, certChain, externalSF,
- tsaUrl, tsaCert, tSAPolicyID, signingMechanism, args, zipFile);
+ tsaUrl, tsaCert, tSAPolicyID, tSADigestAlg, signingMechanism, args, zipFile);
}
@@ -2288,8 +2296,8 @@
*/
Block(SignatureFile sfg, PrivateKey privateKey, String sigalg,
X509Certificate[] certChain, boolean externalSF, String tsaUrl,
- X509Certificate tsaCert, String tSAPolicyID, ContentSigner signingMechanism,
- String[] args, ZipFile zipFile)
+ X509Certificate tsaCert, String tSAPolicyID, String tSADigestAlg,
+ ContentSigner signingMechanism, String[] args, ZipFile zipFile)
throws NoSuchAlgorithmException, InvalidKeyException, IOException,
SignatureException, CertificateException {
@@ -2371,7 +2379,8 @@
// Assemble parameters for the signing mechanism
ContentSignerParameters params =
- new JarSignerParameters(args, tsaUri, tsaCert, tSAPolicyID, signature,
+ new JarSignerParameters(args, tsaUri, tsaCert, tSAPolicyID,
+ tSADigestAlg, signature,
signatureAlgorithm, certChain, content, zipFile);
// Generate the signature block
@@ -2400,120 +2409,3 @@
}
}
}
-
-
-/*
- * This object encapsulates the parameters used to perform content signing.
- */
-class JarSignerParameters implements ContentSignerParameters {
-
- private String[] args;
- private URI tsa;
- private X509Certificate tsaCertificate;
- private byte[] signature;
- private String signatureAlgorithm;
- private X509Certificate[] signerCertificateChain;
- private byte[] content;
- private ZipFile source;
- private String tSAPolicyID;
-
- /**
- * Create a new object.
- */
- JarSignerParameters(String[] args, URI tsa, X509Certificate tsaCertificate,
- String tSAPolicyID,
- byte[] signature, String signatureAlgorithm,
- X509Certificate[] signerCertificateChain, byte[] content,
- ZipFile source) {
-
- if (signature == null || signatureAlgorithm == null ||
- signerCertificateChain == null) {
- throw new NullPointerException();
- }
- this.args = args;
- this.tsa = tsa;
- this.tsaCertificate = tsaCertificate;
- this.tSAPolicyID = tSAPolicyID;
- this.signature = signature;
- this.signatureAlgorithm = signatureAlgorithm;
- this.signerCertificateChain = signerCertificateChain;
- this.content = content;
- this.source = source;
- }
-
- /**
- * Retrieves the command-line arguments.
- *
- * @return The command-line arguments. May be null.
- */
- public String[] getCommandLine() {
- return args;
- }
-
- /**
- * Retrieves the identifier for a Timestamping Authority (TSA).
- *
- * @return The TSA identifier. May be null.
- */
- public URI getTimestampingAuthority() {
- return tsa;
- }
-
- /**
- * Retrieves the certificate for a Timestamping Authority (TSA).
- *
- * @return The TSA certificate. May be null.
- */
- public X509Certificate getTimestampingAuthorityCertificate() {
- return tsaCertificate;
- }
-
- public String getTSAPolicyID() {
- return tSAPolicyID;
- }
-
- /**
- * Retrieves the signature.
- *
- * @return The non-null signature bytes.
- */
- public byte[] getSignature() {
- return signature;
- }
-
- /**
- * Retrieves the name of the signature algorithm.
- *
- * @return The non-null string name of the signature algorithm.
- */
- public String getSignatureAlgorithm() {
- return signatureAlgorithm;
- }
-
- /**
- * Retrieves the signer's X.509 certificate chain.
- *
- * @return The non-null array of X.509 public-key certificates.
- */
- public X509Certificate[] getSignerCertificateChain() {
- return signerCertificateChain;
- }
-
- /**
- * Retrieves the content that was signed.
- *
- * @return The content bytes. May be null.
- */
- public byte[] getContent() {
- return content;
- }
-
- /**
- * Retrieves the original source ZIP file before it was signed.
- *
- * @return The original ZIP file. May be null.
- */
- public ZipFile getSource() {
- return source;
- }
-}
diff --git a/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java b/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java
index 77b0628..db35b1e 100644
--- a/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java
+++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Resources.java
@@ -88,6 +88,8 @@
"[-tsacert <alias>] public key certificate for Timestamping Authority"},
{".tsapolicyid.tsapolicyid.for.Timestamping.Authority",
"[-tsapolicyid <oid>] TSAPolicyID for Timestamping Authority"},
+ {".tsadigestalg.algorithm.of.digest.data.in.timestamping.request",
+ "[-tsadigestalg <algorithm>] algorithm of digest data in timestamping request"},
{".altsigner.class.class.name.of.an.alternative.signing.mechanism",
"[-altsigner <class>] class name of an alternative signing mechanism"},
{".altsignerpath.pathlist.location.of.an.alternative.signing.mechanism",
diff --git a/jdk/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java b/jdk/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java
index 3e50419..c149f8b 100644
--- a/jdk/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java
+++ b/jdk/src/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java
@@ -132,9 +132,14 @@
}
}
}
+ String tSADigestAlg = "SHA-256";
+ if (params instanceof JarSignerParameters) {
+ tSADigestAlg = ((JarSignerParameters)params).getTSADigestAlg();
+ }
return PKCS7.generateSignedData(signature, signerChain, content,
params.getSignatureAlgorithm(), tsaURI,
- params.getTSAPolicyID());
+ params.getTSAPolicyID(),
+ tSADigestAlg);
}
/**
diff --git a/jdk/src/windows/classes/sun/security/mscapi/KeyStore.java b/jdk/src/windows/classes/sun/security/mscapi/KeyStore.java
index abaa2e3..cbf4240 100644
--- a/jdk/src/windows/classes/sun/security/mscapi/KeyStore.java
+++ b/jdk/src/windows/classes/sun/security/mscapi/KeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -189,8 +189,10 @@
/*
* The keystore entries.
+ * Keys in the map are unique aliases (thus can differ from
+ * KeyEntry.getAlias())
*/
- private Collection<KeyEntry> entries = new ArrayList<KeyEntry>();
+ private Map<String,KeyEntry> entries = new HashMap<>();
/*
* The keystore name.
@@ -250,13 +252,10 @@
if (engineIsKeyEntry(alias) == false)
return null;
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey();
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ return (entry == null)
+ ? null
+ : entry.getPrivateKey();
}
/**
@@ -276,15 +275,13 @@
return null;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- X509Certificate[] certChain = entry.getCertificateChain();
-
- return certChain.clone();
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ X509Certificate[] certChain = (entry == null)
+ ? null
+ : entry.getCertificateChain();
+ return (certChain == null)
+ ? null
+ : certChain.clone();
}
/**
@@ -308,15 +305,13 @@
return null;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias()))
- {
- X509Certificate[] certChain = entry.getCertificateChain();
- return certChain.length == 0 ? null : certChain[0];
- }
- }
-
- return null;
+ KeyEntry entry = entries.get(alias);
+ X509Certificate[] certChain = (entry == null)
+ ? null
+ : entry.getCertificateChain();
+ return (certChain == null || certChain.length == 0)
+ ? null
+ : certChain[0];
}
/**
@@ -380,29 +375,32 @@
if (key instanceof RSAPrivateCrtKey) {
- KeyEntry entry = null;
- boolean found = false;
+ KeyEntry entry = entries.get(alias);
- for (KeyEntry e : entries) {
- if (alias.equals(e.getAlias())) {
- found = true;
- entry = e;
- break;
+ X509Certificate[] xchain;
+ if (chain != null) {
+ if (chain instanceof X509Certificate[]) {
+ xchain = (X509Certificate[]) chain;
+ } else {
+ xchain = new X509Certificate[chain.length];
+ System.arraycopy(chain, 0, xchain, 0, chain.length);
}
+ } else {
+ xchain = null;
}
- if (! found) {
+ if (entry == null) {
entry =
//TODO new KeyEntry(alias, key, (X509Certificate[]) chain);
- new KeyEntry(alias, null, (X509Certificate[]) chain);
- entries.add(entry);
+ new KeyEntry(alias, null, xchain);
+ storeWithUniqueAlias(alias, entry);
}
entry.setAlias(alias);
try {
entry.setPrivateKey((RSAPrivateCrtKey) key);
- entry.setCertificateChain((X509Certificate[]) chain);
+ entry.setCertificateChain(xchain);
} catch (CertificateException ce) {
throw new KeyStoreException(ce);
@@ -474,23 +472,14 @@
// TODO - build CryptoAPI chain?
X509Certificate[] chain =
new X509Certificate[]{ (X509Certificate) cert };
- KeyEntry entry = null;
- boolean found = false;
+ KeyEntry entry = entries.get(alias);
- for (KeyEntry e : entries) {
- if (alias.equals(e.getAlias())) {
- found = true;
- entry = e;
- break;
- }
- }
-
- if (! found) {
+ if (entry == null) {
entry =
new KeyEntry(alias, null, chain);
- entries.add(entry);
-
+ storeWithUniqueAlias(alias, entry);
}
+
if (entry.getPrivateKey() == null) { // trusted-cert entry
entry.setAlias(alias);
@@ -522,32 +511,26 @@
throw new KeyStoreException("alias must not be null");
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
+ KeyEntry entry = entries.remove(alias);
+ if (entry != null) {
+ // Get end-entity certificate and remove from system cert store
+ X509Certificate[] certChain = entry.getCertificateChain();
+ if (certChain != null) {
- // Get end-entity certificate and remove from system cert store
- X509Certificate[] certChain = entry.getCertificateChain();
- if (certChain != null) {
+ try {
- try {
-
- byte[] encoding = certChain[0].getEncoded();
- removeCertificate(getName(), alias, encoding,
+ byte[] encoding = certChain[0].getEncoded();
+ removeCertificate(getName(), entry.getAlias(), encoding,
encoding.length);
- } catch (CertificateException e) {
- throw new KeyStoreException("Cannot remove entry: " +
- e);
- }
+ } catch (CertificateException e) {
+ throw new KeyStoreException("Cannot remove entry: ", e);
}
- Key privateKey = entry.getPrivateKey();
- if (privateKey != null) {
- destroyKeyContainer(
- Key.getContainerName(privateKey.getHCryptProvider()));
- }
-
- entries.remove(entry);
- break;
+ }
+ Key privateKey = entry.getPrivateKey();
+ if (privateKey != null) {
+ destroyKeyContainer(
+ Key.getContainerName(privateKey.getHCryptProvider()));
}
}
}
@@ -558,8 +541,7 @@
* @return enumeration of the alias names
*/
public Enumeration<String> engineAliases() {
-
- final Iterator<KeyEntry> iter = entries.iterator();
+ final Iterator<String> iter = entries.keySet().iterator();
return new Enumeration<String>()
{
@@ -570,8 +552,7 @@
public String nextElement()
{
- KeyEntry entry = iter.next();
- return entry.getAlias();
+ return iter.next();
}
};
}
@@ -584,15 +565,7 @@
* @return true if the alias exists, false otherwise
*/
public boolean engineContainsAlias(String alias) {
- for (Enumeration<String> enumerator = engineAliases();
- enumerator.hasMoreElements();)
- {
- String a = enumerator.nextElement();
-
- if (a.equals(alias))
- return true;
- }
- return false;
+ return entries.containsKey(alias);
}
/**
@@ -617,13 +590,8 @@
return false;
}
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey() != null;
- }
- }
-
- return false;
+ KeyEntry entry = entries.get(alias);
+ return entry != null && entry.getPrivateKey() != null;
}
/**
@@ -633,15 +601,14 @@
* @return true if the entry identified by the given alias is a
* <i>trusted certificate entry</i>, false otherwise.
*/
- public boolean engineIsCertificateEntry(String alias)
- {
- for (KeyEntry entry : entries) {
- if (alias.equals(entry.getAlias())) {
- return entry.getPrivateKey() == null;
- }
+ public boolean engineIsCertificateEntry(String alias) {
+
+ if (alias == null) {
+ return false;
}
- return false;
+ KeyEntry entry = entries.get(alias);
+ return entry != null && entry.getPrivateKey() == null;
}
/**
@@ -660,9 +627,10 @@
* @return the (alias) name of the first entry with matching certificate,
* or null if no such entry exists in this keystore.
*/
- public String engineGetCertificateAlias(Certificate cert)
- {
- for (KeyEntry entry : entries) {
+ public String engineGetCertificateAlias(Certificate cert) {
+
+ for (Map.Entry<String,KeyEntry> mapEntry : entries.entrySet()) {
+ KeyEntry entry = mapEntry.getValue();
if (entry.certChain != null && entry.certChain[0].equals(cert)) {
return entry.getAlias();
}
@@ -755,7 +723,7 @@
try {
// Load keys and/or certificate chains
- loadKeysOrCertificateChains(getName(), entries);
+ loadKeysOrCertificateChains(getName());
} catch (KeyStoreException e) {
throw new IOException(e);
@@ -763,12 +731,31 @@
}
/**
+ * Stores the given entry into the map, making sure
+ * the alias, used as the key is unique.
+ * If the same alias already exists, it tries to append
+ * a suffix (1), (2), etc to it until it finds a unique
+ * value.
+ */
+ private void storeWithUniqueAlias(String alias, KeyEntry entry) {
+ String uniqAlias = alias;
+ int uniqNum = 1;
+
+ while (true) {
+ if (entries.putIfAbsent(uniqAlias, entry) == null) {
+ break;
+ }
+ uniqAlias = alias + " (" + (uniqNum++) + ")";
+ }
+ }
+
+
+ /**
* Generates a certificate chain from the collection of
* certificates and stores the result into a key entry.
*/
private void generateCertificateChain(String alias,
- Collection<? extends Certificate> certCollection,
- Collection<KeyEntry> entries)
+ Collection<? extends Certificate> certCollection)
{
try
{
@@ -782,10 +769,8 @@
certChain[i] = (X509Certificate) iter.next();
}
- KeyEntry entry = new KeyEntry(alias, null, certChain);
-
- // Add cert chain
- entries.add(entry);
+ storeWithUniqueAlias(alias,
+ new KeyEntry(alias, null, certChain));
}
catch (Throwable e)
{
@@ -800,8 +785,7 @@
*/
private void generateRSAKeyAndCertificateChain(String alias,
long hCryptProv, long hCryptKey, int keyLength,
- Collection<? extends Certificate> certCollection,
- Collection<KeyEntry> entries)
+ Collection<? extends Certificate> certCollection)
{
try
{
@@ -815,11 +799,9 @@
certChain[i] = (X509Certificate) iter.next();
}
- KeyEntry entry = new KeyEntry(alias, new RSAPrivateKey(hCryptProv,
- hCryptKey, keyLength), certChain);
-
- // Add cert chain
- entries.add(entry);
+ storeWithUniqueAlias(alias, new KeyEntry(alias,
+ new RSAPrivateKey(hCryptProv, hCryptKey, keyLength),
+ certChain));
}
catch (Throwable e)
{
@@ -876,8 +858,8 @@
* @param name Name of keystore.
* @param entries Collection of key/certificate.
*/
- private native void loadKeysOrCertificateChains(String name,
- Collection<KeyEntry> entries) throws KeyStoreException;
+ private native void loadKeysOrCertificateChains(String name)
+ throws KeyStoreException;
/**
* Stores a DER-encoded certificate into the certificate store
diff --git a/jdk/src/windows/native/sun/security/mscapi/security.cpp b/jdk/src/windows/native/sun/security/mscapi/security.cpp
index 161c2ae..553dd42 100644
--- a/jdk/src/windows/native/sun/security/mscapi/security.cpp
+++ b/jdk/src/windows/native/sun/security/mscapi/security.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -266,7 +266,7 @@
* Signature: (Ljava/lang/String;Ljava/util/Collection;)V
*/
JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateChains
- (JNIEnv *env, jobject obj, jstring jCertStoreName, jobject jCollections)
+ (JNIEnv *env, jobject obj, jstring jCertStoreName)
{
/**
* Certificate in cert store has enhanced key usage extension
@@ -325,7 +325,7 @@
// Determine method ID to generate certificate chain
jmethodID mGenCertChain = env->GetMethodID(clazzOfThis,
"generateCertificateChain",
- "(Ljava/lang/String;Ljava/util/Collection;Ljava/util/Collection;)V");
+ "(Ljava/lang/String;Ljava/util/Collection;)V");
if (mGenCertChain == NULL) {
__leave;
}
@@ -333,7 +333,7 @@
// Determine method ID to generate RSA certificate chain
jmethodID mGenRSAKeyAndCertChain = env->GetMethodID(clazzOfThis,
"generateRSAKeyAndCertificateChain",
- "(Ljava/lang/String;JJILjava/util/Collection;Ljava/util/Collection;)V");
+ "(Ljava/lang/String;JJILjava/util/Collection;)V");
if (mGenRSAKeyAndCertChain == NULL) {
__leave;
}
@@ -360,38 +360,37 @@
} else {
// Private key is available
- BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
+ BOOL bGetUserKey = ::CryptGetUserKey(hCryptProv, dwKeySpec, &hUserKey);
- // Skip certificate if cannot find private key
- if (bGetUserKey == FALSE)
- {
- if (bCallerFreeProv)
- ::CryptReleaseContext(hCryptProv, NULL);
+ // Skip certificate if cannot find private key
+ if (bGetUserKey == FALSE)
+ {
+ if (bCallerFreeProv)
+ ::CryptReleaseContext(hCryptProv, NULL);
- continue;
+ continue;
+ }
+
+ // Set cipher mode to ECB
+ DWORD dwCipherMode = CRYPT_MODE_ECB;
+ ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
+
+
+ // If the private key is present in smart card, we may not be able to
+ // determine the key length by using the private key handle. However,
+ // since public/private key pairs must have the same length, we could
+ // determine the key length of the private key by using the public key
+ // in the certificate.
+ dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
+
}
-
- // Set cipher mode to ECB
- DWORD dwCipherMode = CRYPT_MODE_ECB;
- ::CryptSetKeyParam(hUserKey, KP_MODE, (BYTE*)&dwCipherMode, NULL);
-
-
- // If the private key is present in smart card, we may not be able to
- // determine the key length by using the private key handle. However,
- // since public/private key pairs must have the same length, we could
- // determine the key length of the private key by using the public key
- // in the certificate.
- dwPublicKeyLength = ::CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- &(pCertContext->pCertInfo->SubjectPublicKeyInfo));
-
-}
PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
// Build certificate chain by using system certificate store.
// Add cert chain into collection for any key usage.
//
- if (GetCertificateChain(OID_EKU_ANY, pCertContext,
- &pCertChainContext))
+ if (GetCertificateChain(OID_EKU_ANY, pCertContext, &pCertChainContext))
{
for (unsigned int i=0; i < pCertChainContext->cChain; i++)
@@ -450,26 +449,26 @@
// collection
env->CallVoidMethod(obj, mGenCertChain,
env->NewStringUTF(pszNameString),
- jArrayList, jCollections);
+ jArrayList);
}
else
{
- // Determine key type: RSA or DSA
- DWORD dwData = CALG_RSA_KEYX;
- DWORD dwSize = sizeof(DWORD);
- ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData,
- &dwSize, NULL);
+ // Determine key type: RSA or DSA
+ DWORD dwData = CALG_RSA_KEYX;
+ DWORD dwSize = sizeof(DWORD);
+ ::CryptGetKeyParam(hUserKey, KP_ALGID, (BYTE*)&dwData,
+ &dwSize, NULL);
- if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
- {
- // Generate RSA certificate chain and store into cert
- // chain collection
- env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
- env->NewStringUTF(pszNameString),
- (jlong) hCryptProv, (jlong) hUserKey,
- dwPublicKeyLength, jArrayList, jCollections);
+ if ((dwData & ALG_TYPE_RSA) == ALG_TYPE_RSA)
+ {
+ // Generate RSA certificate chain and store into cert
+ // chain collection
+ env->CallVoidMethod(obj, mGenRSAKeyAndCertChain,
+ env->NewStringUTF(pszNameString),
+ (jlong) hCryptProv, (jlong) hUserKey,
+ dwPublicKeyLength, jArrayList);
+ }
}
-}
}
// Free cert chain
diff --git a/jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java b/jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java
similarity index 77%
rename from jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java
rename to jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java
index 190390d..3c42ec7 100644
--- a/jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java
+++ b/jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -20,6 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.Robot;
@@ -29,22 +30,23 @@
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
+
import sun.awt.OSInfo;
/**
* @test
- * @bug 8033000
+ * @bug 8033000 8147994
* @author Alexander Scherbatiy
* @summary No Horizontal Mouse Wheel Support In BasicScrollPaneUI
- * @run main bug8033000
+ * @run main HorizontalMouseWheelOnShiftPressed
*/
-public class bug8033000 {
+public class HorizontalMouseWheelOnShiftPressed {
private static JScrollPane scrollPane;
private static JTextArea textArea;
private static Point point;
private static final int delta;
+ private static JFrame frame;
static {
delta = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -30 : 30;
@@ -55,9 +57,17 @@
Robot robot = new Robot();
robot.setAutoDelay(50);
- SwingUtilities.invokeAndWait(bug8033000::createAndShowGUI);
+ SwingUtilities.invokeAndWait(
+ HorizontalMouseWheelOnShiftPressed::createAndShowGUI);
robot.waitForIdle();
+ try {
+ test(robot);
+ } finally {
+ frame.dispose();
+ }
+ }
+ private static void test(Robot robot) throws Exception {
SwingUtilities.invokeAndWait(() -> {
Point locationOnScreen = scrollPane.getLocationOnScreen();
point = new Point(
@@ -73,7 +83,7 @@
robot.waitForIdle();
robot.mouseWheel(delta);
robot.waitForIdle();
- checkScrollPane(true);
+ checkScrollPane(true, false);
// vertical scroll bar is enabled + shift
initScrollPane(true, false);
@@ -82,14 +92,14 @@
robot.mouseWheel(delta);
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.waitForIdle();
- checkScrollPane(true);
+ checkScrollPane(false, false);
// horizontal scroll bar is enabled
initScrollPane(false, true);
robot.waitForIdle();
robot.mouseWheel(delta);
robot.waitForIdle();
- checkScrollPane(false);
+ checkScrollPane(false, true);
// horizontal scroll bar is enabled + shift
initScrollPane(false, true);
@@ -98,14 +108,14 @@
robot.mouseWheel(delta);
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.waitForIdle();
- checkScrollPane(false);
+ checkScrollPane(false, true);
// both scroll bars are enabled
initScrollPane(true, true);
robot.waitForIdle();
robot.mouseWheel(delta);
robot.waitForIdle();
- checkScrollPane(true);
+ checkScrollPane(true, false);
// both scroll bars are enabled + shift
initScrollPane(true, true);
@@ -114,7 +124,7 @@
robot.mouseWheel(delta);
robot.keyRelease(KeyEvent.VK_SHIFT);
robot.waitForIdle();
- checkScrollPane(false);
+ checkScrollPane(false, true);
}
static void initScrollPane(boolean vVisible, boolean hVisible) throws Exception {
@@ -129,17 +139,25 @@
});
}
- static void checkScrollPane(boolean verticalScrolled) throws Exception {
+ static void checkScrollPane(boolean verticalScrolled,
+ boolean horizontalScrolled) throws Exception {
SwingUtilities.invokeAndWait(() -> {
if (verticalScrolled) {
- if (scrollPane.getVerticalScrollBar().getValue() == 0
- || scrollPane.getHorizontalScrollBar().getValue() != 0) {
+ if (scrollPane.getVerticalScrollBar().getValue() == 0) {
throw new RuntimeException("Wrong vertical scrolling!");
}
+ } else{
+ if (scrollPane.getVerticalScrollBar().getValue() != 0) {
+ throw new RuntimeException("Wrong vertical scrolling!");
+ }
+ }
+ if (horizontalScrolled) {
+ if (scrollPane.getHorizontalScrollBar().getValue() == 0) {
+ throw new RuntimeException("Wrong horizontal scrolling!");
+ }
} else {
- if (scrollPane.getVerticalScrollBar().getValue() != 0
- || scrollPane.getHorizontalScrollBar().getValue() == 0) {
+ if (scrollPane.getHorizontalScrollBar().getValue() != 0) {
throw new RuntimeException("Wrong horizontal scrolling!");
}
}
@@ -147,9 +165,10 @@
}
static void createAndShowGUI() {
- JFrame frame = new JFrame();
+ frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
+ frame.setLocationRelativeTo(null);
textArea = new JTextArea("Hello World!");
scrollPane = new JScrollPane(textArea);
JPanel panel = new JPanel(new BorderLayout());
diff --git a/jdk/test/sun/security/mscapi/CastError.java b/jdk/test/sun/security/mscapi/CastError.java
new file mode 100644
index 0000000..439ba24
--- /dev/null
+++ b/jdk/test/sun/security/mscapi/CastError.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+
+/**
+ * @test
+ * @bug 8143913
+ * @requires os.family == "windows"
+ * @summary MSCAPI keystore should accept Certificate[] in setEntry()
+ */
+
+public class CastError {
+ public static void main(String[] args) throws Exception {
+ KeyStore ks = KeyStore.getInstance("JKS");
+ FileInputStream fis = new FileInputStream(
+ new File(System.getProperty("test.src"),
+ "../tools/jarsigner/JarSigning.keystore"));
+ ks.load(fis, "bbbbbb".toCharArray());
+
+ PrivateKey pk = (PrivateKey) ks.getKey("c", "bbbbbb".toCharArray());
+ Certificate cert = ks.getCertificate("c");
+
+ ks = KeyStore.getInstance("Windows-MY");
+ ks.load(null, null);
+
+ ks.setKeyEntry("8143913", pk, null, new Certificate[]{cert});
+ ks.deleteEntry("8143913");
+ }
+}
diff --git a/jdk/test/sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh b/jdk/test/sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh
new file mode 100644
index 0000000..b6e264c
--- /dev/null
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh
@@ -0,0 +1,100 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2016, 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.
+#
+# 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.
+#
+
+
+# @test
+# @ignore Uses certutil.exe that isn't guaranteed to be installed
+# @bug 6483657
+# @requires os.family == "windows"
+# @run shell NonUniqueAliases.sh
+# @summary Test "keytool -list" displays correcly same named certificates
+
+# set a few environment variables so that the shell-script can run stand-alone
+# in the source directory
+if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC="."
+fi
+
+if [ "${TESTCLASSES}" = "" ] ; then
+ TESTCLASSES="."
+fi
+
+if [ "${TESTJAVA}" = "" ] ; then
+ echo "TESTJAVA not set. Test cannot execute."
+ echo "FAILED!!!"
+ exit 1
+fi
+
+OS=`uname -s`
+case "$OS" in
+ Windows* | CYGWIN* )
+
+ # 'uname -m' does not give us enough information -
+ # should rely on $PROCESSOR_IDENTIFIER (as is done in Defs-windows.gmk),
+ # but JTREG does not pass this env variable when executing a shell script.
+ #
+ # execute test program - rely on it to exit if platform unsupported
+
+ echo "removing the alias NonUniqueName if it already exists"
+ certutil -user -delstore MY NonUniqueName
+
+ echo "Importing 1st certificate into MY keystore using certutil tool"
+ certutil -user -addstore MY ${TESTSRC}/nonUniq1.pem
+
+ echo "Importing 2nd certificate into MY keystore using certutil tool"
+ certutil -user -addstore MY ${TESTSRC}/nonUniq2.pem
+
+ echo "Listing certificates with keytool"
+ ${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My
+
+ echo "Counting expected entries"
+ count0=`${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My | grep 'NonUniqueName,' | wc -l`
+
+ if [ ! $count0 = 1 ]; then
+ echo "error: unexpected number of entries ($count0) in the Windows-MY store"
+ certutil -user -delstore MY NonUniqueName
+ exit 115
+ fi
+
+ echo "Counting expected entries"
+ count1=`${TESTJAVA}/bin/keytool ${TESTTOOLVMOPTS} -list -storetype Windows-My | grep 'NonUniqueName (1),' | wc -l`
+
+ if [ ! $count1 = 1 ]; then
+ echo "error: unexpected number of entries ($count1) in the Windows-MY store"
+ certutil -user -delstore MY NonUniqueName
+ exit 116
+ fi
+
+ echo "Cleaning up"
+ certutil -user -delstore MY NonUniqueName
+
+ exit 0
+ ;;
+
+ * )
+ echo "This test is not intended for '$OS' - passing test"
+ exit 0
+ ;;
+esac
diff --git a/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq1.pem b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq1.pem
new file mode 100644
index 0000000..73ed657
--- /dev/null
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq1.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAWegAwIBAgIJANy5XBGM4BSuMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
+BAMMDU5vblVuaXF1ZU5hbWUwHhcNMTYwNDAxMTcyMjQ0WhcNMTYwNzEwMTcyMjQ0
+WjAYMRYwFAYDVQQDDA1Ob25VbmlxdWVOYW1lMIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDI0hlED2YFVgTaVLKWvsqB9JN9EJpUWECkB97fJwb1x99dHf0TO2p6
+HPPvkvjBiAMEZYbojCz+WpNhG1Ilu/UgKwPyHh1pL6kRcEhlS2G3i7p9SDLHWlk0
+xfdhSZERgd6ROpDnY7eaj1CTdVCSyEATs4FFyNtN9Q39jyeCU++ksQIDAQABo1Aw
+TjAdBgNVHQ4EFgQUpW/Wtw/OOTdnFTL7afIkNjuCVr8wHwYDVR0jBBgwFoAUpW/W
+tw/OOTdnFTL7afIkNjuCVr8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB
+gQAWC+xX1cGNNp3F6dAb5tKKJGgQwsjfrjDP0/AirWc7Im1kTCpVPT61Ayt0bHgH
+n3hGivKmO7ChQAI3QsDMDKWE98tF6afPltBOoWh2a9tPd65JSD1HfkG+Wc1IZ5gL
+8rKp1tdKTEG2A+qXRN/e6DdtMsgDrK1iPfX+rer53TC+Yg==
+-----END CERTIFICATE-----
diff --git a/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq2.pem b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq2.pem
new file mode 100644
index 0000000..ac4d1a7
--- /dev/null
+++ b/jdk/test/sun/security/mscapi/nonUniqueAliases/nonUniq2.pem
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAWegAwIBAgIJAPyQune5t/SZMA0GCSqGSIb3DQEBCwUAMBgxFjAUBgNV
+BAMMDU5vblVuaXF1ZU5hbWUwHhcNMTYwNDAxMTcyMzI0WhcNMTYwNzEwMTcyMzI0
+WjAYMRYwFAYDVQQDDA1Ob25VbmlxdWVOYW1lMIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDeSu/pPzL9hA1kjA2Rs13LpN2lNrisbYg/Vj/swGDMJnVCzS3IFQQy
+71515mru+ngrHnfPSo4FKUhZPJzET2D7CruR65SzhQ96SHGoR8rhmL41KRBKELuR
+3MoarLFziFzeIil4NZg55xp6TE/WCXRfi7HNdIgoKQGLoIhehVGN8QIDAQABo1Aw
+TjAdBgNVHQ4EFgQUxFw79pLSf5Ul3zLqi/Mc6pSxEtswHwYDVR0jBBgwFoAUxFw7
+9pLSf5Ul3zLqi/Mc6pSxEtswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOB
+gQDPilBcFpFrjwqb+lJxDxXK992KjNUS8yFLo1DQ/LBTaoHvy/U5zxzRq+nvSaaf
+h+RIKqTwIbuBhSjrXVdJ/gzob/UlPC7IDo7FVbZwOHqTkqEum8jQEpX67hEevw9s
++reyqGhLsCtQK6uBTd2Nt9uOVCHrWNzWgQewkVYAUM5QpA==
+-----END CERTIFICATE-----
diff --git a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
index 65b1cca..113bb26 100644
--- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
+++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java
@@ -24,10 +24,9 @@
import com.sun.net.httpserver.*;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
-import java.io.File;
import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
@@ -38,9 +37,15 @@
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import sun.misc.IOUtils;
import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
+import sun.security.pkcs.PKCS9Attribute;
import sun.security.pkcs.SignerInfo;
+import sun.security.timestamp.TimestampToken;
import sun.security.util.DerOutputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
@@ -51,6 +56,8 @@
static final String TSKS = "tsks";
static final String JAR = "old.jar";
+ static final String defaultPolicyId = "2.3.4.5";
+
static class Handler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
int len = 0;
@@ -94,6 +101,11 @@
* 6: extension is missing
* 7: extension is non-critical
* 8: extension does not have timestamping
+ * 9: no cert in response
+ * 10: normal
+ * 11: always return default policy id
+ * 12: normal
+ * otherwise: normal
* @returns the signed
*/
byte[] sign(byte[] input, int path) throws Exception {
@@ -106,6 +118,7 @@
messageImprint.data.getDerValue());
System.err.println("AlgorithmId: " + aid);
+ ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId);
BigInteger nonce = null;
while (value.data.available() > 0) {
DerValue v = value.data.getDerValue();
@@ -114,6 +127,9 @@
System.err.println("nonce: " + nonce);
} else if (v.tag == DerValue.tag_Boolean) {
System.err.println("certReq: " + v.getBoolean());
+ } else if (v.tag == DerValue.tag_ObjectId) {
+ policyId = v.getOID();
+ System.err.println("PolicyID: " + policyId);
}
}
@@ -127,6 +143,10 @@
if (path == 7) alias = "tsbad2";
if (path == 8) alias = "tsbad3";
+ if (path == 11) {
+ policyId = new ObjectIdentifier(defaultPolicyId);
+ }
+
DerOutputStream statusInfo = new DerOutputStream();
statusInfo.putInteger(0);
@@ -150,7 +170,7 @@
DerOutputStream tst = new DerOutputStream();
tst.putInteger(1);
- tst.putOID(new ObjectIdentifier("1.2.3.4")); // policy
+ tst.putOID(policyId);
if (path != 3 && path != 4) {
tst.putDerValue(messageImprint);
@@ -260,15 +280,43 @@
jarsigner(cmd, 7, false); // tsbad2
jarsigner(cmd, 8, false); // tsbad3
jarsigner(cmd, 9, false); // no cert in timestamp
- jarsigner(cmd + " -tsapolicyid 1.2.3.4", 0, true);
- jarsigner(cmd + " -tsapolicyid 1.2.3.5", 0, false);
+ jarsigner(cmd + " -tsapolicyid 1.2.3.4", 10, true);
+ checkTimestamp("new_10.jar", "1.2.3.4", "SHA-256");
+ jarsigner(cmd + " -tsapolicyid 1.2.3.5", 11, false);
+ jarsigner(cmd + " -tsadigestalg SHA", 12, true);
+ checkTimestamp("new_12.jar", defaultPolicyId, "SHA-1");
} else { // Run as a standalone server
System.err.println("Press Enter to quit server");
System.in.read();
}
} finally {
server.stop(0);
- new File("x.jar").delete();
+ }
+ }
+
+ static void checkTimestamp(String file, String policyId, String digestAlg)
+ throws Exception {
+ try (JarFile jf = new JarFile(file)) {
+ JarEntry je = jf.getJarEntry("META-INF/OLD.RSA");
+ try (InputStream is = jf.getInputStream(je)) {
+ byte[] content = IOUtils.readFully(is, -1, true);
+ PKCS7 p7 = new PKCS7(content);
+ SignerInfo[] si = p7.getSignerInfos();
+ if (si == null || si.length == 0) {
+ throw new Exception("Not signed");
+ }
+ PKCS9Attribute p9 = si[0].getUnauthenticatedAttributes()
+ .getAttribute(PKCS9Attribute.SIGNATURE_TIMESTAMP_TOKEN_OID);
+ PKCS7 tsToken = new PKCS7((byte[]) p9.getValue());
+ TimestampToken tt =
+ new TimestampToken(tsToken.getContentInfo().getData());
+ if (!tt.getHashAlgorithm().toString().equals(digestAlg)) {
+ throw new Exception("Digest alg different");
+ }
+ if (!tt.getPolicyID().equals(policyId)) {
+ throw new Exception("policyId different");
+ }
+ }
}
}
diff --git a/jdk/test/sun/security/tools/jarsigner/ts.sh b/jdk/test/sun/security/tools/jarsigner/ts.sh
index 928b22e..6cee680 100644
--- a/jdk/test/sun/security/tools/jarsigner/ts.sh
+++ b/jdk/test/sun/security/tools/jarsigner/ts.sh
@@ -86,6 +86,6 @@
$KT -alias ca -gencert -ext eku:critical=cs | \
$KT -alias tsbad3 -importcert
-$JAVAC -d . ${TESTSRC}/TimestampCheck.java
+$JAVAC -XDignore.symbol.file -d . ${TESTSRC}/TimestampCheck.java
$JAVA ${TESTVMOPTS} TimestampCheck
diff --git a/nashorn/.hgtags b/nashorn/.hgtags
index b0149ea..7a86bdd 100644
--- a/nashorn/.hgtags
+++ b/nashorn/.hgtags
@@ -519,12 +519,20 @@
81e48503b62fd8814135f642905fe38056aaf2a9 jdk8u72-b13
e48d06eeff82bea512cea44fa14d59b88067ef83 jdk8u72-b14
769b21d1b85cfb57c11c89bbc8f185f9e520df66 jdk8u72-b15
+c90794ad4d12eeeae5d9bbfce65fa0043a313548 jdk8u72-b31
e9b46178f2e35d9ed2cd5b2f7279cf5e4e954222 jdk8u73-b00
eeb5306edb7a0140117fe346782cce19c4c562a7 jdk8u73-b01
955689d050b9f3f61b90ca063fe13704a82f5394 jdk8u73-b02
2a36c3c61f905c5b389ae1d62f446e57f96be3a2 jdk8u74-b00
ae6c74c1197afcbd83d393aa6f96221d759022a2 jdk8u74-b01
3107cf87696f0516d6f5fa7cdc416069e2800d02 jdk8u74-b02
+4608bbcc94f73059680acd0f486744ff26485ee9 jdk8u74-b31
+7d0f4c8fc2754e25c1c148ff47bb79aa880c2874 jdk8u74-b32
+7bce03d47545e6a5341a2722168cd6bf697c4132 jdk8u77-b00
+678b645aa10aaf27895c87872c399c15daa026a1 jdk8u77-b01
+09abd795d1d143933224bcb3f12f5d4686b65373 jdk8u77-b02
+b6ee21a35619ce4d3b46a9b825438a3bc9bb63cd jdk8u77-b03
+961f73438a3cdacc6197663b2495b73c08805f24 jdk8u77-b31
c90794ad4d12eeeae5d9bbfce65fa0043a313548 jdk8u72-b31
c7eddafb2ee2cc9d62f20c4d821ccac03bd4617d jdk8u75-b00
69fa156c1ebe6a8d6587147967e8e27f6de37d99 jdk8u75-b01
@@ -538,6 +546,13 @@
fd2b29bd7cb64a9a04d75a659bc683751b3a4f35 jdk8u75-b09
bab68ab3df71269887bb3572291a19f7856e49dc jdk8u75-b10
e35e96663a905f0258f6572ab6a07fbea71b9d45 jdk8u75-b12
+7bce03d47545e6a5341a2722168cd6bf697c4132 jdk8u77-b00
+678b645aa10aaf27895c87872c399c15daa026a1 jdk8u77-b01
+09abd795d1d143933224bcb3f12f5d4686b65373 jdk8u77-b02
+b6ee21a35619ce4d3b46a9b825438a3bc9bb63cd jdk8u77-b03
+a2c005a7b33abed886cfb4309a846dd80c87bd4e jdk8u91-b00
+22925b345dffe4ba96fe2f429c4185cda1b30239 jdk8u91-b13
+6296644a2c9c30db0062117fc776341e937ca1f9 jdk8u91-b14
9ff5c21813330147bf08389b3992534780c93247 jdk8u76-b00
b7bbed8b05dd50c27050c7e10e20d25329dcd32b jdk8u76-b01
4c1aa7b8c43c6fd38f9c13a6df2264378dd6a873 jdk8u76-b02
@@ -550,3 +565,7 @@
fe15575fd53e7ee8e8bf44728bab9cc0a9e6b107 jdk8u76-b09
2816d2045f017d1b0dfd20319bbb59004d698396 jdk8u76-b10
0608b63feb608f36bde691498d2ad22c7c24ad0f jdk8u76-b11
+da1aa86606ef1b46655ae28d34e0d02604fb4cde jdk8u76-b12
+256922f1e9e7648eb5af5a9da82ff8032b3855bc jdk8u92-b00
+e2294411edbda51165bc1a10261c246cb4d3c5c5 jdk8u92-b13
+d2af8d0297223ff16d59ee64b7058cafef8f3bb8 jdk8u92-b14