Merge
diff --git a/.hgtags b/.hgtags
index 62c1a03..b20d370 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1,3 +1,127 @@
+9abe75655318fdc111277f4d8d6ca28fe804cc76 jdk8u71-b09
+251daf4b0264f746daf4cd4f06a98c66f869b345 jdk8u71-b10
+3a39a03b0af0a2c35491ab1b5fe8103d08224e45 jdk8u71-b08
+c795203ce82defbf1034d32b0ccf741a7b665800 jdk8u71-b07
+6e5174a14363fdd77f13fc0b61fed2e1aa55042f jdk8u60-b31
+a91357360fd22fc7952c3490a7244eddc85e3cdb jdk8u60-b32
+dc0dfb35073c850437b95a66c98c023e2d806feb jdk8u66-b31
+51d33adee38e5db59878c811ce8314f801d79a38 jdk8u66-b32
+ebcdd5266a709b0d7370a1816390dae1a0e376bf jdk8u65-b16
+9869d9ef1d3a7b842a12fd7cf1da4b0a6d6fa278 jdk8u66-b16
+b1579f9a647fde24d9d6c60144706e0798b91780 jdk8u65-b15
+179d8c7c04d13217e7889c7ab6c5d5ea747e9c0e jdk8u65-b14
+45a1d473e06f5159e8f92b5fbbe353ecda2c48c0 jdk8u65-b13
+6ed276357e8da3b16cd7b814103f59d6b9cbab3a jdk8u65-b12
+119e550b70f060dbdd70458d3cecea27b9b149b0 jdk8u65-b11
+545f4caa853a1501b700d95d1ce07c07eae333c2 jdk8u65-b10
+a1cb608ab6785f685da69a974c83499394bd0124 jdk8u65-b09
+028cd257bbdec9312c374ca5ac13457ae88a04b7 jdk8u60-b26
+54ebedfc1162ec239b6f3d4bba0f399f30b04de6 jdk8u65-b08
+63c1704e50892d972586062717442323bd9b802f jdk8u60-b25
+0cc080d5fe65ac86993514e79be0c5815680e77b jdk8u45-b33
+895e6c8ff4a599b46bcd17c2a059541f8c827f2b jdk8u45-b34
+b59ca414f450b4cbf35498e986ce7b830fe45446 jdk8u45-b35
+1ce441d60057bf9845a433aec8ce8d94089f0371 jdk8u45-b36
+4da2290e22a41ad8efc6c51a62daea7fa7746ef1 jdk8u45-b37
+2f4d1dfe22b000f80e366554a406e09e8dd76110 jdk8u51-b31
+de742e2dfad5035049c15494e5389377416f759c jdk8u65-b03
+7d999291a4227be894f0f117452773e960650bba jdk8u65-b04
+43a13123c4a0366e0f6ade5a6bd0e4c75ba7de36 jdk8u45-b32
+2d380b0473db25d28f9ee291f204495bbe639fe2 jdk8u65-b00
+181454578aa185b047fb66b25959f346a85b3fd8 jdk8u31-b33
+745fbda5fc8a524dc46d94f5781b3692d2f6caa7 jdk8u51-b04
+de6c9ad9257c8417d49746481a65cf1961bcbef5 jdk8u51-b05
+729ddf2ce5508b47f5f6e2bea52f1f7465f87367 jdk8u51-b06
+c823f29bfde1a30b34a094c3229ccf3bdedb2378 jdk8u51-b07
+f6ffff2443fedaa9af40aba99fec356488a9336f jdk8u51-b08
+f33638386ce0caf2eb61d78a69a711337553862b jdk8u51-b09
+88f1359636075346fb2c300bc5d1cc2d17f7d49b jdk8u51-b10
+b47527e0d139cb87949a02b91bf6bd75ba35eea5 jdk8u51-b11
+1b1ed849d692b4d36ae753acd22d353a46edc084 jdk8u51-b12
+3ed1ef5177cc7f7dc045abd5d2444ba1661b2aee jdk8u51-b13
+2ae16d4e8ccd7664c866fae7f6c8f27d3e1765a1 jdk8u51-b14
+e87f038e4f523f6c7a0d4ad1f4761f470e524d2f jdk8u51-b15
+af0b455357600a703ebc78982c3c3227fe7abec9 jdk8u51-b16
+b5075673d083d9fe14139e94d18e1e45ed243c03 jdk8u60-b23
+15c23f3d4f3dbabfdb5c99141acf182754d76b60 jdk8u60-b20
+98d1fd261305fe80d85851f55c5f9ea21db6e5aa jdk8u60-b19
+ba1397fcc2ca345cfd9c20944bf8140dbf9810db jdk8u40-b31
+c90e78d4811c62f74189e00f39cb5dea16a8aa99 jdk8u25-b33
+d6cf1fca53751af35e3df00028ce64ced10912b1 jdk8u31-b31
+c98f2e9598ec9ea7de5ede11e19de9acbc1cd0b2 jdk8u31-b32
+3a60ce949dcdb00a10dbb2d5f068845e08a95f93 jdk8u45-b01
+a82451c6b7d7c54991e67d8a9ed92b8ab4e0fb94 jdk8u40-b25
+395f98e0054748f3752180c4e72041989cb77dae jdk8u40-b24
+62af9eb0a1aeebc2a0d1a84871f7229d1e340352 jdk8u40-b23
+e8e01fadd9217cf0a6b9cab83d3958e5a923e9c8 jdk8u25-b31
+9a56e4dd93ec7bb7a7bed2e171fe012327377298 jdk8u25-b32
+b8ea0ec8e3f75630782a55e356f11d86edbb1c8a jdk8u20-b32
+286baa471341d61135a91de7f5f99225238cd83f jdk8u20-b31
+9ab042324c5d665cdf3438d0d7d880264b2ab468 jdk8u31-b01
+4a15a5836895e5db8418064830f45a2ca9a6c32d jdk8u31-b02
+95a960bef4aa09683b85630c99cbfdcb09be8c80 jdk8u31-b03
+3a39ffc73a70fbbebf11604618c889282cb5e266 jdk8u45-b00
+aa664b83dd7a732bc4101ccfa409c88aaf2c6396 jdk8u31-b04
+9b8a2433fb1b2ec0403278b25bb3e7996e8f2492 jdk8u31-b05
+0de449900099c610e51496317f9e4fede032f58d jdk8u31-b06
+6da1a3d24f9d0a4f486b6261684441756877ce03 jdk8u31-b07
+6c1232e0a1d8ce8fec8b0ad48fb1f06847566d65 jdk8u31-b08
+7e10b3fa8ec67cb43c8db65175f20f3e43710a78 jdk8u31-b09
+e986a1848381ad067cfe951b9e595851f3329fd4 jdk8u31-b10
+788b8201911214a3db8f2cc2f6a7ea1cf3e0eaec jdk8u31-b11
+6cd235fec9f2033751347feb3d43204c18028c15 jdk8u31-b12
+b851e244dc9d68490d608bdf5568abdf83a43ef7 jdk8u31-b13
+087958469f8c564aa0d222a375aa776e79e844a1 jdk8u31-b14
+d32902522c486b30b522deee59185b3e82dcd6a3 jdk8u40-b21
+f8031ed80d3a1575d322f6cabaac450d3f287ddf jdk8u51-b00
+e80b2282a8b097a42ceaf82723adf3985b6610c3 jdk8u40-b20
+ee2460d6e2ee31cafb31c44e7dfdaf60f79b8cf8 jdk8u40-b19
+4ec8983cde118ffbc10ee1b87761a21dd7de7974 jdk8u60-b00
+3f619677e64b5bc0c0305b4f33706cd6df11c105 jdk8u45-b02
+07e23c2206a8513bd547de4d757b5589729a1d5f jdk8u45-b03
+2528216fd06302e783fba96855ce7b541d9a13b8 jdk8u45-b04
+74d0570ae0f18ea4c4af251083f905262016be6f jdk8u45-b05
+47f16e9f82cddd25be7080b66cbd1c5a95f5d56a jdk8u45-b06
+bf76825ec23fbf496ce2d76869ddfc9cf254f5e3 jdk8u45-b07
+cb7537e17f40be56a1882730d0af587b78f7d774 jdk8u45-b08
+557ddbca52e09b8f25af90109c04d9d0cb1b18eb jdk8u45-b09
+3bad03a34f400b62ea644f6500f3b3800a286e9f jdk8u45-b10
+22664e4df905ac06a0ced6899a9ce27426a01231 jdk8u45-b11
+52738b0ca4558cf6f9dcabe92502e12b407a4a98 jdk8u51-b01
+4dd1911c59a51c58c0e14c9c4556d04f528e3a3e jdk8u51-b02
+54e85cf0018b30605093b50d31392f3faba7d754 jdk8u51-b03
+77a247120f0b1f47ee66b01aed2a774081423c76 jdk8u65-b01
+b3d08ee2c32792aa8f9767bdf2c2bbe3d4a075f3 jdk8u65-b02
+c2d5bc74f06ca8ca14b1773b0cef6119bca81237 jdk8u65-b05
+cba2b484316853d6578e5c3b0e927318f8c32030 jdk8u71-b00
+8aa387a2cfed71ce0e85712a0c4916d244703c1e jdk8u65-b06
+e873134b53001129a46d8b42f5ca42f4c8c74e0e jdk8u65-b07
+397e81dfa7f3e02c7bd5688a25360ba73d8ed015 jdk8u66-b07
+5e7c74b7f74e769100285e32b2160ee3356a0f95 jdk8u66-b08
+3bcc6f7741599958f18eac6438fb611c0284687f jdk8u66-b09
+007fd88a5d47576b5ecedce3cb52c78e26830931 jdk8u66-b10
+a8e505e913f2f795bcc151061524529d3bf7786f jdk8u66-b11
+abcf93186482b993462ca6e9a3479993829ad0b3 jdk8u66-b12
+ac97b2995cb9a022db1385afb0f6c836b520a998 jdk8u66-b13
+d1ae7d0e117aa94429717a5e871c4335fbcc9f2a jdk8u66-b14
+9449e97835c377cf00c81136c76892a0bf50a3c3 jdk8u66-b15
+28bca1e9c3d6a827ab939f0509fff690cd9d87e5 jdk8u71-b01
+fa84571a88c1c8c4e0ce5b599d7106df66553d1c jdk8u71-b02
+706eef0274977ec103ece3443f8c0eaa9d01c35a jdk8u71-b03
+27b481762b7de4559fd0d22428084b5f1d961030 jdk8u75-b00
+d24032ba0010c039e0606ab6893f0aa19d3fde1f jdk8u71-b04
+ace3e66932112ea698c8777d97f708bfbcf32701 jdk8u71-b05
+ba183987098a65bcda427630deb8b27bc23f6519 jdk8u71-b06
+973c11838cc710b5040ab8f25ad2c6ce352dbe18 jdk8u65-b17
+93da0415ad0e6f90d343d9bba466c029d11fea8c jdk8u66-b17
+70b13325acdb87193fe84c1f15c2b70114d78756 jdk8u66-b18
+ee1523567c8e8ba2451b55d6b602d29ac5e81a2d jdk8u60-b24
+4cf1883bd7e4549c6d00f0cd05dce0c8abf9cbc3 jdk8u66-b01
+99e27251f1eb4031844d39f39c6ffdeab70e28ef jdk8u66-b02
+16609726bde12e07e58b02dfcf420b07cfd82dcc jdk8u72-b00
+09ef8323b8a03061cb917cbd73448b76d5ecadff jdk8u72-b01
+dad06297a2dcb171d1e9bb60aca25fa0d4c32fb7 jdk8u72-b02
+5cf387a32b6f532eab42a141210cfbe1cda1237f jdk8u72-b03
f15b6f880d3b2b128d8cd22bb691015982932b4c jdk8u40-b27
f56f8fd6d5fbffa25c040c5628d7209fcedd33f3 jdk8u45-b12
26ff3c0376bf2142ee611636556c22c1cc95d3f5 jdk8u45-b13
@@ -377,5 +501,7 @@
8328c93a759d4af6e71872f6fc03d3de8aee58e5 jdk8u60-b22
4dbc8f3ec683f6c9bb8c58a848b9f1829bcb8735 jdk8u66-b00
74f5b686f69880881068f8033cef8fe0db5313e6 jdk8u60-b27
-9abe75655318fdc111277f4d8d6ca28fe804cc76 jdk8u71-b09
-251daf4b0264f746daf4cd4f06a98c66f869b345 jdk8u71-b10
+a4b5390f7c1dccd5b320e1eeed0d15f29e6cf3d1 jdk8u72-b04
+31ff984a61a4546540fd0b250476d7612971d620 jdk8u72-b06
+25baf1f91330645e829c6e3e4ab03daa248ed318 jdk8u72-b07
+a0a179c689af775d60e435f4c19d613bd6bc42cd jdk8u72-b08
diff --git a/.hgtags-top-repo b/.hgtags-top-repo
index 4c69fcb..441c644 100644
--- a/.hgtags-top-repo
+++ b/.hgtags-top-repo
@@ -505,3 +505,12 @@
9b1bb13cc10cae3379849f341ccd0f21600de863 jdk8u71-b07
0ed543b92df44dfcfbfd074b9d6461a50e5f198f jdk8u71-b08
4231747bc5013bbead0cefa37ae4d2a390f2d446 jdk8u71-b09
+31a6e29ec33a9a3c6ac13ce66d3b96196700841c jdk8u72-b00
+d0afaafe3790d446d24ca35ddf61380457362b39 jdk8u72-b01
+2ffdd22b85317d3ba5ab28e34bcd288a5f18d998 jdk8u72-b02
+4270b7d818b26a67f9704b1575208876ab07f45d jdk8u72-b03
+19bf2975a37001daa2d45c171f65ae4e12d639df jdk8u72-b04
+674a69ec28a9e62b1adc90b138a4957bbc82946c jdk8u72-b05
+8c0ad72a45012464c18b4a74fdd711fe82e8842d jdk8u72-b06
+98f42c9df8c121347367164776eff3ebd50cb91e jdk8u72-b07
+55c885702381d47704589a37f05c0f7045be4e36 jdk8u72-b08
diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4
index fa2dfc9..ace6f7d 100644
--- a/common/autoconf/boot-jdk.m4
+++ b/common/autoconf/boot-jdk.m4
@@ -289,6 +289,16 @@
BOOT_JDK_SOURCETARGET="-source 7 -target 7"
AC_SUBST(BOOT_JDK_SOURCETARGET)
AC_SUBST(JAVAC_FLAGS)
+
+ # Check if the boot jdk is 32 or 64 bit
+ if "$JAVA" -d64 -version > /dev/null 2>&1; then
+ BOOT_JDK_BITS="64"
+ else
+ BOOT_JDK_BITS="32"
+ fi
+ AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits])
+ AC_MSG_RESULT([$BOOT_JDK_BITS])
+ AC_SUBST(BOOT_JDK_BITS)
])
AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS],
@@ -323,7 +333,7 @@
# Maximum amount of heap memory.
# Maximum stack size.
- if test "x$BUILD_NUM_BITS" = x32; then
+ if test "x$BOOT_JDK_BITS" = x32; then
JVM_MAX_HEAP=1100M
STACK_SIZE=768
else
diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh
index 0848db3..3dbbbd7 100644
--- a/common/autoconf/generated-configure.sh
+++ b/common/autoconf/generated-configure.sh
@@ -792,6 +792,7 @@
JAVA_FLAGS_SMALL
JAVA_FLAGS_BIG
JAVA_FLAGS
+BOOT_JDK_BITS
JAVAC_FLAGS
BOOT_JDK_SOURCETARGET
BOOT_JDK
@@ -3879,7 +3880,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1444076935
+DATE_WHEN_GENERATED=1445418840
###############################################################################
#
@@ -16071,6 +16072,18 @@
+ # Check if the boot jdk is 32 or 64 bit
+ if "$JAVA" -d64 -version > /dev/null 2>&1; then
+ BOOT_JDK_BITS="64"
+ else
+ BOOT_JDK_BITS="32"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Boot JDK is 32 or 64 bits" >&5
+$as_echo_n "checking if Boot JDK is 32 or 64 bits... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BOOT_JDK_BITS" >&5
+$as_echo "$BOOT_JDK_BITS" >&6; }
+
+
##############################################################################
#
@@ -16150,7 +16163,7 @@
# Maximum amount of heap memory.
# Maximum stack size.
- if test "x$BUILD_NUM_BITS" = x32; then
+ if test "x$BOOT_JDK_BITS" = x32; then
JVM_MAX_HEAP=1100M
STACK_SIZE=768
else
diff --git a/corba/.hgtags b/corba/.hgtags
index fdd69e9..155f6be 100644
--- a/corba/.hgtags
+++ b/corba/.hgtags
@@ -507,3 +507,12 @@
cdc7f7d08434d1219016a0098d27c0e528a0f3dd jdk8u71-b07
68e0b5479460cbce7b91f3eec723a652bbd2f3b8 jdk8u71-b08
a6d5b4ad93ac5c0d53ee956ff6c121708eae1804 jdk8u71-b09
+81296d52090354da1eb9748d63a29d30bb1230f7 jdk8u72-b00
+f0c760a2a888db7c84ec7d7a11892b8de867b2ae jdk8u72-b01
+4483a58cf74e7c237208059f94eced2ac9e2ed89 jdk8u72-b02
+c7110d67f536f9ff356ab5d871cf8316962da096 jdk8u72-b03
+948d562cd00d4a94264c5f97e55e16ce763a6367 jdk8u72-b04
+c752f355ace8127ef54b1e02968fcab934e199bd jdk8u72-b05
+ad9ef5b972345cdb79ebaf688dd026f8c2ecfd8c jdk8u72-b06
+812a4a1c5cf055413e5035ddc5ea6bff35d6ef57 jdk8u72-b07
+163f56ecf17237f326b3175a825762bae5149ce5 jdk8u72-b08
diff --git a/hotspot/.hgtags b/hotspot/.hgtags
index f774b11..3fc3607 100644
--- a/hotspot/.hgtags
+++ b/hotspot/.hgtags
@@ -773,3 +773,12 @@
bf9d01d1dc6c58b52cb2d0fb07820c51b62c3827 jdk8u71-b07
19d7052b56715803f40e39aaff00d34ca71f5bc3 jdk8u71-b08
4fb1acaab7a3205277fa21b083694f1bbb9ae957 jdk8u71-b09
+b8f426369187c32551f0a3d571d933908988c81c jdk8u72-b00
+c0205eddb31766ece562483595ec28a7506971e9 jdk8u72-b01
+15ef554f2f2e0a8d7c330191432fcd2126d19dab jdk8u72-b02
+bb98a4ba1556d0505461de98aa3dddf75278c09b jdk8u72-b03
+6c8ceb05ccf78f2f8f72f0870e3f6f3bd4895bb1 jdk8u72-b04
+a2969911663ab29c71a61aa3403e53243ad89923 jdk8u72-b05
+acf0d80cb84f14d787c34360abf2bc38b186999a jdk8u72-b06
+a382a72730f480078af5454afe782de9b6c210d3 jdk8u72-b07
+f26ad2273cd42cde957084ee953a9dc1a2598b5d jdk8u72-b08
diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
index d79d3d0..49c9dba 100644
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp
@@ -592,7 +592,7 @@
result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
cores_per_cpu();
}
- return result;
+ return (result == 0 ? 1 : result);
}
static intx prefetch_data_size() {
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index bbe347e..4f7c38a 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -5922,9 +5922,11 @@
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant");
} else {
+ // must capture correct index before unlocking
+ int index = _cur_index;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant");
- status = pthread_cond_signal (&_cond[_cur_index]);
+ status = pthread_cond_signal (&_cond[index]);
assert (status == 0, "invariant");
}
} else {
diff --git a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp
index fe9c6f9..0b99263 100644
--- a/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp
+++ b/hotspot/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -53,6 +53,10 @@
return cpuinfo_field_contains("cpu", "Niagara");
}
+static bool detect_M_family() {
+ return cpuinfo_field_contains("cpu", "SPARC-M");
+}
+
static bool detect_blkinit() {
return cpuinfo_field_contains("cpucaps", "blkinit");
}
@@ -66,6 +70,11 @@
features = niagara1_m | T_family_m;
}
+ if (detect_M_family()) {
+ NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Detected Linux on M family");)
+ features = sun4v_m | generic_v9_m | M_family_m | T_family_m;
+ }
+
if (detect_blkinit()) {
features |= blk_init_instructions_m;
}
diff --git a/hotspot/src/share/vm/classfile/stackMapTable.cpp b/hotspot/src/share/vm/classfile/stackMapTable.cpp
index f74adbe..1c92b61 100644
--- a/hotspot/src/share/vm/classfile/stackMapTable.cpp
+++ b/hotspot/src/share/vm/classfile/stackMapTable.cpp
@@ -186,7 +186,6 @@
u2 offset = _stream->get_u2(THREAD);
if (offset >= _code_length ||
_code_data[offset] != ClassVerifier::NEW_OFFSET) {
- ResourceMark rm(THREAD);
_verifier->class_format_error(
"StackMapTable format error: bad offset for Uninitialized");
return VerificationType::bogus_type();
diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp
index eef8b4d..c9059d7 100644
--- a/hotspot/src/share/vm/code/codeCache.cpp
+++ b/hotspot/src/share/vm/code/codeCache.cpp
@@ -521,15 +521,17 @@
void CodeCache::gc_epilogue() {
assert_locked_or_safepoint(CodeCache_lock);
- FOR_ALL_ALIVE_BLOBS(cb) {
- if (cb->is_nmethod()) {
- nmethod *nm = (nmethod*)cb;
- assert(!nm->is_unloaded(), "Tautology");
- if (needs_cache_clean()) {
- nm->cleanup_inline_caches();
+ NOT_DEBUG(if (needs_cache_clean())) {
+ FOR_ALL_ALIVE_BLOBS(cb) {
+ if (cb->is_nmethod()) {
+ nmethod *nm = (nmethod*)cb;
+ assert(!nm->is_unloaded(), "Tautology");
+ DEBUG_ONLY(if (needs_cache_clean())) {
+ nm->cleanup_inline_caches();
+ }
+ DEBUG_ONLY(nm->verify());
+ DEBUG_ONLY(nm->verify_oop_relocations());
}
- DEBUG_ONLY(nm->verify());
- DEBUG_ONLY(nm->verify_oop_relocations());
}
}
set_needs_cache_clean(false);
@@ -734,27 +736,6 @@
return number_of_marked_CodeBlobs;
}
-void CodeCache::make_marked_nmethods_zombies() {
- assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
- FOR_ALL_ALIVE_NMETHODS(nm) {
- if (nm->is_marked_for_deoptimization()) {
-
- // If the nmethod has already been made non-entrant and it can be converted
- // then zombie it now. Otherwise make it non-entrant and it will eventually
- // be zombied when it is no longer seen on the stack. Note that the nmethod
- // might be "entrant" and not on the stack and so could be zombied immediately
- // but we can't tell because we don't track it on stack until it becomes
- // non-entrant.
-
- if (nm->is_not_entrant() && nm->can_not_entrant_be_converted()) {
- nm->make_zombie();
- } else {
- nm->make_not_entrant();
- }
- }
- }
-}
-
void CodeCache::make_marked_nmethods_not_entrant() {
assert_locked_or_safepoint(CodeCache_lock);
FOR_ALL_ALIVE_NMETHODS(nm) {
diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp
index 966304f..f098284 100644
--- a/hotspot/src/share/vm/code/codeCache.hpp
+++ b/hotspot/src/share/vm/code/codeCache.hpp
@@ -179,7 +179,6 @@
static void mark_all_nmethods_for_deoptimization();
static int mark_for_deoptimization(Method* dependee);
- static void make_marked_nmethods_zombies();
static void make_marked_nmethods_not_entrant();
// tells how many nmethods have dependencies
diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp
index 77e435e..478a6cf 100644
--- a/hotspot/src/share/vm/code/compiledIC.cpp
+++ b/hotspot/src/share/vm/code/compiledIC.cpp
@@ -155,6 +155,14 @@
return _ic_call->destination();
}
+// Clears the IC stub if the compiled IC is in transition state
+void CompiledIC::clear_ic_stub() {
+ if (is_in_transition_state()) {
+ ICStub* stub = ICStub_from_destination_address(stub_address());
+ stub->clear();
+ }
+}
+
//-----------------------------------------------------------------------------
// High-level access to an inline cache. Guaranteed to be MT-safe.
@@ -279,6 +287,7 @@
assert( is_c1_method ||
!is_monomorphic ||
is_optimized() ||
+ !caller->is_alive() ||
(cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check");
#endif // ASSERT
return is_monomorphic;
@@ -313,7 +322,7 @@
}
-void CompiledIC::set_to_clean() {
+void CompiledIC::set_to_clean(bool in_use) {
assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call");
if (TraceInlineCacheClearing || TraceICs) {
tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
@@ -329,17 +338,14 @@
// A zombie transition will always be safe, since the metadata has already been set to NULL, so
// we only need to patch the destination
- bool safe_transition = is_optimized() || SafepointSynchronize::is_at_safepoint();
+ bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
if (safe_transition) {
// Kill any leftover stub we might have too
- if (is_in_transition_state()) {
- ICStub* old_stub = ICStub_from_destination_address(stub_address());
- old_stub->clear();
- }
+ clear_ic_stub();
if (is_optimized()) {
- set_ic_destination(entry);
- } else {
+ set_ic_destination(entry);
+ } else {
set_ic_destination_and_value(entry, (void*)NULL);
}
} else {
diff --git a/hotspot/src/share/vm/code/compiledIC.hpp b/hotspot/src/share/vm/code/compiledIC.hpp
index f2207cc..b797329 100644
--- a/hotspot/src/share/vm/code/compiledIC.hpp
+++ b/hotspot/src/share/vm/code/compiledIC.hpp
@@ -228,8 +228,9 @@
//
// They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
//
- void set_to_clean(); // Can only be called during a safepoint operation
+ void set_to_clean(bool in_use = true);
void set_to_monomorphic(CompiledICInfo& info);
+ void clear_ic_stub();
// Returns true if successful and false otherwise. The call can fail if memory
// allocation in the code cache fails.
diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp
index b31ede0..94f4962 100644
--- a/hotspot/src/share/vm/code/nmethod.cpp
+++ b/hotspot/src/share/vm/code/nmethod.cpp
@@ -1148,9 +1148,20 @@
}
}
+// Clear ICStubs of all compiled ICs
+void nmethod::clear_ic_stubs() {
+ assert_locked_or_safepoint(CompiledIC_lock);
+ RelocIterator iter(this);
+ while(iter.next()) {
+ if (iter.type() == relocInfo::virtual_call_type) {
+ CompiledIC* ic = CompiledIC_at(&iter);
+ ic->clear_ic_stub();
+ }
+ }
+}
+
void nmethod::cleanup_inline_caches() {
-
assert_locked_or_safepoint(CompiledIC_lock);
// If the method is not entrant or zombie then a JMP is plastered over the
@@ -1166,7 +1177,8 @@
// In fact, why are we bothering to look at oops in a non-entrant method??
}
- // Find all calls in an nmethod, and clear the ones that points to zombie methods
+ // Find all calls in an nmethod and clear the ones that point to non-entrant,
+ // zombie and unloaded nmethods.
ResourceMark rm;
RelocIterator iter(this, low_boundary);
while(iter.next()) {
@@ -1178,8 +1190,8 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
- // Clean inline caches pointing to both zombie and not_entrant methods
- if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
+ // Clean inline caches pointing to zombie, non-entrant and unloaded methods
+ if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive());
}
break;
}
@@ -1188,7 +1200,7 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
if( cb != NULL && cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
- // Clean inline caches pointing to both zombie and not_entrant methods
+ // Clean inline caches pointing to zombie, non-entrant and unloaded methods
if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
}
break;
@@ -1279,7 +1291,7 @@
// Tell if a non-entrant method can be converted to a zombie (i.e.,
// there are no activations on the stack, not in use by the VM,
// and not in use by the ServiceThread)
-bool nmethod::can_not_entrant_be_converted() {
+bool nmethod::can_convert_to_zombie() {
assert(is_not_entrant(), "must be a non-entrant method");
// Since the nmethod sweeper only does partial sweep the sweeper's traversal
@@ -2695,7 +2707,7 @@
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
// seems odd.
- if( is_zombie() || is_not_entrant() )
+ if (is_zombie() || is_not_entrant() || is_unloaded())
return;
// Make sure all the entry points are correctly aligned for patching.
diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp
index 7a39221..b7d6890 100644
--- a/hotspot/src/share/vm/code/nmethod.hpp
+++ b/hotspot/src/share/vm/code/nmethod.hpp
@@ -577,6 +577,7 @@
// Inline cache support
void clear_inline_caches();
+ void clear_ic_stubs();
void cleanup_inline_caches();
bool inlinecache_check_contains(address addr) const {
return (addr >= code_begin() && addr < verified_entry_point());
@@ -604,7 +605,7 @@
// See comment at definition of _last_seen_on_stack
void mark_as_seen_on_stack();
- bool can_not_entrant_be_converted();
+ bool can_convert_to_zombie();
// Evolution support. We make old (discarded) compiled methods point to new Method*s.
void set_method(Method* method) { _method = method; }
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp
index c380b89..b27696d 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp
@@ -117,7 +117,7 @@
G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) :
_g1h(g1h),
- _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)),
+ _process_strong_tasks(G1RP_PS_NumElements),
_srs(g1h),
_lock(Mutex::leaf, "G1 Root Scanning barrier lock", false),
_n_workers_discovered_strong_classes(0) {}
@@ -160,7 +160,7 @@
{
// Now the CM ref_processor roots.
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CMRefRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_refProcessor_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_refProcessor_oops_do)) {
// We need to treat the discovered reference lists of the
// concurrent mark ref processor as roots and keep entries
// (which are added by the marking threads) on them live
@@ -203,12 +203,12 @@
// as implicitly live).
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) {
JavaThread::satb_mark_queue_set().filter_thread_buffers();
}
}
- _process_strong_tasks->all_tasks_completed();
+ _process_strong_tasks.all_tasks_completed();
}
void G1RootProcessor::process_strong_roots(OopClosure* oops,
@@ -218,7 +218,7 @@
process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0);
process_vm_roots(oops, NULL, NULL, 0);
- _process_strong_tasks->all_tasks_completed();
+ _process_strong_tasks.all_tasks_completed();
}
void G1RootProcessor::process_all_roots(OopClosure* oops,
@@ -228,11 +228,11 @@
process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0);
process_vm_roots(oops, oops, NULL, 0);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_CodeCache_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) {
CodeCache::blobs_do(blobs);
}
- _process_strong_tasks->all_tasks_completed();
+ _process_strong_tasks.all_tasks_completed();
}
void G1RootProcessor::process_java_roots(OopClosure* strong_roots,
@@ -248,7 +248,7 @@
// let the thread process the weak CLDs and nmethods.
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CLDGRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ClassLoaderDataGraph_oops_do)) {
ClassLoaderDataGraph::roots_cld_do(strong_clds, weak_clds);
}
}
@@ -265,49 +265,49 @@
uint worker_i) {
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::UniverseRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Universe_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Universe_oops_do)) {
Universe::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JNIRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_JNIHandles_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_JNIHandles_oops_do)) {
JNIHandles::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ObjectSynchronizerRoots, worker_i);
- if (!_process_strong_tasks-> is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
FlatProfiler::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_Management_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) {
Management::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::JVMTIRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_jvmti_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_jvmti_oops_do)) {
JvmtiExport::oops_do(strong_roots);
}
}
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SystemDictionaryRoots, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) {
+ if (!_process_strong_tasks.is_task_claimed(G1RP_PS_SystemDictionary_oops_do)) {
SystemDictionary::roots_oops_do(strong_roots, weak_roots);
}
}
@@ -335,5 +335,5 @@
}
void G1RootProcessor::set_num_workers(int active_workers) {
- _process_strong_tasks->set_n_threads(active_workers);
+ _process_strong_tasks.set_n_threads(active_workers);
}
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp
index ee7b00f..1cce9f3 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp
@@ -45,7 +45,7 @@
// worker thread call the process_roots methods.
class G1RootProcessor : public StackObj {
G1CollectedHeap* _g1h;
- SubTasksDone* _process_strong_tasks;
+ SubTasksDone _process_strong_tasks;
SharedHeap::StrongRootsScope _srs;
// Used to implement the Thread work barrier.
diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp
index f9fec29..f0599a1 100644
--- a/hotspot/src/share/vm/opto/block.cpp
+++ b/hotspot/src/share/vm/opto/block.cpp
@@ -393,7 +393,7 @@
VectorSet visited(a);
// Allocate stack with enough space to avoid frequent realloc
- Node_Stack nstack(a, C->unique() >> 1);
+ Node_Stack nstack(a, C->live_nodes() >> 1);
nstack.push(_root, 0);
uint sum = 0; // Counter for blocks
diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp
index 2522303..85c6d51 100644
--- a/hotspot/src/share/vm/opto/cfgnode.cpp
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp
@@ -791,7 +791,7 @@
Compile *C = igvn->C;
Arena *a = Thread::current()->resource_area();
Node_Array node_map = new Node_Array(a);
- Node_Stack stack(a, C->unique() >> 4);
+ Node_Stack stack(a, C->live_nodes() >> 4);
PhiNode *nphi = slice_memory(at);
igvn->register_new_node_with_optimizer( nphi );
node_map.map(_idx, nphi);
diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp
index 9db6247..cbfabd3 100644
--- a/hotspot/src/share/vm/opto/compile.cpp
+++ b/hotspot/src/share/vm/opto/compile.cpp
@@ -327,7 +327,7 @@
// Use breadth-first pass that records state in a Unique_Node_List,
// recursive traversal is slower.
void Compile::identify_useful_nodes(Unique_Node_List &useful) {
- int estimated_worklist_size = unique();
+ int estimated_worklist_size = live_nodes();
useful.map( estimated_worklist_size, NULL ); // preallocate space
// Initialize worklist
@@ -3212,8 +3212,8 @@
Final_Reshape_Counts frc;
// Visit everybody reachable!
- // Allocate stack of size C->unique()/2 to avoid frequent realloc
- Node_Stack nstack(unique() >> 1);
+ // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc
+ Node_Stack nstack(live_nodes() >> 1);
final_graph_reshaping_walk(nstack, root(), frc);
// Check for unreachable (from below) code (i.e., infinite loops).
diff --git a/hotspot/src/share/vm/opto/domgraph.cpp b/hotspot/src/share/vm/opto/domgraph.cpp
index a7fa053..576506e 100644
--- a/hotspot/src/share/vm/opto/domgraph.cpp
+++ b/hotspot/src/share/vm/opto/domgraph.cpp
@@ -505,8 +505,8 @@
// Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup
// 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent.
int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uint *dfsorder) {
- // Allocate stack of size C->unique()/8 to avoid frequent realloc
- GrowableArray <Node *> dfstack(pil->C->unique() >> 3);
+ // Allocate stack of size C->live_nodes()/8 to avoid frequent realloc
+ GrowableArray <Node *> dfstack(pil->C->live_nodes() >> 3);
Node *b = pil->C->root();
int dfsnum = 1;
dfsorder[b->_idx] = dfsnum; // Cache parent's dfsnum for a later use
diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp
index 03a0e2d..b5e1f6b 100644
--- a/hotspot/src/share/vm/opto/escape.cpp
+++ b/hotspot/src/share/vm/opto/escape.cpp
@@ -3183,7 +3183,7 @@
// Note 2: MergeMem may already contains instance memory slices added
// during find_inst_mem() call when memory nodes were processed above.
igvn->hash_delete(nmm);
- uint nslices = nmm->req();
+ uint nslices = MIN2(nmm->req(), new_index_start);
for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) {
Node* mem = nmm->in(i);
Node* cur = NULL;
diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp
index 9d7b1b4..c574998 100644
--- a/hotspot/src/share/vm/opto/gcm.cpp
+++ b/hotspot/src/share/vm/opto/gcm.cpp
@@ -118,8 +118,8 @@
//------------------------------schedule_pinned_nodes--------------------------
// Set the basic block for Nodes pinned into blocks
void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) {
- // Allocate node stack of size C->unique()+8 to avoid frequent realloc
- GrowableArray <Node *> spstack(C->unique() + 8);
+ // Allocate node stack of size C->live_nodes()+8 to avoid frequent realloc
+ GrowableArray <Node *> spstack(C->live_nodes() + 8);
spstack.push(_root);
while (spstack.is_nonempty()) {
Node* node = spstack.pop();
@@ -1285,7 +1285,7 @@
visited.Clear();
Node_List stack(arena);
// Pre-grow the list
- stack.map((C->unique() >> 1) + 16, NULL);
+ stack.map((C->live_nodes() >> 1) + 16, NULL);
if (!schedule_early(visited, stack)) {
// Bailout without retry
C->record_method_not_compilable("early schedule failed");
diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp
index 57066d9..7fea1b4 100644
--- a/hotspot/src/share/vm/opto/loopnode.cpp
+++ b/hotspot/src/share/vm/opto/loopnode.cpp
@@ -2230,7 +2230,7 @@
// _nodes array holds the earliest legal controlling CFG node.
// Allocate stack with enough space to avoid frequent realloc
- int stack_size = (C->unique() >> 1) + 16; // (unique>>1)+16 from Java2D stats
+ int stack_size = (C->live_nodes() >> 1) + 16; // (live_nodes>>1)+16 from Java2D stats
Node_Stack nstack( a, stack_size );
visited.Clear();
@@ -2686,7 +2686,7 @@
}
}
if (_dom_stk == NULL) {
- uint init_size = C->unique() / 100; // Guess that 1/100 is a reasonable initial size.
+ uint init_size = C->live_nodes() / 100; // Guess that 1/100 is a reasonable initial size.
if (init_size < 10) init_size = 10;
_dom_stk = new GrowableArray<uint>(init_size);
}
@@ -2776,8 +2776,8 @@
// The sort is of size number-of-control-children, which generally limits
// it to size 2 (i.e., I just choose between my 2 target loops).
void PhaseIdealLoop::build_loop_tree() {
- // Allocate stack of size C->unique()/2 to avoid frequent realloc
- GrowableArray <Node *> bltstack(C->unique() >> 1);
+ // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc
+ GrowableArray <Node *> bltstack(C->live_nodes() >> 1);
Node *n = C->root();
bltstack.push(n);
int pre_order = 1;
@@ -3666,7 +3666,7 @@
void PhaseIdealLoop::dump( ) const {
ResourceMark rm;
Arena* arena = Thread::current()->resource_area();
- Node_Stack stack(arena, C->unique() >> 2);
+ Node_Stack stack(arena, C->live_nodes() >> 2);
Node_List rpo_list;
VectorSet visited(arena);
visited.set(C->top()->_idx);
diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp
index 179f3e1..f4097b3 100644
--- a/hotspot/src/share/vm/opto/matcher.cpp
+++ b/hotspot/src/share/vm/opto/matcher.cpp
@@ -335,14 +335,14 @@
grow_new_node_array(C->unique());
// Reset node counter so MachNodes start with _idx at 0
- int nodes = C->unique(); // save value
+ int live_nodes = C->live_nodes();
C->set_unique(0);
C->reset_dead_node_list();
// Recursively match trees from old space into new space.
// Correct leaves of new-space Nodes; they point to old-space.
_visited.Clear(); // Clear visit bits for xform call
- C->set_cached_top_node(xform( C->top(), nodes ));
+ C->set_cached_top_node(xform( C->top(), live_nodes));
if (!C->failing()) {
Node* xroot = xform( C->root(), 1 );
if (xroot == NULL) {
@@ -995,7 +995,7 @@
Node *Matcher::transform( Node *n ) { ShouldNotCallThis(); return n; }
Node *Matcher::xform( Node *n, int max_stack ) {
// Use one stack to keep both: child's node/state and parent's node/index
- MStack mstack(max_stack * 2 * 2); // C->unique() * 2 * 2
+ MStack mstack(max_stack * 2 * 2); // usually: C->live_nodes() * 2 * 2
mstack.push(n, Visit, NULL, -1); // set NULL as parent to indicate root
while (mstack.is_nonempty()) {
@@ -2021,8 +2021,8 @@
//------------------------------find_shared------------------------------------
// Set bits if Node is shared or otherwise a root
void Matcher::find_shared( Node *n ) {
- // Allocate stack of size C->unique() * 2 to avoid frequent realloc
- MStack mstack(C->unique() * 2);
+ // Allocate stack of size C->live_nodes() * 2 to avoid frequent realloc
+ MStack mstack(C->live_nodes() * 2);
// Mark nodes as address_visited if they are inputs to an address expression
VectorSet address_visited(Thread::current()->resource_area());
mstack.push(n, Visit); // Don't need to pre-visit root node
diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp
index dd3c079..8bd7f89 100644
--- a/hotspot/src/share/vm/opto/node.cpp
+++ b/hotspot/src/share/vm/opto/node.cpp
@@ -1749,7 +1749,7 @@
uint depth = (uint)ABS(d);
int direction = d;
Compile* C = Compile::current();
- GrowableArray <Node *> nstack(C->unique());
+ GrowableArray <Node *> nstack(C->live_nodes());
nstack.append(s);
int begin = 0;
diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp
index 3485132..2616f11 100644
--- a/hotspot/src/share/vm/opto/phaseX.cpp
+++ b/hotspot/src/share/vm/opto/phaseX.cpp
@@ -783,7 +783,7 @@
//------------------------------PhaseIterGVN-----------------------------------
// Initialize hash table to fresh and clean for +VerifyOpto
PhaseIterGVN::PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ) : PhaseGVN(igvn,dummy), _worklist( ),
- _stack(C->unique() >> 1),
+ _stack(C->live_nodes() >> 1),
_delay_transform(false) {
}
@@ -800,7 +800,11 @@
// Initialize with previous PhaseGVN info from Parser
PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn),
_worklist(*C->for_igvn()),
- _stack(C->unique() >> 1),
+// TODO: Before incremental inlining it was allocated only once and it was fine. Now that
+// the constructor is used in incremental inlining, this consumes too much memory:
+// _stack(C->live_nodes() >> 1),
+// So, as a band-aid, we replace this by:
+ _stack(C->comp_arena(), 32),
_delay_transform(false)
{
uint max;
@@ -1586,7 +1590,7 @@
_nodes.map( n->_idx, new_node ); // Flag as having been cloned
// Allocate stack of size _nodes.Size()/2 to avoid frequent realloc
- GrowableArray <Node *> trstack(C->unique() >> 1);
+ GrowableArray <Node *> trstack(C->live_nodes() >> 1);
trstack.push(new_node); // Process children of cloned node
while ( trstack.is_nonempty() ) {
diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
index d19b4a1..07a8a79 100644
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
@@ -3751,7 +3751,7 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ // Make the dependent methods not entrant
CodeCache::make_marked_nmethods_not_entrant();
// From now on we know that the dependency information is complete
diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp
index 20fe5e8..31f899b 100644
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -226,7 +226,8 @@
//
// * The monitor entry list operations avoid locks, but strictly speaking
// they're not lock-free. Enter is lock-free, exit is not.
-// See http://j2se.east/~dice/PERSIST/040825-LockFreeQueues.html
+// For a description of 'Methods and apparatus providing non-blocking access
+// to a resource,' see U.S. Pat. No. 7844973.
//
// * The cxq can have multiple concurrent "pushers" but only one concurrent
// detaching thread. This mechanism is immune from the ABA corruption.
@@ -1955,7 +1956,8 @@
// (duration) or we can fix the count at approximately the duration of
// a context switch and vary the frequency. Of course we could also
// vary both satisfying K == Frequency * Duration, where K is adaptive by monitor.
-// See http://j2se.east/~dice/PERSIST/040824-AdaptiveSpinning.html.
+// For a description of 'Adaptive spin-then-block mutual exclusion in
+// multi-threaded processing,' see U.S. Pat. No. 8046758.
//
// This implementation varies the duration "D", where D varies with
// the success rate of recent spin attempts. (D is capped at approximately
diff --git a/hotspot/src/share/vm/runtime/sweeper.cpp b/hotspot/src/share/vm/runtime/sweeper.cpp
index 4eba81d..b4954ff 100644
--- a/hotspot/src/share/vm/runtime/sweeper.cpp
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp
@@ -538,10 +538,14 @@
} else if (nm->is_not_entrant()) {
// If there are no current activations of this method on the
// stack we can safely convert it to a zombie method
- if (nm->can_not_entrant_be_converted()) {
+ if (nm->can_convert_to_zombie()) {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
}
+ // Clear ICStubs to prevent back patching stubs of zombie or unloaded
+ // nmethods during the next safepoint (see ICStub::finalize).
+ MutexLocker cl(CompiledIC_lock);
+ nm->clear_ic_stubs();
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
_zombified_count++;
@@ -567,6 +571,12 @@
release_nmethod(nm);
_flushed_count++;
} else {
+ {
+ // Clean ICs of unloaded nmethods as well because they may reference other
+ // unloaded nmethods that may be flushed earlier in the sweeper cycle.
+ MutexLocker cl(CompiledIC_lock);
+ nm->cleanup_inline_caches();
+ }
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
_zombified_count++;
diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp
index d46e1f7..a4219d2 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp
@@ -106,8 +106,8 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods zombies
- CodeCache::make_marked_nmethods_zombies();
+ // Make the dependent methods not entrant
+ CodeCache::make_marked_nmethods_not_entrant();
}
diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp
index 9875c6e..a8e6b0b 100644
--- a/hotspot/src/share/vm/services/management.cpp
+++ b/hotspot/src/share/vm/services/management.cpp
@@ -1107,6 +1107,8 @@
bool with_locked_monitors,
bool with_locked_synchronizers,
TRAPS) {
+ // no need to actually perform thread dump if no TIDs are specified
+ if (num_threads == 0) return;
// First get an array of threadObj handles.
// A JavaThread may terminate before we get the stack trace.
diff --git a/hotspot/test/compiler/escapeAnalysis/TestEABadMergeMem.java b/hotspot/test/compiler/escapeAnalysis/TestEABadMergeMem.java
new file mode 100644
index 0000000..236cbe7
--- /dev/null
+++ b/hotspot/test/compiler/escapeAnalysis/TestEABadMergeMem.java
@@ -0,0 +1,86 @@
+/*
+ * 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 8134031
+ * @summary Bad rewiring of memory edges when we split unique types during EA
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestEABadMergeMem::m_notinlined TestEABadMergeMem
+ *
+ */
+
+public class TestEABadMergeMem {
+
+ static class Box {
+ int i;
+ }
+
+ static void m_notinlined() {
+ }
+
+ static float dummy1;
+ static float dummy2;
+
+ static int test(Box a, Box c, int i, int j, int k, boolean flag1, boolean flag2) {
+ Box b = new Box(); // non escaping
+ a.i = i;
+ b.i = j;
+ c.i = k;
+
+ m_notinlined();
+
+ boolean flag3 = false;
+ if (flag1) {
+ for (int ii = 0; ii < 100; ii++) {
+ if (flag2) {
+ dummy1 = (float)ii;
+ } else {
+ dummy2 = (float)ii;
+ }
+ }
+ flag3 = true;
+ }
+ // Memory Phi here with projection of not inlined call as one edge, MergeMem as other
+
+ if (flag3) { // will split through Phi during loopopts
+ int res = c.i + b.i;
+ m_notinlined(); // prevents split through phi during igvn
+ return res;
+ } else {
+ return 44 + 43;
+ }
+ }
+
+ static public void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ // m(2);
+ Box a = new Box();
+ Box c = new Box();
+ int res = test(a, c, 42, 43, 44, (i%2) == 0, (i%3) == 0);
+ if (res != 44 + 43) {
+ throw new RuntimeException("Bad result " + res);
+ }
+ }
+ }
+
+}
diff --git a/jaxp/.hgtags b/jaxp/.hgtags
index dad5117..fe6deb0 100644
--- a/jaxp/.hgtags
+++ b/jaxp/.hgtags
@@ -509,3 +509,12 @@
5cadfe102e5c7fa1d5ea37991a3e7fc0337e7fab jdk8u71-b07
6efaec82e8da45264718ce9391bc02f196da63a0 jdk8u71-b08
19185d4e00661de65f3707328b014e3a011f5456 jdk8u71-b09
+60e623d06ebdcdc681943b16f00a87aeedf46873 jdk8u72-b00
+176a2ce2e2d6fd07964eca60c28c6b0049d7bc4d jdk8u72-b01
+3c5915665396301b730f808f8f5aa6e95b7c6113 jdk8u72-b02
+fb395cc3de779ad4274063c2a1d876194bcfaabf jdk8u72-b03
+5b5626716c88646895c4ada9ed1a35b24e7148c8 jdk8u72-b04
+1636e47c2d48d92827dac1493d292ebe19a2e108 jdk8u72-b05
+3a3863b12884f6167261f995b5eb0b8c69495f30 jdk8u72-b06
+8045ef94fd11dbda897404de345d1ea1eef52a01 jdk8u72-b07
+be05920afa17d374bc853d890a1575db097ac91c jdk8u72-b08
diff --git a/jaxws/.hgtags b/jaxws/.hgtags
index 633a355..3c191b0 100644
--- a/jaxws/.hgtags
+++ b/jaxws/.hgtags
@@ -503,3 +503,12 @@
58f12bf42e5d726b01429a5bbfe26955c6620051 jdk8u71-b07
7099cbc92fa4f4555e9ad8e19773851d701968b2 jdk8u71-b08
a46eae10609ff4c9199fec9bff277f892da00495 jdk8u71-b09
+3cbfc8bd4b1c83e151ba786778e04e8502ea13e4 jdk8u72-b00
+121e784f01d1b658866e499a42288b2f98eeb482 jdk8u72-b01
+c51556c23de38d5f4412622853e643bb8c67d647 jdk8u72-b02
+dddcabf97b4ab156545b3e98d67d6d3e37c8529e jdk8u72-b03
+baa0e7874269223b1726c9b2eccf628d0f72bcfe jdk8u72-b04
+b2b41f383c882ee7a8c2a54dfb0957aa2764d1f8 jdk8u72-b05
+fb0c51afcc55180608f07eb6697d517416ae15da jdk8u72-b06
+abf379db9ce09f747535558fa81d8468b220b810 jdk8u72-b07
+9c9e8cacf2b9161b2cbe232c6aa083fa09a5e63a jdk8u72-b08
diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/SchemaGenerator.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/SchemaGenerator.java
index cd4619a..f1f675e 100644
--- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/SchemaGenerator.java
+++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/SchemaGenerator.java
@@ -30,6 +30,7 @@
import com.sun.xml.internal.bind.util.Which;
import javax.lang.model.SourceVersion;
+import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
@@ -239,7 +240,12 @@
if (episode != null)
r.setEpisodeFile(episode);
task.setProcessors(Collections.singleton(r));
- return task.call();
+ boolean res = task.call();
+ //Print messages generated by compiler
+ for (Diagnostic<? extends JavaFileObject> d : diagnostics.getDiagnostics()) {
+ System.err.println(d.toString());
+ }
+ return res;
}
}
diff --git a/jdk/.hgtags b/jdk/.hgtags
index 1d35430..fead8f7 100644
--- a/jdk/.hgtags
+++ b/jdk/.hgtags
@@ -506,3 +506,12 @@
f556d4c82ef13430e2708053caa9e11a74b2aebf jdk8u71-b07
a81edad7e1e16c2b3cf2e60a8a98e232ebcaf3b1 jdk8u71-b08
eac13ca04cc5c9adb4f14a76856376db0187f7dc jdk8u71-b09
+be5faa9c77042f202106c18f4e8ea211137b4a3b jdk8u72-b00
+5ad1e9e8e8417f80c91d7e0f1f44cdf89b34ead3 jdk8u72-b01
+ab0c1040414d038ccbcfcc8ceb1ccf2f44ead8e4 jdk8u72-b02
+bdbb8a650d90d3481802a4f5297b522a16bd3f63 jdk8u72-b03
+b6645d81ccd773820aca99548640ace9c2f39225 jdk8u72-b04
+2bae9d627eb83f2ea23f4fa86e8eb46920cd1be6 jdk8u72-b05
+93148bc60f510af5160b6727533733c66284a84f jdk8u72-b06
+2a18f2af436ea62e7565ca0324f99112ef9cd4bc jdk8u72-b07
+c7d5bd8d04eb5d2adbb1112de95a2e2986e85925 jdk8u72-b08
diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk
index 758fa8e..066a4bf 100644
--- a/jdk/make/lib/CoreLibraries.gmk
+++ b/jdk/make/lib/CoreLibraries.gmk
@@ -205,6 +205,7 @@
-framework Foundation \
-framework Security -framework SystemConfiguration, \
LDFLAGS_SUFFIX_windows := -export:winFileHandleOpen -export:handleLseek \
+ -export:getErrorString \
jvm.lib $(BUILD_LIBFDLIBM) $(WIN_VERIFY_LIB) \
shell32.lib delayimp.lib -DELAYLOAD:shell32.dll \
advapi32.lib version.lib, \
diff --git a/jdk/make/mapfiles/libawt/mapfile-mawt-vers b/jdk/make/mapfiles/libawt/mapfile-mawt-vers
index b8ea163..28ad353 100644
--- a/jdk/make/mapfiles/libawt/mapfile-mawt-vers
+++ b/jdk/make/mapfiles/libawt/mapfile-mawt-vers
@@ -242,7 +242,7 @@
getDefaultConfig;
Java_sun_font_FontConfigManager_getFontConfig;
Java_sun_font_FontConfigManager_getFontConfigAASettings;
- Java_sun_awt_X11FontManager_getFontPathNative;
+ Java_sun_awt_FcFontManager_getFontPathNative;
Java_sun_font_SunFontManager_populateFontFileNameMap;
# CDE private entry point
diff --git a/jdk/make/mapfiles/libawt/mapfile-vers-linux b/jdk/make/mapfiles/libawt/mapfile-vers-linux
index 922b015..5624693 100644
--- a/jdk/make/mapfiles/libawt/mapfile-vers-linux
+++ b/jdk/make/mapfiles/libawt/mapfile-vers-linux
@@ -270,7 +270,7 @@
getDefaultConfig;
Java_sun_font_FontConfigManager_getFontConfig;
Java_sun_font_FontConfigManager_getFontConfigAASettings;
- Java_sun_awt_X11FontManager_getFontPathNative;
+ Java_sun_awt_FcFontManager_getFontPathNative;
Java_sun_font_SunFontManager_populateFontFileNameMap;
# CDE private entry point
diff --git a/jdk/make/mapfiles/libawt_headless/mapfile-vers b/jdk/make/mapfiles/libawt_headless/mapfile-vers
index c12d07d..44efc29 100644
--- a/jdk/make/mapfiles/libawt_headless/mapfile-vers
+++ b/jdk/make/mapfiles/libawt_headless/mapfile-vers
@@ -65,7 +65,7 @@
Java_sun_font_FontConfigManager_getFontConfig;
Java_sun_font_FontConfigManager_getFontConfigAASettings;
Java_sun_font_FontConfigManager_getFontConfigVersion;
- Java_sun_awt_X11FontManager_getFontPathNative;
+ Java_sun_awt_FcFontManager_getFontPathNative;
Java_sun_awt_FontDescriptor_initIDs;
Java_sun_awt_PlatformFont_initIDs;
diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers
index 3ae8af3..d24a527 100644
--- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers
+++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers
@@ -188,7 +188,7 @@
Java_sun_font_FontConfigManager_getFontConfig;
Java_sun_font_FontConfigManager_getFontConfigAASettings;
Java_sun_font_FontConfigManager_getFontConfigVersion;
- Java_sun_awt_X11FontManager_getFontPathNative;
+ Java_sun_awt_FcFontManager_getFontPathNative;
Java_sun_awt_X11GraphicsEnvironment_initDisplay;
Java_sun_awt_X11GraphicsEnvironment_initGLX;
Java_sun_awt_X11GraphicsEnvironment_initXRender;
diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers
index c4775ea..618d501 100644
--- a/jdk/make/mapfiles/libjava/mapfile-vers
+++ b/jdk/make/mapfiles/libjava/mapfile-vers
@@ -284,6 +284,8 @@
# ZipFile.c needs this one
throwFileNotFoundException;
+ # zip_util.c needs this
+ getErrorString;
# Java_sun_misc_VM_getState; threads.c
# Java_sun_misc_VM_threadsSuspended; threads.c
diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers
index 5cc8b93..0e432d3 100644
--- a/jdk/make/mapfiles/libnet/mapfile-vers
+++ b/jdk/make/mapfiles/libnet/mapfile-vers
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 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
@@ -28,8 +28,7 @@
SUNWprivate_1.1 {
global:
JNI_OnLoad;
- Java_java_net_AbstractPlainDatagramSocketImpl_init;
- Java_java_net_AbstractPlainDatagramSocketImpl_dataAvailable;
+ Java_java_net_PlainDatagramSocketImpl_dataAvailable;
Java_java_net_PlainSocketImpl_socketListen;
Java_java_net_PlainDatagramSocketImpl_getTTL;
Java_java_net_PlainDatagramSocketImpl_init;
diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java
index 26d2347..429a395 100644
--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CDataTransferer.java
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -27,9 +28,10 @@
import java.awt.*;
import java.awt.image.*;
-import sun.awt.image.ImageRepresentation;
import java.io.*;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.URL;
import java.text.Normalizer;
import java.text.Normalizer.Form;
@@ -54,7 +56,8 @@
"PDF",
"URL",
"PNG",
- "JFIF"
+ "JFIF",
+ "XPICT"
};
static {
@@ -78,6 +81,7 @@
public static final int CF_URL = 7;
public static final int CF_PNG = 8;
public static final int CF_JPEG = 9;
+ public static final int CF_XPICT = 10;
private CDataTransferer() {}
@@ -122,26 +126,43 @@
@Override
public Object translateBytes(byte[] bytes, DataFlavor flavor,
- long format, Transferable transferable) throws IOException {
+ long format, Transferable transferable) throws IOException {
- if (format == CF_URL && URL.class.equals(flavor.getRepresentationClass()))
- {
- String charset = getDefaultTextCharset();
- if (transferable != null && transferable.isDataFlavorSupported(javaTextEncodingFlavor)) {
- try {
- charset = new String((byte[])transferable.getTransferData(javaTextEncodingFlavor), "UTF-8");
- } catch (UnsupportedFlavorException cannotHappen) {
- }
+
+ if (format == CF_URL && URL.class.equals(flavor.getRepresentationClass())) {
+ String[] strings = dragQueryFile(bytes);
+ if(strings == null || strings.length == 0) {
+ return null;
+ }
+ return new URL(strings[0]);
+ } else if(isUriListFlavor(flavor)) {
+ // dragQueryFile works fine with files and url,
+ // it parses and extracts values from property list.
+ // maxosx always returns property list for
+ // CF_URL and CF_FILE
+ String[] strings = dragQueryFile(bytes);
+ if(strings == null) {
+ return null;
+ }
+ String separator = System.getProperty("line.separator");
+ StringBuilder sb = new StringBuilder();
+ if(strings.length > 0) {
+ sb.append(strings[0]);
+ for(int i = 1; i < strings.length; i++) {
+ sb.append(strings[i]);
+ sb.append(separator);
}
-
- return new URL(new String(bytes, charset));
}
+ bytes = sb.toString().getBytes();
+ // now we extracted uri from xml, now we should treat it as
+ // regular string that allows to translate data to target represantation
+ // class by base method
+ format = CF_STRING;
+ } else if (format == CF_STRING) {
+ bytes = Normalizer.normalize(new String(bytes, "UTF8"), Form.NFC).getBytes("UTF8");
+ }
- if (format == CF_STRING) {
- bytes = Normalizer.normalize(new String(bytes, "UTF8"), Form.NFC).getBytes("UTF8");
- }
-
- return super.translateBytes(bytes, flavor, format, transferable);
+ return super.translateBytes(bytes, flavor, format, transferable);
}
@Override
@@ -219,6 +240,7 @@
return nativeDragQueryFile(bytes);
}
+
@Override
protected Image platformImageBytesToImage(byte[] bytes, long format) throws IOException {
return CImage.getCreator().createImageFromPlatformImageBytes(bytes);
@@ -243,7 +265,7 @@
}
try {
DataFlavor df = new DataFlavor(nat);
- if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
+ if (isUriListFlavor(df)) {
return true;
}
} catch (Exception e) {
@@ -251,6 +273,13 @@
}
return false;
}
+
+ private boolean isUriListFlavor(DataFlavor df) {
+ if (df.getPrimaryType().equals("text") && df.getSubType().equals("uri-list")) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
index cc89642..352ab7e 100644
--- a/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
+++ b/jdk/src/macosx/classes/sun/nio/ch/KQueueSelectorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -84,10 +84,24 @@
long fds = IOUtil.makePipe(false);
fd0 = (int)(fds >>> 32);
fd1 = (int)fds;
- kqueueWrapper = new KQueueArrayWrapper();
- kqueueWrapper.initInterrupt(fd0, fd1);
- fdMap = new HashMap<>();
- totalChannels = 1;
+ try {
+ kqueueWrapper = new KQueueArrayWrapper();
+ kqueueWrapper.initInterrupt(fd0, fd1);
+ fdMap = new HashMap<>();
+ totalChannels = 1;
+ } catch (Throwable t) {
+ try {
+ FileDispatcherImpl.closeIntFD(fd0);
+ } catch (IOException ioe0) {
+ t.addSuppressed(ioe0);
+ }
+ try {
+ FileDispatcherImpl.closeIntFD(fd1);
+ } catch (IOException ioe1) {
+ t.addSuppressed(ioe1);
+ }
+ throw t;
+ }
}
diff --git a/jdk/src/macosx/lib/flavormap.properties b/jdk/src/macosx/lib/flavormap.properties
index 8f17d95..dc04804 100644
--- a/jdk/src/macosx/lib/flavormap.properties
+++ b/jdk/src/macosx/lib/flavormap.properties
@@ -80,4 +80,6 @@
RICH_TEXT=text/rtf
HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1
URL=application/x-java-url;class=java.net.URL
+FILE_NAME=text/uri-list;eoln="\r\n";terminators=1
URL=text/uri-list;eoln="\r\n";terminators=1
+XPICT=image/x-pict;class=java.io.InputStream
diff --git a/jdk/src/macosx/native/sun/awt/CDataTransferer.m b/jdk/src/macosx/native/sun/awt/CDataTransferer.m
index 488068a..4c1e1a4 100644
--- a/jdk/src/macosx/native/sun/awt/CDataTransferer.m
+++ b/jdk/src/macosx/native/sun/awt/CDataTransferer.m
@@ -58,6 +58,8 @@
forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_PNG]];
[sStandardMappings setObject:(NSString*)kUTTypeJPEG
forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_JPEG]];
+ [sStandardMappings setObject:NSPICTPboardType
+ forKey:[NSNumber numberWithLong:sun_lwawt_macosx_CDataTransferer_CF_XPICT]];
}
return sStandardMappings;
}
diff --git a/jdk/src/macosx/native/sun/awt/LWCToolkit.m b/jdk/src/macosx/native/sun/awt/LWCToolkit.m
index b16760b..8b34eba 100644
--- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m
+++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m
@@ -287,7 +287,7 @@
// Processing all events excluding NSApplicationDefined which need to be processed
// on the main loop only (those events are intended for disposing resources)
NSEvent *event;
- if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefined)
+ if ((event = [NSApp nextEventMatchingMask:(NSAnyEventMask & ~NSApplicationDefinedMask)
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES]) != nil) {
diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java b/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java
index e0d0454..f6b42d3 100644
--- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java
+++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapClient.java
@@ -494,16 +494,14 @@
*/
void processConnectionClosure() {
// Notify listeners
- synchronized (unsolicited) {
- if (unsolicited.size() > 0) {
- String msg;
- if (conn != null) {
- msg = conn.host + ":" + conn.port + " connection closed";
- } else {
- msg = "Connection closed";
- }
- notifyUnsolicited(new CommunicationException(msg));
+ if (unsolicited.size() > 0) {
+ String msg;
+ if (conn != null) {
+ msg = conn.host + ":" + conn.port + " connection closed";
+ } else {
+ msg = "Connection closed";
}
+ notifyUnsolicited(new CommunicationException(msg));
}
// Remove from pool
@@ -1499,13 +1497,8 @@
if (debug > 0) {
System.err.println("LdapClient.removeUnsolicited" + ctx);
}
- synchronized (unsolicited) {
- if (unsolicited.size() == 0) {
- return;
- }
unsolicited.removeElement(ctx);
}
- }
// NOTE: Cannot be synchronized because this is called asynchronously
// by the reader thread in Connection. Instead, sync on 'unsolicited' Vector.
@@ -1513,30 +1506,35 @@
if (debug > 0) {
System.err.println("LdapClient.processUnsolicited");
}
- synchronized (unsolicited) {
- try {
- // Parse the response
- LdapResult res = new LdapResult();
+ try {
+ // Parse the response
+ LdapResult res = new LdapResult();
- ber.parseSeq(null); // init seq
- ber.parseInt(); // msg id; should be 0; ignored
- if (ber.parseByte() != LDAP_REP_EXTENSION) {
- throw new IOException(
- "Unsolicited Notification must be an Extended Response");
- }
- ber.parseLength();
- parseExtResponse(ber, res);
+ ber.parseSeq(null); // init seq
+ ber.parseInt(); // msg id; should be 0; ignored
+ if (ber.parseByte() != LDAP_REP_EXTENSION) {
+ throw new IOException(
+ "Unsolicited Notification must be an Extended Response");
+ }
+ ber.parseLength();
+ parseExtResponse(ber, res);
- if (DISCONNECT_OID.equals(res.extensionId)) {
- // force closing of connection
- forceClose(pooled);
- }
+ if (DISCONNECT_OID.equals(res.extensionId)) {
+ // force closing of connection
+ forceClose(pooled);
+ }
+ LdapCtx first = null;
+ UnsolicitedNotification notice = null;
+
+ synchronized (unsolicited) {
if (unsolicited.size() > 0) {
+ first = unsolicited.elementAt(0);
+
// Create an UnsolicitedNotification using the parsed data
// Need a 'ctx' object because we want to use the context's
// list of provider control factories.
- UnsolicitedNotification notice = new UnsolicitedResponseImpl(
+ notice = new UnsolicitedResponseImpl(
res.extensionId,
res.extensionValue,
res.referrals,
@@ -1544,42 +1542,45 @@
res.errorMessage,
res.matchedDN,
(res.resControls != null) ?
- unsolicited.elementAt(0).convertControls(res.resControls) :
+ first.convertControls(res.resControls) :
null);
-
- // Fire UnsolicitedNotification events to listeners
- notifyUnsolicited(notice);
-
- // If "disconnect" notification,
- // notify unsolicited listeners via NamingException
- if (DISCONNECT_OID.equals(res.extensionId)) {
- notifyUnsolicited(
- new CommunicationException("Connection closed"));
- }
}
- } catch (IOException e) {
- if (unsolicited.size() == 0)
- return; // no one registered; ignore
-
- NamingException ne = new CommunicationException(
- "Problem parsing unsolicited notification");
- ne.setRootCause(e);
-
- notifyUnsolicited(ne);
-
- } catch (NamingException e) {
- notifyUnsolicited(e);
}
+
+ if (notice != null) {
+ // Fire UnsolicitedNotification events to listeners
+ notifyUnsolicited(notice);
+
+ // If "disconnect" notification,
+ // notify unsolicited listeners via NamingException
+ if (DISCONNECT_OID.equals(res.extensionId)) {
+ notifyUnsolicited(
+ new CommunicationException("Connection closed"));
+ }
+ }
+ } catch (IOException e) {
+ NamingException ne = new CommunicationException(
+ "Problem parsing unsolicited notification");
+ ne.setRootCause(e);
+
+ notifyUnsolicited(ne);
+
+ } catch (NamingException e) {
+ notifyUnsolicited(e);
}
}
private void notifyUnsolicited(Object e) {
- for (int i = 0; i < unsolicited.size(); i++) {
- unsolicited.elementAt(i).fireUnsolicited(e);
+ Vector<LdapCtx> unsolicitedCopy;
+ synchronized (unsolicited) {
+ unsolicitedCopy = new Vector<>(unsolicited);
+ if (e instanceof NamingException) {
+ unsolicited.setSize(0); // no more listeners after exception
+ }
}
- if (e instanceof NamingException) {
- unsolicited.setSize(0); // no more listeners after exception
+ for (int i = 0; i < unsolicitedCopy.size(); i++) {
+ unsolicitedCopy.elementAt(i).fireUnsolicited(e);
}
}
diff --git a/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java b/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java
index 3397e0f..83547e4 100644
--- a/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java
+++ b/jdk/src/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -1041,12 +1041,11 @@
}
Type findBootType(String signature) throws ClassNotLoadedException {
- List<ReferenceType> types = allClasses();
+ List<ReferenceType> types = retrieveClassesBySignature(signature);
Iterator<ReferenceType> iter = types.iterator();
while (iter.hasNext()) {
ReferenceType type = iter.next();
- if ((type.classLoader() == null) &&
- (type.signature().equals(signature))) {
+ if (type.classLoader() == null) {
return type;
}
}
diff --git a/jdk/src/share/classes/java/awt/EventQueue.java b/jdk/src/share/classes/java/awt/EventQueue.java
index d0d8539..f050900 100644
--- a/jdk/src/share/classes/java/awt/EventQueue.java
+++ b/jdk/src/share/classes/java/awt/EventQueue.java
@@ -896,11 +896,13 @@
}
}
- // Wake up EDT waiting in getNextEvent(), so it can
- // pick up a new EventQueue. Post the waking event before
- // topQueue.nextQueue is assigned, otherwise the event would
- // go newEventQueue
- topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
+ if (topQueue.dispatchThread != null) {
+ // Wake up EDT waiting in getNextEvent(), so it can
+ // pick up a new EventQueue. Post the waking event before
+ // topQueue.nextQueue is assigned, otherwise the event would
+ // go newEventQueue
+ topQueue.postEventPrivate(new InvocationEvent(topQueue, dummyRunnable));
+ }
newEventQueue.previousQueue = topQueue;
topQueue.nextQueue = newEventQueue;
diff --git a/jdk/src/share/classes/java/lang/Character.java b/jdk/src/share/classes/java/lang/Character.java
index 3fda1bb..60f05f0 100644
--- a/jdk/src/share/classes/java/lang/Character.java
+++ b/jdk/src/share/classes/java/lang/Character.java
@@ -6647,7 +6647,7 @@
* <td>{@code FORM FEED}</td></tr>
* <tr><td>{@code '\r'}</td> <td>{@code U+000D}</td>
* <td>{@code CARRIAGE RETURN}</td></tr>
- * <tr><td>{@code ' '}</td> <td>{@code U+0020}</td>
+ * <tr><td>{@code ' '}</td> <td>{@code U+0020}</td>
* <td>{@code SPACE}</td></tr>
* </table>
*
diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaFormEditor.java b/jdk/src/share/classes/java/lang/invoke/LambdaFormEditor.java
index 7bc2dfb..7368108 100644
--- a/jdk/src/share/classes/java/lang/invoke/LambdaFormEditor.java
+++ b/jdk/src/share/classes/java/lang/invoke/LambdaFormEditor.java
@@ -436,7 +436,7 @@
}
private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
- assert(mh.form == lambdaForm);
+ assert(mh.form.uncustomize() == lambdaForm);
assert(mh.form.names[1+pos].type == bt);
assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
return mh.type().dropParameterTypes(pos, pos+1);
diff --git a/jdk/src/share/classes/java/lang/invoke/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java
index cd169f3..d0c6e42 100644
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java
@@ -93,7 +93,7 @@
/** Return the simple name of this member.
* For a type, it is the same as {@link Class#getSimpleName}.
* For a method or field, it is the simple name of the member.
- * For a constructor, it is always {@code "<init>"}.
+ * For a constructor, it is always {@code "<init>"}.
*/
public String getName() {
if (name == null) {
@@ -727,7 +727,7 @@
}
/** Create a method or constructor name from the given components:
* Declaring class, name, type, reference kind.
- * It will be a constructor if and only if the name is {@code "<init>"}.
+ * It will be a constructor if and only if the name is {@code "<init>"}.
* The declaring class may be supplied as null if this is to be a bare name and type.
* The last argument is optional, a boolean which requests REF_invokeSpecial.
* The resulting name will in an unresolved state.
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
index d63db84..ad6799a 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java
@@ -155,7 +155,7 @@
/**
* Returns the name of the cracked method handle's underlying member.
- * This is {@code "<init>"} if the underlying member was a constructor,
+ * This is {@code "<init>"} if the underlying member was a constructor,
* else it is a simple method name or field name.
* @return the simple name of the underlying member
*/
diff --git a/jdk/src/share/classes/java/lang/invoke/Stable.java b/jdk/src/share/classes/java/lang/invoke/Stable.java
index 077c546..a0a413e 100644
--- a/jdk/src/share/classes/java/lang/invoke/Stable.java
+++ b/jdk/src/share/classes/java/lang/invoke/Stable.java
@@ -51,7 +51,7 @@
* If the field is an array type, then both the field value and
* all the components of the field value (if the field value is non-null)
* are indicated to be stable.
- * If the field type is an array type with rank {@code N > 1},
+ * If the field type is an array type with rank {@code N > 1},
* then each component of the field value (if the field value is non-null),
* is regarded as a stable array of rank {@code N-1}.
* <p>
diff --git a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
index 01c16f5..5d9b3bf 100644
--- a/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
+++ b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
@@ -55,20 +55,20 @@
* At that point {@code guardWithTest} may ignore {@code T} and return {@code F}.
* <p>
* Here is an example of a switch point in action:
- * <blockquote><pre>{@code
-MethodHandle MH_strcat = MethodHandles.lookup()
- .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
-SwitchPoint spt = new SwitchPoint();
-assert(!spt.hasBeenInvalidated());
-// the following steps may be repeated to re-use the same switch point:
-MethodHandle worker1 = MH_strcat;
-MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
-MethodHandle worker = spt.guardWithTest(worker1, worker2);
-assertEquals("method", (String) worker.invokeExact("met", "hod"));
-SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
-assert(spt.hasBeenInvalidated());
-assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
- * }</pre></blockquote>
+ * <pre>{@code
+ * MethodHandle MH_strcat = MethodHandles.lookup()
+ * .findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class));
+ * SwitchPoint spt = new SwitchPoint();
+ * assert(!spt.hasBeenInvalidated());
+ * // the following steps may be repeated to re-use the same switch point:
+ * MethodHandle worker1 = MH_strcat;
+ * MethodHandle worker2 = MethodHandles.permuteArguments(MH_strcat, MH_strcat.type(), 1, 0);
+ * MethodHandle worker = spt.guardWithTest(worker1, worker2);
+ * assertEquals("method", (String) worker.invokeExact("met", "hod"));
+ * SwitchPoint.invalidateAll(new SwitchPoint[]{ spt });
+ * assert(spt.hasBeenInvalidated());
+ * assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
+ * }</pre>
* <p style="font-size:smaller;">
* <em>Discussion:</em>
* Switch points are useful without subclassing. They may also be subclassed.
@@ -82,31 +82,31 @@
* <em>Implementation Note:</em>
* A switch point behaves as if implemented on top of {@link MutableCallSite},
* approximately as follows:
- * <blockquote><pre>{@code
-public class SwitchPoint {
- private static final MethodHandle
- K_true = MethodHandles.constant(boolean.class, true),
- K_false = MethodHandles.constant(boolean.class, false);
- private final MutableCallSite mcs;
- private final MethodHandle mcsInvoker;
- public SwitchPoint() {
- this.mcs = new MutableCallSite(K_true);
- this.mcsInvoker = mcs.dynamicInvoker();
- }
- public MethodHandle guardWithTest(
- MethodHandle target, MethodHandle fallback) {
- // Note: mcsInvoker is of type ()boolean.
- // Target and fallback may take any arguments, but must have the same type.
- return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
- }
- public static void invalidateAll(SwitchPoint[] spts) {
- List<MutableCallSite> mcss = new ArrayList<>();
- for (SwitchPoint spt : spts) mcss.add(spt.mcs);
- for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
- MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
- }
-}
- * }</pre></blockquote>
+ * <pre>{@code
+ * public class SwitchPoint {
+ * private static final MethodHandle
+ * K_true = MethodHandles.constant(boolean.class, true),
+ * K_false = MethodHandles.constant(boolean.class, false);
+ * private final MutableCallSite mcs;
+ * private final MethodHandle mcsInvoker;
+ * public SwitchPoint() {
+ * this.mcs = new MutableCallSite(K_true);
+ * this.mcsInvoker = mcs.dynamicInvoker();
+ * }
+ * public MethodHandle guardWithTest(
+ * MethodHandle target, MethodHandle fallback) {
+ * // Note: mcsInvoker is of type ()boolean.
+ * // Target and fallback may take any arguments, but must have the same type.
+ * return MethodHandles.guardWithTest(this.mcsInvoker, target, fallback);
+ * }
+ * public static void invalidateAll(SwitchPoint[] spts) {
+ * List<MutableCallSite> mcss = new ArrayList<>();
+ * for (SwitchPoint spt : spts) mcss.add(spt.mcs);
+ * for (MutableCallSite mcs : mcss) mcs.setTarget(K_false);
+ * MutableCallSite.syncAll(mcss.toArray(new MutableCallSite[0]));
+ * }
+ * }
+ * }</pre>
* @author Remi Forax, JSR 292 EG
*/
public class SwitchPoint {
diff --git a/jdk/src/share/classes/java/lang/ref/Reference.java b/jdk/src/share/classes/java/lang/ref/Reference.java
index 42d2ba9..5febcae 100644
--- a/jdk/src/share/classes/java/lang/ref/Reference.java
+++ b/jdk/src/share/classes/java/lang/ref/Reference.java
@@ -26,6 +26,8 @@
package java.lang.ref;
import sun.misc.Cleaner;
+import sun.misc.JavaLangRefAccess;
+import sun.misc.SharedSecrets;
/**
* Abstract base class for reference objects. This class defines the
@@ -111,7 +113,7 @@
* therefore critical that any code holding this lock complete as quickly
* as possible, allocate no new objects, and avoid calling user code.
*/
- static private class Lock { };
+ static private class Lock { }
private static Lock lock = new Lock();
@@ -126,53 +128,96 @@
*/
private static class ReferenceHandler extends Thread {
+ private static void ensureClassInitialized(Class<?> clazz) {
+ try {
+ Class.forName(clazz.getName(), true, clazz.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
+ }
+ }
+
+ static {
+ // pre-load and initialize InterruptedException and Cleaner classes
+ // so that we don't get into trouble later in the run loop if there's
+ // memory shortage while loading/initializing them lazily.
+ ensureClassInitialized(InterruptedException.class);
+ ensureClassInitialized(Cleaner.class);
+ }
+
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
- for (;;) {
- Reference<Object> r;
- synchronized (lock) {
- if (pending != null) {
- r = pending;
- pending = r.discovered;
- r.discovered = null;
- } else {
- // The waiting on the lock may cause an OOME because it may try to allocate
- // exception objects, so also catch OOME here to avoid silent exit of the
- // reference handler thread.
- //
- // Explicitly define the order of the two exceptions we catch here
- // when waiting for the lock.
- //
- // We do not want to try to potentially load the InterruptedException class
- // (which would be done if this was its first use, and InterruptedException
- // were checked first) in this situation.
- //
- // This may lead to the VM not ever trying to load the InterruptedException
- // class again.
- try {
- try {
- lock.wait();
- } catch (OutOfMemoryError x) { }
- } catch (InterruptedException x) { }
- continue;
- }
- }
-
- // Fast path for cleaners
- if (r instanceof Cleaner) {
- ((Cleaner)r).clean();
- continue;
- }
-
- ReferenceQueue<Object> q = r.queue;
- if (q != ReferenceQueue.NULL) q.enqueue(r);
+ while (true) {
+ tryHandlePending(true);
}
}
}
+ /**
+ * Try handle pending {@link Reference} if there is one.<p>
+ * Return {@code true} as a hint that there might be another
+ * {@link Reference} pending or {@code false} when there are no more pending
+ * {@link Reference}s at the moment and the program can do some other
+ * useful work instead of looping.
+ *
+ * @param waitForNotify if {@code true} and there was no pending
+ * {@link Reference}, wait until notified from VM
+ * or interrupted; if {@code false}, return immediately
+ * when there is no pending {@link Reference}.
+ * @return {@code true} if there was a {@link Reference} pending and it
+ * was processed, or we waited for notification and either got it
+ * or thread was interrupted before being notified;
+ * {@code false} otherwise.
+ */
+ static boolean tryHandlePending(boolean waitForNotify) {
+ Reference<Object> r;
+ Cleaner c;
+ try {
+ synchronized (lock) {
+ if (pending != null) {
+ r = pending;
+ // 'instanceof' might throw OutOfMemoryError sometimes
+ // so do this before un-linking 'r' from the 'pending' chain...
+ c = r instanceof Cleaner ? (Cleaner) r : null;
+ // unlink 'r' from 'pending' chain
+ pending = r.discovered;
+ r.discovered = null;
+ } else {
+ // The waiting on the lock may cause an OutOfMemoryError
+ // because it may try to allocate exception objects.
+ if (waitForNotify) {
+ lock.wait();
+ }
+ // retry if waited
+ return waitForNotify;
+ }
+ }
+ } catch (OutOfMemoryError x) {
+ // Give other threads CPU time so they hopefully drop some live references
+ // and GC reclaims some space.
+ // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
+ // persistently throws OOME for some time...
+ Thread.yield();
+ // retry
+ return true;
+ } catch (InterruptedException x) {
+ // retry
+ return true;
+ }
+
+ // Fast path for cleaners
+ if (c != null) {
+ c.clean();
+ return true;
+ }
+
+ ReferenceQueue<? super Object> q = r.queue;
+ if (q != ReferenceQueue.NULL) q.enqueue(r);
+ return true;
+ }
+
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
@@ -185,8 +230,15 @@
handler.setPriority(Thread.MAX_PRIORITY);
handler.setDaemon(true);
handler.start();
- }
+ // provide access in SharedSecrets
+ SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
+ @Override
+ public boolean tryHandlePendingReference() {
+ return tryHandlePending(false);
+ }
+ });
+ }
/* -- Referent accessor and setters -- */
diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java
index fb2aa2c..bf17091 100644
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java
@@ -218,6 +218,7 @@
/**
* {@inheritDoc}
+ * @since 1.8
*/
public int getParameterCount() { return parameterTypes.length; }
diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java
index ca55d09..3e82d99 100644
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java
@@ -245,7 +245,6 @@
* declared or implicitly declared or neither) for the executable
* represented by this object.
*
- * @since 1.8
* @return The number of formal parameters for the executable this
* object represents
*/
@@ -343,7 +342,6 @@
* have unique names, or names that are legal identifiers in the
* Java programming language (JLS 3.8).
*
- * @since 1.8
* @throws MalformedParametersException if the class file contains
* a MethodParameters attribute that is improperly formatted.
* @return an array of {@code Parameter} objects representing all
@@ -575,7 +573,6 @@
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
- * @since 1.8
*/
@Override
public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
@@ -623,8 +620,6 @@
*
* @return an object representing the return type of the method
* or constructor represented by this {@code Executable}
- *
- * @since 1.8
*/
public abstract AnnotatedType getAnnotatedReturnType();
@@ -633,8 +628,6 @@
* Returns an AnnotatedType object that represents the use of a type to
* specify the return type of the method/constructor represented by this
* Executable.
- *
- * @since 1.8
*/
AnnotatedType getAnnotatedReturnType0(Type returnType) {
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(),
@@ -664,8 +657,6 @@
*
* @return an object representing the receiver type of the method or
* constructor represented by this {@code Executable}
- *
- * @since 1.8
*/
public AnnotatedType getAnnotatedReceiverType() {
if (Modifier.isStatic(this.getModifiers()))
@@ -692,8 +683,6 @@
* @return an array of objects representing the types of the
* formal parameters of the method or constructor represented by this
* {@code Executable}
- *
- * @since 1.8
*/
public AnnotatedType[] getAnnotatedParameterTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
@@ -718,8 +707,6 @@
* @return an array of objects representing the declared
* exceptions of the method or constructor represented by this {@code
* Executable}
- *
- * @since 1.8
*/
public AnnotatedType[] getAnnotatedExceptionTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java
index 786aac6..ddf0f38 100644
--- a/jdk/src/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java
@@ -266,6 +266,7 @@
/**
* {@inheritDoc}
+ * @since 1.8
*/
public int getParameterCount() { return parameterTypes.length; }
diff --git a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
index 1793cfc..fdc3843 100644
--- a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
+++ b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -68,7 +68,6 @@
return null;
}
});
- init();
}
/**
@@ -364,6 +363,5 @@
return connectDisabled;
}
- native int dataAvailable();
- private static native void init();
+ abstract int dataAvailable();
}
diff --git a/jdk/src/share/classes/java/nio/Bits.java b/jdk/src/share/classes/java/nio/Bits.java
index 11f2b6d..c7f2b78 100644
--- a/jdk/src/share/classes/java/nio/Bits.java
+++ b/jdk/src/share/classes/java/nio/Bits.java
@@ -26,6 +26,11 @@
package java.nio;
import java.security.AccessController;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.LongAdder;
+
+import sun.misc.JavaLangRefAccess;
+import sun.misc.SharedSecrets;
import sun.misc.Unsafe;
import sun.misc.VM;
@@ -621,55 +626,103 @@
// direct buffer memory. This value may be changed during VM
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
private static volatile long maxMemory = VM.maxDirectMemory();
- private static volatile long reservedMemory;
- private static volatile long totalCapacity;
- private static volatile long count;
- private static boolean memoryLimitSet = false;
+ private static final AtomicLong reservedMemory = new AtomicLong();
+ private static final AtomicLong totalCapacity = new AtomicLong();
+ private static final AtomicLong count = new AtomicLong();
+ private static volatile boolean memoryLimitSet = false;
+ // max. number of sleeps during try-reserving with exponentially
+ // increasing delay before throwing OutOfMemoryError:
+ // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
+ // which means that OOME will be thrown after 0.5 s of trying
+ private static final int MAX_SLEEPS = 9;
// These methods should be called whenever direct memory is allocated or
// freed. They allow the user to control the amount of direct memory
// which a process may access. All sizes are specified in bytes.
static void reserveMemory(long size, int cap) {
- synchronized (Bits.class) {
- if (!memoryLimitSet && VM.isBooted()) {
- maxMemory = VM.maxDirectMemory();
- memoryLimitSet = true;
- }
- // -XX:MaxDirectMemorySize limits the total capacity rather than the
- // actual memory usage, which will differ when buffers are page
- // aligned.
- if (cap <= maxMemory - totalCapacity) {
- reservedMemory += size;
- totalCapacity += cap;
- count++;
+
+ if (!memoryLimitSet && VM.isBooted()) {
+ maxMemory = VM.maxDirectMemory();
+ memoryLimitSet = true;
+ }
+
+ // optimist!
+ if (tryReserveMemory(size, cap)) {
+ return;
+ }
+
+ final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
+
+ // retry while helping enqueue pending Reference objects
+ // which includes executing pending Cleaner(s) which includes
+ // Cleaner(s) that free direct buffer memory
+ while (jlra.tryHandlePendingReference()) {
+ if (tryReserveMemory(size, cap)) {
return;
}
}
+ // trigger VM's Reference processing
System.gc();
- try {
- Thread.sleep(100);
- } catch (InterruptedException x) {
- // Restore interrupt status
- Thread.currentThread().interrupt();
- }
- synchronized (Bits.class) {
- if (totalCapacity + cap > maxMemory)
- throw new OutOfMemoryError("Direct buffer memory");
- reservedMemory += size;
- totalCapacity += cap;
- count++;
- }
+ // a retry loop with exponential back-off delays
+ // (this gives VM some time to do it's job)
+ boolean interrupted = false;
+ try {
+ long sleepTime = 1;
+ int sleeps = 0;
+ while (true) {
+ if (tryReserveMemory(size, cap)) {
+ return;
+ }
+ if (sleeps >= MAX_SLEEPS) {
+ break;
+ }
+ if (!jlra.tryHandlePendingReference()) {
+ try {
+ Thread.sleep(sleepTime);
+ sleepTime <<= 1;
+ sleeps++;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ }
+
+ // no luck
+ throw new OutOfMemoryError("Direct buffer memory");
+
+ } finally {
+ if (interrupted) {
+ // don't swallow interrupts
+ Thread.currentThread().interrupt();
+ }
+ }
}
- static synchronized void unreserveMemory(long size, int cap) {
- if (reservedMemory > 0) {
- reservedMemory -= size;
- totalCapacity -= cap;
- count--;
- assert (reservedMemory > -1);
+ private static boolean tryReserveMemory(long size, int cap) {
+
+ // -XX:MaxDirectMemorySize limits the total capacity rather than the
+ // actual memory usage, which will differ when buffers are page
+ // aligned.
+ long totalCap;
+ while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
+ if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
+ reservedMemory.addAndGet(size);
+ count.incrementAndGet();
+ return true;
+ }
}
+
+ return false;
+ }
+
+
+ static void unreserveMemory(long size, int cap) {
+ long cnt = count.decrementAndGet();
+ long reservedMem = reservedMemory.addAndGet(-size);
+ long totalCap = totalCapacity.addAndGet(-cap);
+ assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
}
// -- Monitoring of direct buffer usage --
@@ -687,15 +740,15 @@
}
@Override
public long getCount() {
- return Bits.count;
+ return Bits.count.get();
}
@Override
public long getTotalCapacity() {
- return Bits.totalCapacity;
+ return Bits.totalCapacity.get();
}
@Override
public long getMemoryUsed() {
- return Bits.reservedMemory;
+ return Bits.reservedMemory.get();
}
};
}
diff --git a/jdk/src/share/classes/java/text/SimpleDateFormat.java b/jdk/src/share/classes/java/text/SimpleDateFormat.java
index 729238b..a5663a4 100644
--- a/jdk/src/share/classes/java/text/SimpleDateFormat.java
+++ b/jdk/src/share/classes/java/text/SimpleDateFormat.java
@@ -1722,7 +1722,7 @@
}
return (start + zoneNames[nameIndex].length());
}
- return 0;
+ return -start;
}
/**
diff --git a/jdk/src/share/classes/java/time/Instant.java b/jdk/src/share/classes/java/time/Instant.java
index 91a177c..9b9efa5 100644
--- a/jdk/src/share/classes/java/time/Instant.java
+++ b/jdk/src/share/classes/java/time/Instant.java
@@ -1229,8 +1229,14 @@
* @throws ArithmeticException if numeric overflow occurs
*/
public long toEpochMilli() {
- long millis = Math.multiplyExact(seconds, 1000);
- return millis + nanos / 1000_000;
+ if (seconds < 0 && nanos > 0) {
+ long millis = Math.multiplyExact(seconds+1, 1000);
+ long adjustment = nanos / 1000_000 - 1000;
+ return Math.addExact(millis, adjustment);
+ } else {
+ long millis = Math.multiplyExact(seconds, 1000);
+ return Math.addExact(millis, nanos / 1000_000);
+ }
}
//-----------------------------------------------------------------------
diff --git a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
index 676421a..5848e94 100644
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDate.java
@@ -715,7 +715,7 @@
* only compares the underlying date and not the chronology.
* This allows dates in different calendar systems to be compared based
* on the time-line position.
- * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}.
+ * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}.
* <p>
* This default implementation performs the comparison based on the epoch-day.
*
@@ -733,7 +733,7 @@
* only compares the underlying date and not the chronology.
* This allows dates in different calendar systems to be compared based
* on the time-line position.
- * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}.
+ * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}.
* <p>
* This default implementation performs the comparison based on the epoch-day.
*
diff --git a/jdk/src/share/classes/java/util/zip/Deflater.java b/jdk/src/share/classes/java/util/zip/Deflater.java
index c4521be..3bb5f99 100644
--- a/jdk/src/share/classes/java/util/zip/Deflater.java
+++ b/jdk/src/share/classes/java/util/zip/Deflater.java
@@ -318,7 +318,9 @@
* should be called in order to provide more input
*/
public boolean needsInput() {
- return len <= 0;
+ synchronized (zsRef) {
+ return len <= 0;
+ }
}
/**
diff --git a/jdk/src/share/classes/java/util/zip/ZStreamRef.java b/jdk/src/share/classes/java/util/zip/ZStreamRef.java
index 980d47f..09b2f30 100644
--- a/jdk/src/share/classes/java/util/zip/ZStreamRef.java
+++ b/jdk/src/share/classes/java/util/zip/ZStreamRef.java
@@ -31,7 +31,7 @@
class ZStreamRef {
- private long address;
+ private volatile long address;
ZStreamRef (long address) {
this.address = address;
}
diff --git a/jdk/src/share/classes/java/util/zip/ZipFile.java b/jdk/src/share/classes/java/util/zip/ZipFile.java
index e6b9f01..adf8057 100644
--- a/jdk/src/share/classes/java/util/zip/ZipFile.java
+++ b/jdk/src/share/classes/java/util/zip/ZipFile.java
@@ -58,7 +58,7 @@
*/
public
class ZipFile implements ZipConstants, Closeable {
- private long jzfile; // address of jzfile data
+ private long jzfile; // address of jzfile data
private final String name; // zip file name
private final int total; // total number of entries
private final boolean locsig; // if zip file starts with LOCSIG (usually true)
@@ -685,7 +685,7 @@
* (possibly compressed) zip file entry.
*/
private class ZipFileInputStream extends InputStream {
- private volatile boolean closeRequested = false;
+ private volatile boolean zfisCloseRequested = false;
protected long jzentry; // address of jzentry data
private long pos; // current position within entry data
protected long rem; // number of remaining bytes within entry
@@ -712,6 +712,7 @@
len = (int) rem;
}
+ // Check if ZipFile open
ensureOpenOrZipException();
len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
off, len);
@@ -755,9 +756,9 @@
}
public void close() {
- if (closeRequested)
+ if (zfisCloseRequested)
return;
- closeRequested = true;
+ zfisCloseRequested = true;
rem = 0;
synchronized (ZipFile.this) {
diff --git a/jdk/src/share/classes/javax/swing/event/ListSelectionEvent.java b/jdk/src/share/classes/javax/swing/event/ListSelectionEvent.java
index 5dee295..22d0bc6 100644
--- a/jdk/src/share/classes/javax/swing/event/ListSelectionEvent.java
+++ b/jdk/src/share/classes/javax/swing/event/ListSelectionEvent.java
@@ -78,7 +78,7 @@
/**
* Returns the index of the first row whose selection may have changed.
- * {@code getFirstIndex() <= getLastIndex()}
+ * {@code getFirstIndex() <= getLastIndex()}
*
* @return the first row whose selection value may have changed,
* where zero is the first row
@@ -87,7 +87,7 @@
/**
* Returns the index of the last row whose selection may have changed.
- * {@code getLastIndex() >= getFirstIndex()}
+ * {@code getLastIndex() >= getFirstIndex()}
*
* @return the last row whose selection value may have changed,
* where zero is the first row
diff --git a/jdk/src/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java b/jdk/src/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java
index 47a737f..3f9bf0f 100644
--- a/jdk/src/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java
+++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/AbstractRegionPainter.java
@@ -625,10 +625,6 @@
// check if we can scale to the requested size
Dimension canvas = ctx.canvasSize;
Insets insets = ctx.stretchingInsets;
- if (insets.left + insets.right > w || insets.top + insets.bottom > h) {
- return;
- }
-
if (w <= (canvas.width * ctx.maxHorizontalScaleFactor) && h <= (canvas.height * ctx.maxVerticalScaleFactor)) {
// get image at canvas size
VolatileImage img = getImage(g.getDeviceConfiguration(), c, canvas.width, canvas.height, extendedCacheKeys);
diff --git a/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf b/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf
index 394721e..208a3b0 100644
--- a/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf
+++ b/jdk/src/share/classes/javax/swing/plaf/nimbus/skin.laf
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1998, 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
@@ -16195,6 +16195,10 @@
<dimension width="150" height="19"/>
</uiProperty>
<uiProperty name="cycleTime" type="INT" value="250"/>
+ <uiProperty name="minBarSize" type="DIMENSION">
+ <dimension width="6" height="6"/>
+ </uiProperty>
+ <uiProperty name="glowWidth" type="INT" value="2"/>
</uiproperties>
</style>
<backgroundStates>
@@ -16351,7 +16355,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16444,7 +16448,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16528,7 +16532,7 @@
<canvas>
<size width="30" height="13"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16619,7 +16623,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16701,7 +16705,7 @@
<canvas>
<size width="27" height="19"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
@@ -16785,7 +16789,7 @@
<canvas>
<size width="30" height="13"/>
<nextLayerNameIndex>2</nextLayerNameIndex>
- <stretchingInsets top="5" bottom="5" left="5" right="5"/>
+ <stretchingInsets top="3" bottom="3" left="3" right="3"/>
<layer name="Layer 1">
<opacity>1.0</opacity>
<fillOpacity>1.0</fillOpacity>
diff --git a/jdk/src/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java b/jdk/src/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java
index c37ce49..f38fea8 100644
--- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java
+++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthProgressBarUI.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -49,6 +49,8 @@
private boolean paintOutsideClip;
private boolean tileWhenIndeterminate; //whether to tile indeterminate painting
private int tileWidth; //the width of each tile
+ private Dimension minBarSize; // minimal visible bar size
+ private int glowWidth; // Glow around the bar foreground
/**
* Creates a new UI object for the given component.
@@ -114,6 +116,8 @@
tileWidth *= 0.784;
}
}
+ minBarSize = (Dimension)style.get(context, "ProgressBar.minBarSize");
+ glowWidth = style.getInt(context, "ProgressBar.glowWidth", 0);
context.dispose();
}
@@ -258,7 +262,7 @@
if (!SynthLookAndFeel.isLeftToRight(pBar)) {
x = pBar.getWidth() - pBarInsets.right - width
- - progressPadding;
+ - progressPadding - glowWidth;
}
} else { // JProgressBar.VERTICAL
x = pBarInsets.left + progressPadding;
@@ -271,9 +275,9 @@
y = pBar.getHeight() - pBarInsets.bottom - height
- progressPadding;
- // When the progress bar is vertical we always paint
- // from bottom to top, not matter what the component
- // orientation is.
+ if (SynthLookAndFeel.isLeftToRight(pBar)) {
+ y -= glowWidth;
+ }
}
}
} else {
@@ -307,8 +311,11 @@
}
g.setClip(clip);
} else {
- context.getPainter().paintProgressBarForeground(context, g,
- x, y, width, height, pBar.getOrientation());
+ if (minBarSize == null || (width >= minBarSize.width
+ && height >= minBarSize.height)) {
+ context.getPainter().paintProgressBarForeground(context, g,
+ x, y, width, height, pBar.getOrientation());
+ }
}
if (pBar.isStringPainted()) {
diff --git a/jdk/src/share/classes/sun/applet/AppletPanel.java b/jdk/src/share/classes/sun/applet/AppletPanel.java
index 618e1bb..a158542 100644
--- a/jdk/src/share/classes/sun/applet/AppletPanel.java
+++ b/jdk/src/share/classes/sun/applet/AppletPanel.java
@@ -682,12 +682,7 @@
if (toFocus != null) {
if (parent instanceof EmbeddedFrame) {
- // JDK-8056915: Try to request focus to the embedder first and
- // activate the embedded frame through it
- if (!((EmbeddedFrame) parent).requestFocusToEmbedder()) {
- // Otherwise activate the embedded frame directly
- ((EmbeddedFrame) parent).synthesizeWindowActivation(true);
- }
+ ((EmbeddedFrame) parent).synthesizeWindowActivation(true);
}
// EmbeddedFrame might have focus before the applet was added.
// Thus after its activation the most recent focus owner will be
diff --git a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
index e214ca6..66b7915 100644
--- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
+++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
@@ -361,15 +361,6 @@
public void synthesizeWindowActivation(boolean doActivate) {}
/**
- * Requests the focus to the embedder.
- *
- * @return {@code true} if focus request was successful, and {@code false} otherwise.
- */
- public boolean requestFocusToEmbedder() {
- return false;
- }
-
- /**
* Moves this embedded frame to a new location. The top-left corner of
* the new location is specified by the <code>x</code> and <code>y</code>
* parameters relative to the native parent component.
diff --git a/jdk/src/share/classes/sun/font/CompositeFont.java b/jdk/src/share/classes/sun/font/CompositeFont.java
index 43b392b..45480ca 100644
--- a/jdk/src/share/classes/sun/font/CompositeFont.java
+++ b/jdk/src/share/classes/sun/font/CompositeFont.java
@@ -71,6 +71,13 @@
} else {
numSlots = componentNames.length;
}
+ /* We will limit the number of slots to 254.
+ * We store the slot for a glyph id in a byte and we may use one slot
+ * for an EUDC font, and we may also create a composite
+ * using this composite as a backup for a physical font.
+ * So we want to leave space for the two additional slots.
+ */
+ numSlots = (numSlots <= 254) ? numSlots : 254;
/* Only the first "numMetricsSlots" slots are used for font metrics.
* the rest are considered "fallback" slots".
diff --git a/jdk/src/share/classes/sun/font/FileFontStrike.java b/jdk/src/share/classes/sun/font/FileFontStrike.java
index f357aea..888be14 100644
--- a/jdk/src/share/classes/sun/font/FileFontStrike.java
+++ b/jdk/src/share/classes/sun/font/FileFontStrike.java
@@ -420,14 +420,13 @@
/* The following method is called from CompositeStrike as a special case.
*/
- private static final int SLOTZEROMAX = 0xffffff;
int getSlot0GlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
int convertedCnt = 0;
for (int i=0; i<len; i++) {
int glyphCode = glyphCodes[i];
- if (glyphCode >= SLOTZEROMAX) {
+ if (glyphCode >>> 24 != 0) {
return convertedCnt;
} else {
convertedCnt++;
diff --git a/jdk/src/share/classes/sun/invoke/util/BytecodeName.java b/jdk/src/share/classes/sun/invoke/util/BytecodeName.java
index 9b8fa35..7df6611 100644
--- a/jdk/src/share/classes/sun/invoke/util/BytecodeName.java
+++ b/jdk/src/share/classes/sun/invoke/util/BytecodeName.java
@@ -295,7 +295,7 @@
* (The safe name might possibly be mangled to hide further dangerous characters.)
* For example, the qualified class name {@code java/lang/String}
* will be parsed into the array {@code {"java", '/', "lang", '/', "String"}}.
- * The name {@code <init>} will be parsed into { '<', "init", '>'}}
+ * The name {@code <init>} will be parsed into {@code {'<', "init", '>'}}.
* The name {@code foo/bar$:baz} will be parsed into
* {@code {"foo", '/', "bar", '$', ':', "baz"}}.
* The name {@code ::\=:foo:\=bar\!baz} will be parsed into
diff --git a/jdk/src/share/classes/sun/management/ThreadImpl.java b/jdk/src/share/classes/sun/management/ThreadImpl.java
index 019646a..9ac9868 100644
--- a/jdk/src/share/classes/sun/management/ThreadImpl.java
+++ b/jdk/src/share/classes/sun/management/ThreadImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -165,6 +165,10 @@
"Invalid maxDepth parameter: " + maxDepth);
}
+ // ids has been verified to be non-null
+ // an empty array of ids should return an empty array of ThreadInfos
+ if (ids.length == 0) return new ThreadInfo[0];
+
Util.checkMonitorAccess();
ThreadInfo[] infos = new ThreadInfo[ids.length]; // nulls
@@ -436,6 +440,10 @@
boolean lockedMonitors,
boolean lockedSynchronizers) {
verifyThreadIds(ids);
+ // ids has been verified to be non-null
+ // an empty array of ids should return an empty array of ThreadInfos
+ if (ids.length == 0) return new ThreadInfo[0];
+
verifyDumpThreads(lockedMonitors, lockedSynchronizers);
return dumpThreads0(ids, lockedMonitors, lockedSynchronizers);
}
diff --git a/jdk/src/share/classes/sun/misc/JavaLangRefAccess.java b/jdk/src/share/classes/sun/misc/JavaLangRefAccess.java
new file mode 100644
index 0000000..e3e2322
--- /dev/null
+++ b/jdk/src/share/classes/sun/misc/JavaLangRefAccess.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+public interface JavaLangRefAccess {
+
+ /**
+ * Help ReferenceHandler thread process next pending
+ * {@link java.lang.ref.Reference}
+ *
+ * @return {@code true} if there was a pending reference and it
+ * was enqueue-ed or {@code false} if there was no
+ * pending reference
+ */
+ boolean tryHandlePendingReference();
+}
diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java
index bc2ab2e..bfb7c5b 100644
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java
@@ -45,6 +45,7 @@
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static JavaUtilJarAccess javaUtilJarAccess;
private static JavaLangAccess javaLangAccess;
+ private static JavaLangRefAccess javaLangRefAccess;
private static JavaIOAccess javaIOAccess;
private static JavaNetAccess javaNetAccess;
private static JavaNetHttpCookieAccess javaNetHttpCookieAccess;
@@ -76,6 +77,14 @@
return javaLangAccess;
}
+ public static void setJavaLangRefAccess(JavaLangRefAccess jlra) {
+ javaLangRefAccess = jlra;
+ }
+
+ public static JavaLangRefAccess getJavaLangRefAccess() {
+ return javaLangRefAccess;
+ }
+
public static void setJavaNetAccess(JavaNetAccess jna) {
javaNetAccess = jna;
}
diff --git a/jdk/src/share/classes/sun/net/util/IPAddressUtil.java b/jdk/src/share/classes/sun/net/util/IPAddressUtil.java
index 4dafa8a..6aa98c8 100644
--- a/jdk/src/share/classes/sun/net/util/IPAddressUtil.java
+++ b/jdk/src/share/classes/sun/net/util/IPAddressUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -44,6 +44,7 @@
long tmpValue = 0;
int currByte = 0;
+ boolean newOctet = true;
int len = src.length();
if (len == 0 || len > 15) {
@@ -77,11 +78,12 @@
for (int i = 0; i < len; i++) {
char c = src.charAt(i);
if (c == '.') {
- if (tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
+ if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
return null;
}
res[currByte++] = (byte) (tmpValue & 0xff);
tmpValue = 0;
+ newOctet = true;
} else {
int digit = Character.digit(c, 10);
if (digit < 0) {
@@ -89,9 +91,10 @@
}
tmpValue *= 10;
tmpValue += digit;
+ newOctet = false;
}
}
- if (tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
+ if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
return null;
}
switch (currByte) {
diff --git a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
index 88ddab4..4921774 100644
--- a/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
+++ b/jdk/src/share/classes/sun/nio/ch/FileChannelImpl.java
@@ -328,6 +328,7 @@
int rv = -1;
long p = -1;
int ti = -1;
+ long rp = -1;
try {
begin();
ti = threads.add();
@@ -363,8 +364,8 @@
if (p > newSize)
p = newSize;
do {
- rv = (int)position0(fd, p);
- } while ((rv == IOStatus.INTERRUPTED) && isOpen());
+ rp = position0(fd, p);
+ } while ((rp == IOStatus.INTERRUPTED) && isOpen());
return this;
} finally {
threads.remove(ti);
diff --git a/jdk/src/share/classes/sun/security/provider/KeyStoreDelegator.java b/jdk/src/share/classes/sun/security/provider/KeyStoreDelegator.java
index 789d448..c8c0fb9 100644
--- a/jdk/src/share/classes/sun/security/provider/KeyStoreDelegator.java
+++ b/jdk/src/share/classes/sun/security/provider/KeyStoreDelegator.java
@@ -216,57 +216,55 @@
} else {
// First try the primary keystore then try the secondary keystore
- try (InputStream bufferedStream = new BufferedInputStream(stream)) {
- bufferedStream.mark(Integer.MAX_VALUE);
+ InputStream bufferedStream = new BufferedInputStream(stream);
+ bufferedStream.mark(Integer.MAX_VALUE);
+ try {
+ keystore = primaryKeyStore.newInstance();
+ type = primaryType;
+ keystore.engineLoad(bufferedStream, password);
+
+ } catch (Exception e) {
+
+ // incorrect password
+ if (e instanceof IOException &&
+ e.getCause() instanceof UnrecoverableKeyException) {
+ throw (IOException)e;
+ }
try {
- keystore = primaryKeyStore.newInstance();
- type = primaryType;
+ keystore = secondaryKeyStore.newInstance();
+ type = secondaryType;
+ bufferedStream.reset();
keystore.engineLoad(bufferedStream, password);
- } catch (Exception e) {
-
- // incorrect password
- if (e instanceof IOException &&
- e.getCause() instanceof UnrecoverableKeyException) {
- throw (IOException)e;
+ if (debug != null) {
+ debug.println("WARNING: switching from " +
+ primaryType + " to " + secondaryType +
+ " keystore file format has altered the " +
+ "keystore security level");
}
- try {
- keystore = secondaryKeyStore.newInstance();
- type = secondaryType;
- bufferedStream.reset();
- keystore.engineLoad(bufferedStream, password);
+ } catch (InstantiationException |
+ IllegalAccessException e2) {
+ // can safely ignore
- if (debug != null) {
- debug.println("WARNING: switching from " +
- primaryType + " to " + secondaryType +
- " keystore file format has altered the " +
- "keystore security level");
- }
+ } catch (IOException |
+ NoSuchAlgorithmException |
+ CertificateException e3) {
- } catch (InstantiationException |
- IllegalAccessException e2) {
- // can safely ignore
-
- } catch (IOException |
- NoSuchAlgorithmException |
- CertificateException e3) {
-
- // incorrect password
- if (e3 instanceof IOException &&
- e3.getCause() instanceof
- UnrecoverableKeyException) {
- throw (IOException)e3;
- }
- // rethrow the outer exception
- if (e instanceof IOException) {
- throw (IOException)e;
- } else if (e instanceof CertificateException) {
- throw (CertificateException)e;
- } else if (e instanceof NoSuchAlgorithmException) {
- throw (NoSuchAlgorithmException)e;
- }
+ // incorrect password
+ if (e3 instanceof IOException &&
+ e3.getCause() instanceof
+ UnrecoverableKeyException) {
+ throw (IOException)e3;
+ }
+ // rethrow the outer exception
+ if (e instanceof IOException) {
+ throw (IOException)e;
+ } else if (e instanceof CertificateException) {
+ throw (CertificateException)e;
+ } else if (e instanceof NoSuchAlgorithmException) {
+ throw (NoSuchAlgorithmException)e;
}
}
}
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/Builder.java b/jdk/src/share/classes/sun/security/provider/certpath/Builder.java
index 84cbe66..e6b5fc0 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/Builder.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/Builder.java
@@ -102,8 +102,8 @@
/**
* Verifies whether the input certificate completes the path.
- * When building forward, a trust anchor will complete the path.
- * When building reverse, the target certificate will complete the path.
+ * When building in the forward direction, a trust anchor will
+ * complete the path.
*
* @param cert the certificate to test
* @return a boolean value indicating whether the cert completes the path.
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/PKIX.java b/jdk/src/share/classes/sun/security/provider/certpath/PKIX.java
index 98c8834..e33d4a2 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/PKIX.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/PKIX.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -25,7 +25,6 @@
package sun.security.provider.certpath;
import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
import java.security.PublicKey;
import java.security.cert.*;
import java.security.interfaces.DSAPublicKey;
@@ -194,7 +193,6 @@
static class BuilderParams extends ValidatorParams {
private PKIXBuilderParameters params;
- private boolean buildForward = true;
private List<CertStore> stores;
private X500Principal targetSubject;
@@ -213,10 +211,6 @@
+ "targetCertConstraints parameter must be an "
+ "X509CertSelector");
}
- if (params instanceof SunCertPathBuilderParameters) {
- buildForward =
- ((SunCertPathBuilderParameters)params).getBuildForward();
- }
this.params = params;
this.targetSubject = getTargetSubject(
certStores(), (X509CertSelector)targetCertConstraints());
@@ -230,7 +224,6 @@
return stores;
}
int maxPathLength() { return params.getMaxPathLength(); }
- boolean buildForward() { return buildForward; }
PKIXBuilderParameters params() { return params; }
X500Principal targetSubject() { return targetSubject; }
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java b/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java
deleted file mode 100644
index a70945d..0000000
--- a/jdk/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, 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.provider.certpath;
-
-import java.io.IOException;
-import java.security.GeneralSecurityException;
-import java.security.Principal;
-import java.security.cert.CertificateException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.PKIXBuilderParameters;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXParameters;
-import java.security.cert.PKIXReason;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.cert.X509CertSelector;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Set;
-
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.provider.certpath.PKIX.BuilderParams;
-import sun.security.util.Debug;
-import sun.security.x509.Extension;
-import static sun.security.x509.PKIXExtensions.*;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.PolicyMappingsExtension;
-
-/**
- * This class represents a reverse builder, which is able to retrieve
- * matching certificates from CertStores and verify a particular certificate
- * against a ReverseState.
- *
- * @since 1.4
- * @author Sean Mullan
- * @author Yassir Elley
- */
-
-class ReverseBuilder extends Builder {
-
- private Debug debug = Debug.getInstance("certpath");
-
- private final Set<String> initPolicies;
-
- /**
- * Initialize the builder with the input parameters.
- *
- * @param params the parameter set used to build a certification path
- */
- ReverseBuilder(BuilderParams buildParams) {
- super(buildParams);
-
- Set<String> initialPolicies = buildParams.initialPolicies();
- initPolicies = new HashSet<String>();
- if (initialPolicies.isEmpty()) {
- // if no initialPolicies are specified by user, set
- // initPolicies to be anyPolicy by default
- initPolicies.add(PolicyChecker.ANY_POLICY);
- } else {
- initPolicies.addAll(initialPolicies);
- }
- }
-
- /**
- * Retrieves all certs from the specified CertStores that satisfy the
- * requirements specified in the parameters and the current
- * PKIX state (name constraints, policy constraints, etc).
- *
- * @param currentState the current state.
- * Must be an instance of <code>ReverseState</code>
- * @param certStores list of CertStores
- */
- @Override
- Collection<X509Certificate> getMatchingCerts
- (State currState, List<CertStore> certStores)
- throws CertStoreException, CertificateException, IOException
- {
- ReverseState currentState = (ReverseState) currState;
-
- if (debug != null)
- debug.println("In ReverseBuilder.getMatchingCerts.");
-
- /*
- * The last certificate could be an EE or a CA certificate
- * (we may be building a partial certification path or
- * establishing trust in a CA).
- *
- * Try the EE certs before the CA certs. It will be more
- * common to build a path to an end entity.
- */
- Collection<X509Certificate> certs =
- getMatchingEECerts(currentState, certStores);
- certs.addAll(getMatchingCACerts(currentState, certStores));
-
- return certs;
- }
-
- /*
- * Retrieves all end-entity certificates which satisfy constraints
- * and requirements specified in the parameters and PKIX state.
- */
- private Collection<X509Certificate> getMatchingEECerts
- (ReverseState currentState, List<CertStore> certStores)
- throws CertStoreException, CertificateException, IOException {
-
- /*
- * Compose a CertSelector to filter out
- * certs which do not satisfy requirements.
- *
- * First, retrieve clone of current target cert constraints, and
- * then add more selection criteria based on current validation state.
- */
- X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();
-
- /*
- * Match on issuer (subject of previous cert)
- */
- sel.setIssuer(currentState.subjectDN);
-
- /*
- * Match on certificate validity date.
- */
- sel.setCertificateValid(buildParams.date());
-
- /*
- * Policy processing optimizations
- */
- if (currentState.explicitPolicy == 0)
- sel.setPolicy(getMatchingPolicies());
-
- /*
- * If previous cert has a subject key identifier extension,
- * use it to match on authority key identifier extension.
- */
- /*if (currentState.subjKeyId != null) {
- AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
- (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
- null, null);
- sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
- }*/
-
- /*
- * Require EE certs
- */
- sel.setBasicConstraints(-2);
-
- /* Retrieve matching certs from CertStores */
- HashSet<X509Certificate> eeCerts = new HashSet<>();
- addMatchingCerts(sel, certStores, eeCerts, true);
-
- if (debug != null) {
- debug.println("ReverseBuilder.getMatchingEECerts got "
- + eeCerts.size() + " certs.");
- }
- return eeCerts;
- }
-
- /*
- * Retrieves all CA certificates which satisfy constraints
- * and requirements specified in the parameters and PKIX state.
- */
- private Collection<X509Certificate> getMatchingCACerts
- (ReverseState currentState, List<CertStore> certStores)
- throws CertificateException, CertStoreException, IOException {
-
- /*
- * Compose a CertSelector to filter out
- * certs which do not satisfy requirements.
- */
- X509CertSelector sel = new X509CertSelector();
-
- /*
- * Match on issuer (subject of previous cert)
- */
- sel.setIssuer(currentState.subjectDN);
-
- /*
- * Match on certificate validity date.
- */
- sel.setCertificateValid(buildParams.date());
-
- /*
- * Match on target subject name (checks that current cert's
- * name constraints permit it to certify target).
- * (4 is the integer type for DIRECTORY name).
- */
- byte[] subject = targetCertConstraints.getSubjectAsBytes();
- if (subject != null) {
- sel.addPathToName(4, subject);
- } else {
- X509Certificate cert = targetCertConstraints.getCertificate();
- if (cert != null) {
- sel.addPathToName(4,
- cert.getSubjectX500Principal().getEncoded());
- }
- }
-
- /*
- * Policy processing optimizations
- */
- if (currentState.explicitPolicy == 0)
- sel.setPolicy(getMatchingPolicies());
-
- /*
- * If previous cert has a subject key identifier extension,
- * use it to match on authority key identifier extension.
- */
- /*if (currentState.subjKeyId != null) {
- AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
- (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
- null, null);
- sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
- }*/
-
- /*
- * Require CA certs
- */
- sel.setBasicConstraints(0);
-
- /* Retrieve matching certs from CertStores */
- ArrayList<X509Certificate> reverseCerts = new ArrayList<>();
- addMatchingCerts(sel, certStores, reverseCerts, true);
-
- /* Sort remaining certs using name constraints */
- Collections.sort(reverseCerts, new PKIXCertComparator());
-
- if (debug != null)
- debug.println("ReverseBuilder.getMatchingCACerts got " +
- reverseCerts.size() + " certs.");
- return reverseCerts;
- }
-
- /*
- * This inner class compares 2 PKIX certificates according to which
- * should be tried first when building a path to the target. For
- * now, the algorithm is to look at name constraints in each cert and those
- * which constrain the path closer to the target should be
- * ranked higher. Later, we may want to consider other components,
- * such as key identifiers.
- */
- class PKIXCertComparator implements Comparator<X509Certificate> {
-
- private Debug debug = Debug.getInstance("certpath");
-
- @Override
- public int compare(X509Certificate cert1, X509Certificate cert2) {
-
- /*
- * if either cert certifies the target, always
- * put at head of list.
- */
- X500Principal targetSubject = buildParams.targetSubject();
- if (cert1.getSubjectX500Principal().equals(targetSubject)) {
- return -1;
- }
- if (cert2.getSubjectX500Principal().equals(targetSubject)) {
- return 1;
- }
-
- int targetDist1;
- int targetDist2;
- try {
- X500Name targetSubjectName = X500Name.asX500Name(targetSubject);
- targetDist1 = Builder.targetDistance(
- null, cert1, targetSubjectName);
- targetDist2 = Builder.targetDistance(
- null, cert2, targetSubjectName);
- } catch (IOException e) {
- if (debug != null) {
- debug.println("IOException in call to Builder.targetDistance");
- e.printStackTrace();
- }
- throw new ClassCastException
- ("Invalid target subject distinguished name");
- }
-
- if (targetDist1 == targetDist2)
- return 0;
-
- if (targetDist1 == -1)
- return 1;
-
- if (targetDist1 < targetDist2)
- return -1;
-
- return 1;
- }
- }
-
- /**
- * Verifies a matching certificate.
- *
- * This method executes any of the validation steps in the PKIX path validation
- * algorithm which were not satisfied via filtering out non-compliant
- * certificates with certificate matching rules.
- *
- * If the last certificate is being verified (the one whose subject
- * matches the target subject, then the steps in Section 6.1.4 of the
- * Certification Path Validation algorithm are NOT executed,
- * regardless of whether or not the last cert is an end-entity
- * cert or not. This allows callers to certify CA certs as
- * well as EE certs.
- *
- * @param cert the certificate to be verified
- * @param currentState the current state against which the cert is verified
- * @param certPathList the certPathList generated thus far
- */
- @Override
- void verifyCert(X509Certificate cert, State currState,
- List<X509Certificate> certPathList)
- throws GeneralSecurityException
- {
- if (debug != null) {
- debug.println("ReverseBuilder.verifyCert(SN: "
- + Debug.toHexString(cert.getSerialNumber())
- + "\n Subject: " + cert.getSubjectX500Principal() + ")");
- }
-
- ReverseState currentState = (ReverseState) currState;
-
- /* we don't perform any validation of the trusted cert */
- if (currentState.isInitial()) {
- return;
- }
-
- // Don't bother to verify untrusted certificate more.
- currentState.untrustedChecker.check(cert,
- Collections.<String>emptySet());
-
- /*
- * check for looping - abort a loop if
- * ((we encounter the same certificate twice) AND
- * ((policyMappingInhibited = true) OR (no policy mapping
- * extensions can be found between the occurrences of the same
- * certificate)))
- * in order to facilitate the check to see if there are
- * any policy mapping extensions found between the occurrences
- * of the same certificate, we reverse the certpathlist first
- */
- if ((certPathList != null) && (!certPathList.isEmpty())) {
- List<X509Certificate> reverseCertList = new ArrayList<>();
- for (X509Certificate c : certPathList) {
- reverseCertList.add(0, c);
- }
-
- boolean policyMappingFound = false;
- for (X509Certificate cpListCert : reverseCertList) {
- X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
- PolicyMappingsExtension policyMappingsExt =
- cpListCertImpl.getPolicyMappingsExtension();
- if (policyMappingsExt != null) {
- policyMappingFound = true;
- }
- if (debug != null)
- debug.println("policyMappingFound = " + policyMappingFound);
- if (cert.equals(cpListCert)) {
- if ((buildParams.policyMappingInhibited()) ||
- (!policyMappingFound)){
- if (debug != null)
- debug.println("loop detected!!");
- throw new CertPathValidatorException("loop detected");
- }
- }
- }
- }
-
- /* check if target cert */
- boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject());
-
- /* check if CA cert */
- boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);
-
- /* if there are more certs to follow, verify certain constraints */
- if (!finalCert) {
-
- /* check if CA cert */
- if (!caCert)
- throw new CertPathValidatorException("cert is NOT a CA cert");
-
- /* If the certificate was not self-issued, verify that
- * remainingCerts is greater than zero
- */
- if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {
- throw new CertPathValidatorException
- ("pathLenConstraint violated, path too long", null,
- null, -1, PKIXReason.PATH_TOO_LONG);
- }
-
- /*
- * Check keyUsage extension (only if CA cert and not final cert)
- */
- KeyChecker.verifyCAKeyUsage(cert);
-
- } else {
-
- /*
- * If final cert, check that it satisfies specified target
- * constraints
- */
- if (targetCertConstraints.match(cert) == false) {
- throw new CertPathValidatorException("target certificate " +
- "constraints check failed");
- }
- }
-
- /*
- * Check revocation.
- */
- if (buildParams.revocationEnabled() && currentState.revChecker != null) {
- currentState.revChecker.check(cert, Collections.<String>emptySet());
- }
-
- /* Check name constraints if this is not a self-issued cert */
- if (finalCert || !X509CertImpl.isSelfIssued(cert)){
- if (currentState.nc != null) {
- try {
- if (!currentState.nc.verify(cert)){
- throw new CertPathValidatorException
- ("name constraints check failed", null, null, -1,
- PKIXReason.INVALID_NAME);
- }
- } catch (IOException ioe) {
- throw new CertPathValidatorException(ioe);
- }
- }
- }
-
- /*
- * Check policy
- */
- X509CertImpl certImpl = X509CertImpl.toImpl(cert);
- currentState.rootNode = PolicyChecker.processPolicies
- (currentState.certIndex, initPolicies,
- currentState.explicitPolicy, currentState.policyMapping,
- currentState.inhibitAnyPolicy,
- buildParams.policyQualifiersRejected(), currentState.rootNode,
- certImpl, finalCert);
-
- /*
- * Check CRITICAL private extensions
- */
- Set<String> unresolvedCritExts = cert.getCriticalExtensionOIDs();
- if (unresolvedCritExts == null) {
- unresolvedCritExts = Collections.<String>emptySet();
- }
-
- /*
- * Check that the signature algorithm is not disabled.
- */
- currentState.algorithmChecker.check(cert, unresolvedCritExts);
-
- for (PKIXCertPathChecker checker : currentState.userCheckers) {
- checker.check(cert, unresolvedCritExts);
- }
-
- /*
- * Look at the remaining extensions and remove any ones we have
- * already checked. If there are any left, throw an exception!
- */
- if (!unresolvedCritExts.isEmpty()) {
- unresolvedCritExts.remove(BasicConstraints_Id.toString());
- unresolvedCritExts.remove(NameConstraints_Id.toString());
- unresolvedCritExts.remove(CertificatePolicies_Id.toString());
- unresolvedCritExts.remove(PolicyMappings_Id.toString());
- unresolvedCritExts.remove(PolicyConstraints_Id.toString());
- unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString());
- unresolvedCritExts.remove(SubjectAlternativeName_Id.toString());
- unresolvedCritExts.remove(KeyUsage_Id.toString());
- unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString());
-
- if (!unresolvedCritExts.isEmpty())
- throw new CertPathValidatorException
- ("Unrecognized critical extension(s)", null, null, -1,
- PKIXReason.UNRECOGNIZED_CRIT_EXT);
- }
-
- /*
- * Check signature.
- */
- if (buildParams.sigProvider() != null) {
- cert.verify(currentState.pubKey, buildParams.sigProvider());
- } else {
- cert.verify(currentState.pubKey);
- }
- }
-
- /**
- * Verifies whether the input certificate completes the path.
- * This checks whether the cert is the target certificate.
- *
- * @param cert the certificate to test
- * @return a boolean value indicating whether the cert completes the path.
- */
- @Override
- boolean isPathCompleted(X509Certificate cert) {
- return cert.getSubjectX500Principal().equals(buildParams.targetSubject());
- }
-
- /** Adds the certificate to the certPathList
- *
- * @param cert the certificate to be added
- * @param certPathList the certification path list
- */
- @Override
- void addCertToPath(X509Certificate cert,
- LinkedList<X509Certificate> certPathList) {
- certPathList.addLast(cert);
- }
-
- /** Removes final certificate from the certPathList
- *
- * @param certPathList the certification path list
- */
- @Override
- void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
- certPathList.removeLast();
- }
-}
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/ReverseState.java b/jdk/src/share/classes/sun/security/provider/certpath/ReverseState.java
deleted file mode 100644
index c515003..0000000
--- a/jdk/src/share/classes/sun/security/provider/certpath/ReverseState.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, 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.provider.certpath;
-
-import java.io.IOException;
-import java.security.PublicKey;
-import java.security.cert.CertificateException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXRevocationChecker;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.provider.certpath.PKIX.BuilderParams;
-import sun.security.util.Debug;
-import sun.security.x509.NameConstraintsExtension;
-import sun.security.x509.SubjectKeyIdentifierExtension;
-import sun.security.x509.X509CertImpl;
-
-/**
- * A specification of a reverse PKIX validation state
- * which is initialized by each build and updated each time a
- * certificate is added to the current path.
- * @since 1.4
- * @author Sean Mullan
- * @author Yassir Elley
- */
-
-class ReverseState implements State {
-
- private static final Debug debug = Debug.getInstance("certpath");
-
- /* The subject DN of the last cert in the path */
- X500Principal subjectDN;
-
- /* The subject public key of the last cert */
- PublicKey pubKey;
-
- /* The subject key identifier extension (if any) of the last cert */
- SubjectKeyIdentifierExtension subjKeyId;
-
- /* The PKIX constrained/excluded subtrees state variable */
- NameConstraintsExtension nc;
-
- /* The PKIX explicit policy, policy mapping, and inhibit_any-policy
- state variables */
- int explicitPolicy;
- int policyMapping;
- int inhibitAnyPolicy;
- int certIndex;
- PolicyNodeImpl rootNode;
-
- /* The number of remaining CA certs which may follow in the path.
- * -1: previous cert was an EE cert
- * 0: only EE certs may follow.
- * >0 and <Integer.MAX_VALUE:no more than this number of CA certs may follow
- * Integer.MAX_VALUE: unlimited
- */
- int remainingCACerts;
-
- /* The list of user-defined checkers retrieved from the PKIXParameters
- * instance */
- ArrayList<PKIXCertPathChecker> userCheckers;
-
- /* Flag indicating if state is initial (path is just starting) */
- private boolean init = true;
-
- /* the checker used for revocation status */
- RevocationChecker revChecker;
-
- /* the algorithm checker */
- AlgorithmChecker algorithmChecker;
-
- /* the untrusted certificates checker */
- UntrustedChecker untrustedChecker;
-
- /* the trust anchor used to validate the path */
- TrustAnchor trustAnchor;
-
- /* Flag indicating if current cert can vouch for the CRL for
- * the next cert
- */
- boolean crlSign = true;
-
- /**
- * Returns a boolean flag indicating if the state is initial
- * (just starting)
- *
- * @return boolean flag indicating if the state is initial (just starting)
- */
- @Override
- public boolean isInitial() {
- return init;
- }
-
- /**
- * Display state for debugging purposes
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("State [");
- sb.append("\n subjectDN of last cert: ").append(subjectDN);
- sb.append("\n subjectKeyIdentifier: ").append
- (String.valueOf(subjKeyId));
- sb.append("\n nameConstraints: ").append(String.valueOf(nc));
- sb.append("\n certIndex: ").append(certIndex);
- sb.append("\n explicitPolicy: ").append(explicitPolicy);
- sb.append("\n policyMapping: ").append(policyMapping);
- sb.append("\n inhibitAnyPolicy: ").append(inhibitAnyPolicy);
- sb.append("\n rootNode: ").append(rootNode);
- sb.append("\n remainingCACerts: ").append(remainingCACerts);
- sb.append("\n crlSign: ").append(crlSign);
- sb.append("\n init: ").append(init);
- sb.append("\n]\n");
- return sb.toString();
- }
-
- /**
- * Initialize the state.
- *
- * @param buildParams builder parameters
- */
- public void initState(BuilderParams buildParams)
- throws CertPathValidatorException
- {
- /*
- * Initialize number of remainingCACerts.
- * Note that -1 maxPathLen implies unlimited.
- * 0 implies only an EE cert is acceptable.
- */
- int maxPathLen = buildParams.maxPathLength();
- remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE
- : maxPathLen;
-
- /* Initialize explicit policy state variable */
- if (buildParams.explicitPolicyRequired()) {
- explicitPolicy = 0;
- } else {
- // unconstrained if maxPathLen is -1,
- // otherwise, we want to initialize this to the value of the
- // longest possible path + 1 (i.e. maxpathlen + finalcert + 1)
- explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
- }
-
- /* Initialize policy mapping state variable */
- if (buildParams.policyMappingInhibited()) {
- policyMapping = 0;
- } else {
- policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
- }
-
- /* Initialize inhibit any policy state variable */
- if (buildParams.anyPolicyInhibited()) {
- inhibitAnyPolicy = 0;
- } else {
- inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
- }
-
- /* Initialize certIndex */
- certIndex = 1;
-
- /* Initialize policy tree */
- Set<String> initExpPolSet = new HashSet<>(1);
- initExpPolSet.add(PolicyChecker.ANY_POLICY);
-
- rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null,
- false, initExpPolSet, false);
-
- /*
- * Initialize each user-defined checker
- * Shallow copy the checkers
- */
- userCheckers = new ArrayList<>(buildParams.certPathCheckers());
- /* initialize each checker (just in case) */
- for (PKIXCertPathChecker checker : userCheckers) {
- checker.init(false);
- }
-
- /* Start by trusting the cert to sign CRLs */
- crlSign = true;
-
- init = true;
- }
-
- /**
- * Update the state with the specified trust anchor.
- *
- * @param anchor the most-trusted CA
- * @param buildParams builder parameters
- */
- public void updateState(TrustAnchor anchor, BuilderParams buildParams)
- throws CertificateException, IOException, CertPathValidatorException
- {
- trustAnchor = anchor;
- X509Certificate trustedCert = anchor.getTrustedCert();
- if (trustedCert != null) {
- updateState(trustedCert);
- } else {
- X500Principal caName = anchor.getCA();
- updateState(anchor.getCAPublicKey(), caName);
- }
-
- // The user specified AlgorithmChecker and RevocationChecker may not be
- // able to set the trust anchor until now.
- boolean revCheckerAdded = false;
- for (PKIXCertPathChecker checker : userCheckers) {
- if (checker instanceof AlgorithmChecker) {
- ((AlgorithmChecker)checker).trySetTrustAnchor(anchor);
- } else if (checker instanceof PKIXRevocationChecker) {
- if (revCheckerAdded) {
- throw new CertPathValidatorException(
- "Only one PKIXRevocationChecker can be specified");
- }
- // if it's our own, initialize it
- if (checker instanceof RevocationChecker) {
- ((RevocationChecker)checker).init(anchor, buildParams);
- }
- ((PKIXRevocationChecker)checker).init(false);
- revCheckerAdded = true;
- }
- }
-
- // only create a RevocationChecker if revocation is enabled and
- // a PKIXRevocationChecker has not already been added
- if (buildParams.revocationEnabled() && !revCheckerAdded) {
- revChecker = new RevocationChecker(anchor, buildParams);
- revChecker.init(false);
- }
-
- init = false;
- }
-
- /**
- * Update the state. This method is used when the most-trusted CA is
- * a trusted public-key and caName, instead of a trusted cert.
- *
- * @param pubKey the public key of the trusted CA
- * @param subjectDN the subject distinguished name of the trusted CA
- */
- private void updateState(PublicKey pubKey, X500Principal subjectDN) {
-
- /* update subject DN */
- this.subjectDN = subjectDN;
-
- /* update subject public key */
- this.pubKey = pubKey;
- }
-
- /**
- * Update the state with the next certificate added to the path.
- *
- * @param cert the certificate which is used to update the state
- */
- public void updateState(X509Certificate cert)
- throws CertificateException, IOException, CertPathValidatorException {
-
- if (cert == null) {
- return;
- }
-
- /* update subject DN */
- subjectDN = cert.getSubjectX500Principal();
-
- /* check for key needing to inherit alg parameters */
- X509CertImpl icert = X509CertImpl.toImpl(cert);
- PublicKey newKey = cert.getPublicKey();
- if (PKIX.isDSAPublicKeyWithoutParams(newKey)) {
- newKey = BasicChecker.makeInheritedParamsKey(newKey, pubKey);
- }
-
- /* update subject public key */
- pubKey = newKey;
-
- /*
- * if this is a trusted cert (init == true), then we
- * don't update any of the remaining fields
- */
- if (init) {
- init = false;
- return;
- }
-
- /* update subject key identifier */
- subjKeyId = icert.getSubjectKeyIdentifierExtension();
-
- /* update crlSign */
- crlSign = RevocationChecker.certCanSignCrl(cert);
-
- /* update current name constraints */
- if (nc != null) {
- nc.merge(icert.getNameConstraintsExtension());
- } else {
- nc = icert.getNameConstraintsExtension();
- if (nc != null) {
- // Make sure we do a clone here, because we're probably
- // going to modify this object later and we don't want to
- // be sharing it with a Certificate object!
- nc = (NameConstraintsExtension) nc.clone();
- }
- }
-
- /* update policy state variables */
- explicitPolicy =
- PolicyChecker.mergeExplicitPolicy(explicitPolicy, icert, false);
- policyMapping =
- PolicyChecker.mergePolicyMapping(policyMapping, icert);
- inhibitAnyPolicy =
- PolicyChecker.mergeInhibitAnyPolicy(inhibitAnyPolicy, icert);
- certIndex++;
-
- /*
- * Update remaining CA certs
- */
- remainingCACerts =
- ConstraintsChecker.mergeBasicConstraints(cert, remainingCACerts);
-
- init = false;
- }
-
- /**
- * Returns a boolean flag indicating if a key lacking necessary key
- * algorithm parameters has been encountered.
- *
- * @return boolean flag indicating if key lacking parameters encountered.
- */
- @Override
- public boolean keyParamsNeeded() {
- /* when building in reverse, we immediately get parameters needed
- * or else throw an exception
- */
- return false;
- }
-
- /*
- * Clone current state. The state is cloned as each cert is
- * added to the path. This is necessary if backtracking occurs,
- * and a prior state needs to be restored.
- *
- * Note that this is a SMART clone. Not all fields are fully copied,
- * because some of them (e.g., subjKeyId) will
- * not have their contents modified by subsequent calls to updateState.
- */
- @Override
- @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
- public Object clone() {
- try {
- ReverseState clonedState = (ReverseState) super.clone();
-
- /* clone checkers, if cloneable */
- clonedState.userCheckers =
- (ArrayList<PKIXCertPathChecker>)userCheckers.clone();
- ListIterator<PKIXCertPathChecker> li =
- clonedState.userCheckers.listIterator();
- while (li.hasNext()) {
- PKIXCertPathChecker checker = li.next();
- if (checker instanceof Cloneable) {
- li.set((PKIXCertPathChecker)checker.clone());
- }
- }
-
- /* make copy of name constraints */
- if (nc != null) {
- clonedState.nc = (NameConstraintsExtension) nc.clone();
- }
-
- /* make copy of policy tree */
- if (rootNode != null) {
- clonedState.rootNode = rootNode.copyTree();
- }
-
- return clonedState;
- } catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString(), e);
- }
- }
-}
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
index 3f802e2..3e6155c 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java
@@ -35,8 +35,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Set;
@@ -47,8 +45,7 @@
import sun.security.util.Debug;
/**
- * This class is able to build certification paths in either the forward
- * or reverse directions.
+ * This class builds certification paths in the forward direction.
*
* <p> If successful, it returns a certification path which has successfully
* satisfied all the constraints and requirements specified in the
@@ -102,10 +99,8 @@
/**
* Attempts to build a certification path using the Sun build
* algorithm from a trusted anchor(s) to a target subject, which must both
- * be specified in the input parameter set. By default, this method will
- * attempt to build in the forward direction. In order to build in the
- * reverse direction, the caller needs to pass in an instance of
- * SunCertPathBuilderParameters with the buildForward flag set to false.
+ * be specified in the input parameter set. This method will
+ * attempt to build in the forward direction: from the target to the CA.
*
* <p>The certification path that is constructed is validated
* according to the PKIX specification.
@@ -162,11 +157,7 @@
policyTreeResult = null;
LinkedList<X509Certificate> certPathList = new LinkedList<>();
try {
- if (buildParams.buildForward()) {
- buildForward(adjList, certPathList, searchAllCertStores);
- } else {
- buildReverse(adjList, certPathList);
- }
+ buildForward(adjList, certPathList, searchAllCertStores);
} catch (GeneralSecurityException | IOException e) {
if (debug != null) {
debug.println("SunCertPathBuilder.engineBuild() exception in "
@@ -210,81 +201,6 @@
}
/*
- * Private build reverse method.
- */
- private void buildReverse(List<List<Vertex>> adjacencyList,
- LinkedList<X509Certificate> certPathList)
- throws GeneralSecurityException, IOException
- {
- if (debug != null) {
- debug.println("SunCertPathBuilder.buildReverse()...");
- debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
- + buildParams.initialPolicies());
- }
-
- ReverseState currentState = new ReverseState();
- /* Initialize adjacency list */
- adjacencyList.clear();
- adjacencyList.add(new LinkedList<Vertex>());
-
- /*
- * Perform a search using each trust anchor, until a valid
- * path is found
- */
- Iterator<TrustAnchor> iter = buildParams.trustAnchors().iterator();
- while (iter.hasNext()) {
- TrustAnchor anchor = iter.next();
-
- /* check if anchor satisfies target constraints */
- if (anchorIsTarget(anchor, buildParams.targetCertConstraints())) {
- this.trustAnchor = anchor;
- this.pathCompleted = true;
- this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
- break;
- }
-
- // skip anchor if it contains a DSA key with no DSA params
- X509Certificate trustedCert = anchor.getTrustedCert();
- PublicKey pubKey = trustedCert != null ? trustedCert.getPublicKey()
- : anchor.getCAPublicKey();
-
- if (PKIX.isDSAPublicKeyWithoutParams(pubKey)) {
- continue;
- }
-
- /* Initialize current state */
- currentState.initState(buildParams);
- currentState.updateState(anchor, buildParams);
-
- currentState.algorithmChecker = new AlgorithmChecker(anchor);
- currentState.untrustedChecker = new UntrustedChecker();
- try {
- depthFirstSearchReverse(null, currentState,
- new ReverseBuilder(buildParams),
- adjacencyList, certPathList);
- } catch (GeneralSecurityException | IOException e) {
- // continue on error if more anchors to try
- if (iter.hasNext())
- continue;
- else
- throw e;
- }
-
- // break out of loop if search is successful
- if (pathCompleted) {
- break;
- }
- }
-
- if (debug != null) {
- debug.println("SunCertPathBuilder.buildReverse() returned from "
- + "depthFirstSearchReverse()");
- debug.println("SunCertPathBuilder.buildReverse() "
- + "certPathList.size: " + certPathList.size());
- }
- }
-
- /*
* Private build forward method.
*/
private void buildForward(List<List<Vertex>> adjacencyList,
@@ -632,147 +548,6 @@
}
/*
- * This method performs a depth first search for a certification
- * path while building reverse which meets the requirements set in
- * the parameters object.
- * It uses an adjacency list to store all certificates which were
- * tried (i.e. at one time added to the path - they may not end up in
- * the final path if backtracking occurs). This information can
- * be used later to debug or demo the build.
- *
- * See "Data Structure and Algorithms, by Aho, Hopcroft, and Ullman"
- * for an explanation of the DFS algorithm.
- *
- * @param dN the distinguished name being currently searched for certs
- * @param currentState the current PKIX validation state
- */
- private void depthFirstSearchReverse(X500Principal dN,
- ReverseState currentState,
- ReverseBuilder builder,
- List<List<Vertex>> adjList,
- LinkedList<X509Certificate> cpList)
- throws GeneralSecurityException, IOException
- {
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse(" + dN
- + ", " + currentState.toString() + ")");
-
- /*
- * Find all the certificates issued by dN which
- * satisfy the PKIX certification path constraints.
- */
- Collection<X509Certificate> certs =
- builder.getMatchingCerts(currentState, buildParams.certStores());
- List<Vertex> vertices = addVertices(certs, adjList);
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
- + "certs.size=" + vertices.size());
-
- /*
- * For each cert in the collection, verify anything
- * that hasn't been checked yet (signature, revocation, etc)
- * and check for loops. Call depthFirstSearchReverse()
- * recursively for each good cert.
- */
- for (Vertex vertex : vertices) {
- /**
- * Restore state to currentState each time through the loop.
- * This is important because some of the user-defined
- * checkers modify the state, which MUST be restored if
- * the cert eventually fails to lead to the target and
- * the next matching cert is tried.
- */
- ReverseState nextState = (ReverseState) currentState.clone();
- X509Certificate cert = vertex.getCertificate();
- try {
- builder.verifyCert(cert, nextState, cpList);
- } catch (GeneralSecurityException gse) {
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
- + ": validation failed: " + gse);
- vertex.setThrowable(gse);
- continue;
- }
-
- /*
- * Certificate is good, add it to the path (if it isn't a
- * self-signed cert) and update state
- */
- if (!currentState.isInitial())
- builder.addCertToPath(cert, cpList);
- // save trust anchor
- this.trustAnchor = currentState.trustAnchor;
-
- /*
- * Check if path is completed, return ASAP if so.
- */
- if (builder.isPathCompleted(cert)) {
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
- + ": path completed!");
- pathCompleted = true;
-
- PolicyNodeImpl rootNode = nextState.rootNode;
-
- if (rootNode == null)
- policyTreeResult = null;
- else {
- policyTreeResult = rootNode.copyTree();
- ((PolicyNodeImpl)policyTreeResult).setImmutable();
- }
-
- /*
- * Extract and save the final target public key
- */
- finalPublicKey = cert.getPublicKey();
- if (PKIX.isDSAPublicKeyWithoutParams(finalPublicKey)) {
- finalPublicKey =
- BasicChecker.makeInheritedParamsKey
- (finalPublicKey, currentState.pubKey);
- }
-
- return;
- }
-
- /* Update the PKIX state */
- nextState.updateState(cert);
-
- /*
- * Append an entry for cert in adjacency list and
- * set index for current vertex.
- */
- adjList.add(new LinkedList<Vertex>());
- vertex.setIndex(adjList.size() - 1);
-
- /* recursively search for matching certs at next dN */
- depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
- builder, adjList, cpList);
-
- /*
- * If path has been completed, return ASAP!
- */
- if (pathCompleted) {
- return;
- } else {
- /*
- * If we get here, it means we have searched all possible
- * certs issued by the dN w/o finding any matching certs. This
- * means we have to backtrack to the previous cert in the path
- * and try some other paths.
- */
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
- + ": backtracking");
- if (!currentState.isInitial())
- builder.removeFinalCertFromPath(cpList);
- }
- }
- if (debug != null)
- debug.println("SunCertPathBuilder.depthFirstSearchReverse() all "
- + "certs in this adjacency list checked");
- }
-
- /*
* Adds a collection of matching certificates to the
* adjacency list.
*/
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java b/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java
deleted file mode 100644
index 186e252..0000000
--- a/jdk/src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2000, 2012, 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.provider.certpath;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.cert.*;
-import java.util.Set;
-
-/**
- * This class specifies the set of parameters used as input for the Sun
- * certification path build algorithm. It is identical to PKIXBuilderParameters
- * with the addition of a <code>buildForward</code> parameter which allows
- * the caller to specify whether or not the path should be constructed in
- * the forward direction.
- *
- * The default for the <code>buildForward</code> parameter is
- * true, which means that the build algorithm should construct paths
- * from the target subject back to the trusted anchor.
- *
- * @since 1.4
- * @author Sean Mullan
- * @author Yassir Elley
- */
-public class SunCertPathBuilderParameters extends PKIXBuilderParameters {
-
- private boolean buildForward = true;
-
- /**
- * Creates an instance of <code>SunCertPathBuilderParameters</code> with the
- * specified parameter values.
- *
- * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
- * @param targetConstraints a <code>CertSelector</code> specifying the
- * constraints on the target certificate
- * @throws InvalidAlgorithmParameterException if the specified
- * <code>Set</code> is empty <code>(trustAnchors.isEmpty() == true)</code>
- * @throws NullPointerException if the specified <code>Set</code> is
- * <code>null</code>
- * @throws ClassCastException if any of the elements in the <code>Set</code>
- * are not of type <code>java.security.cert.TrustAnchor</code>
- */
- public SunCertPathBuilderParameters(Set<TrustAnchor> trustAnchors,
- CertSelector targetConstraints) throws InvalidAlgorithmParameterException
- {
- super(trustAnchors, targetConstraints);
- setBuildForward(true);
- }
-
- /**
- * Creates an instance of <code>SunCertPathBuilderParameters</code> that
- * uses the specified <code>KeyStore</code> to populate the set
- * of most-trusted CA certificates.
- *
- * @param keystore A keystore from which the set of most-trusted
- * CA certificates will be populated.
- * @param targetConstraints a <code>CertSelector</code> specifying the
- * constraints on the target certificate
- * @throws KeyStoreException if the keystore has not been initialized.
- * @throws InvalidAlgorithmParameterException if the keystore does
- * not contain at least one trusted certificate entry
- * @throws NullPointerException if the keystore is <code>null</code>
- */
- public SunCertPathBuilderParameters(KeyStore keystore,
- CertSelector targetConstraints)
- throws KeyStoreException, InvalidAlgorithmParameterException
- {
- super(keystore, targetConstraints);
- setBuildForward(true);
- }
-
- /**
- * Returns the value of the buildForward flag.
- *
- * @return the value of the buildForward flag
- */
- public boolean getBuildForward() {
- return this.buildForward;
- }
-
- /**
- * Sets the value of the buildForward flag. If true, paths
- * are built from the target subject to the trusted anchor.
- * If false, paths are built from the trusted anchor to the
- * target subject. The default value if not specified is true.
- *
- * @param buildForward the value of the buildForward flag
- */
- public void setBuildForward(boolean buildForward) {
- this.buildForward = buildForward;
- }
-
- /**
- * Returns a formatted string describing the parameters.
- *
- * @return a formatted string describing the parameters.
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("[\n");
- sb.append(super.toString());
- sb.append(" Build Forward Flag: " + String.valueOf(buildForward) + "\n");
- sb.append("]\n");
- return sb.toString();
- }
-}
diff --git a/jdk/src/share/classes/sun/util/resources/en/TimeZoneNames_en_GB.java b/jdk/src/share/classes/sun/util/resources/en/TimeZoneNames_en_GB.java
index 0efee04..e0a3d49 100644
--- a/jdk/src/share/classes/sun/util/resources/en/TimeZoneNames_en_GB.java
+++ b/jdk/src/share/classes/sun/util/resources/en/TimeZoneNames_en_GB.java
@@ -47,7 +47,8 @@
protected final Object[][] getContents() {
return new Object[][] {
{"Europe/London", new String[] {"Greenwich Mean Time", "GMT",
- "British Summer Time", "BST"}},
+ "British Summer Time", "BST",
+ "British Time", "BT"}},
};
}
}
diff --git a/jdk/src/share/classes/sun/util/resources/hi/TimeZoneNames_hi.java b/jdk/src/share/classes/sun/util/resources/hi/TimeZoneNames_hi.java
index d15ed01..05acbc3 100644
--- a/jdk/src/share/classes/sun/util/resources/hi/TimeZoneNames_hi.java
+++ b/jdk/src/share/classes/sun/util/resources/hi/TimeZoneNames_hi.java
@@ -40,7 +40,8 @@
{"Asia/Calcutta",
new String[] {
"\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST",
- "\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST"
+ "\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IST",
+ "\u092d\u093e\u0930\u0924\u0940\u092f \u0938\u092e\u092f", "IT"
}
},
};
diff --git a/jdk/src/share/native/common/jni_util.h b/jdk/src/share/native/common/jni_util.h
index 0242d71..cdfaa63 100644
--- a/jdk/src/share/native/common/jni_util.h
+++ b/jdk/src/share/native/common/jni_util.h
@@ -391,6 +391,7 @@
void buildJniFunctionName(const char *sym, const char *cname,
char *jniEntryName);
+extern int getErrorString(int err, char *buf, size_t len);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
diff --git a/jdk/src/share/native/java/util/zip/Deflater.c b/jdk/src/share/native/java/util/zip/Deflater.c
index c19211c..7492a08 100644
--- a/jdk/src/share/native/java/util/zip/Deflater.c
+++ b/jdk/src/share/native/java/util/zip/Deflater.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -49,13 +49,21 @@
Java_java_util_zip_Deflater_initIDs(JNIEnv *env, jclass cls)
{
levelID = (*env)->GetFieldID(env, cls, "level", "I");
+ CHECK_NULL(levelID);
strategyID = (*env)->GetFieldID(env, cls, "strategy", "I");
+ CHECK_NULL(strategyID);
setParamsID = (*env)->GetFieldID(env, cls, "setParams", "Z");
+ CHECK_NULL(setParamsID);
finishID = (*env)->GetFieldID(env, cls, "finish", "Z");
+ CHECK_NULL(finishID);
finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
+ CHECK_NULL(finishedID);
bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
+ CHECK_NULL(bufID);
offID = (*env)->GetFieldID(env, cls, "off", "I");
+ CHECK_NULL(offID);
lenID = (*env)->GetFieldID(env, cls, "len", "I");
+ CHECK_NULL(lenID);
}
JNIEXPORT jlong JNICALL
@@ -137,14 +145,14 @@
in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
if (in_buf == NULL) {
// Throw OOME only when length is not zero
- if (this_len != 0)
+ if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
if (out_buf == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0)
+ if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
@@ -163,7 +171,7 @@
this_off += this_len - strm->avail_in;
(*env)->SetIntField(env, this, offID, this_off);
(*env)->SetIntField(env, this, lenID, strm->avail_in);
- return len - strm->avail_out;
+ return (jint) (len - strm->avail_out);
case Z_BUF_ERROR:
(*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
return 0;
diff --git a/jdk/src/share/native/java/util/zip/Inflater.c b/jdk/src/share/native/java/util/zip/Inflater.c
index d7766f2..79bcdd5 100644
--- a/jdk/src/share/native/java/util/zip/Inflater.c
+++ b/jdk/src/share/native/java/util/zip/Inflater.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -50,10 +50,15 @@
Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls)
{
needDictID = (*env)->GetFieldID(env, cls, "needDict", "Z");
+ CHECK_NULL(needDictID);
finishedID = (*env)->GetFieldID(env, cls, "finished", "Z");
+ CHECK_NULL(finishedID);
bufID = (*env)->GetFieldID(env, cls, "buf", "[B");
+ CHECK_NULL(bufID);
offID = (*env)->GetFieldID(env, cls, "off", "I");
+ CHECK_NULL(offID);
lenID = (*env)->GetFieldID(env, cls, "len", "I");
+ CHECK_NULL(lenID);
}
JNIEXPORT jlong JNICALL
@@ -127,14 +132,14 @@
in_buf = (*env)->GetPrimitiveArrayCritical(env, this_buf, 0);
if (in_buf == NULL) {
- if (this_len != 0)
+ if (this_len != 0 && (*env)->ExceptionOccurred(env) == NULL)
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
out_buf = (*env)->GetPrimitiveArrayCritical(env, b, 0);
if (out_buf == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
- if (len != 0)
+ if (len != 0 && (*env)->ExceptionOccurred(env) == NULL)
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
@@ -154,7 +159,7 @@
this_off += this_len - strm->avail_in;
(*env)->SetIntField(env, this, offID, this_off);
(*env)->SetIntField(env, this, lenID, strm->avail_in);
- return len - strm->avail_out;
+ return (jint) (len - strm->avail_out);
case Z_NEED_DICT:
(*env)->SetBooleanField(env, this, needDictID, JNI_TRUE);
/* Might have consumed some input here! */
diff --git a/jdk/src/share/native/java/util/zip/ZipFile.c b/jdk/src/share/native/java/util/zip/ZipFile.c
index 7b34f66..8e857c1 100644
--- a/jdk/src/share/native/java/util/zip/ZipFile.c
+++ b/jdk/src/share/native/java/util/zip/ZipFile.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -71,11 +71,13 @@
if (msg != NULL) {
s = JNU_NewStringPlatform(env, msg);
}
- x = JNU_NewObjectByName(env,
+ if (s != NULL) {
+ x = JNU_NewObjectByName(env,
"java/util/zip/ZipException",
"(Ljava/lang/String;)V", s);
- if (x != NULL) {
- (*env)->Throw(env, x);
+ if (x != NULL) {
+ (*env)->Throw(env, x);
+ }
}
}
@@ -363,8 +365,10 @@
/* If some names were found then build array of java strings */
if (count > 0) {
- jclass cls = (*env)->FindClass(env, "java/lang/String");
+ jclass cls = JNU_ClassString(env);
+ CHECK_NULL_RETURN(cls, NULL);
result = (*env)->NewObjectArray(env, count, cls, 0);
+ CHECK_NULL_RETURN(result, NULL);
if (result != 0) {
for (i = 0; i < count; i++) {
jstring str = (*env)->NewStringUTF(env, zip->metanames[i]);
diff --git a/jdk/src/share/native/java/util/zip/zip_util.c b/jdk/src/share/native/java/util/zip/zip_util.c
index b172cde..3245dea 100644
--- a/jdk/src/share/native/java/util/zip/zip_util.c
+++ b/jdk/src/share/native/java/util/zip/zip_util.c
@@ -1314,12 +1314,23 @@
jint
ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
{
- jlong entry_size = (entry->csize != 0) ? entry->csize : entry->size;
+ jlong entry_size;
jlong start;
+ if (zip == 0) {
+ return -1;
+ }
+
/* Clear previous zip error */
zip->msg = NULL;
+ if (entry == 0) {
+ zip->msg = "ZIP_Read: jzentry is NULL";
+ return -1;
+ }
+
+ entry_size = (entry->csize != 0) ? entry->csize : entry->size;
+
/* Check specified position */
if (pos < 0 || pos > entry_size - 1) {
zip->msg = "ZIP_Read: specified offset out of range";
@@ -1449,6 +1460,12 @@
ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
{
char *msg;
+ char tmpbuf[1024];
+
+ if (entry == 0) {
+ jio_fprintf(stderr, "jzentry was invalid");
+ return JNI_FALSE;
+ }
strcpy(entryname, entry->name);
if (entry->csize == 0) {
@@ -1467,8 +1484,11 @@
msg = zip->msg;
ZIP_Unlock(zip);
if (n == -1) {
- jio_fprintf(stderr, "%s: %s\n", zip->name,
- msg != 0 ? msg : strerror(errno));
+ if (msg == 0) {
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ msg = tmpbuf;
+ }
+ jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
return JNI_FALSE;
}
buf += n;
@@ -1481,8 +1501,11 @@
if ((msg == NULL) || (*msg == 0)) {
msg = zip->msg;
}
- jio_fprintf(stderr, "%s: %s\n", zip->name,
- msg != 0 ? msg : strerror(errno));
+ if (msg == 0) {
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ msg = tmpbuf;
+ }
+ jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
return JNI_FALSE;
}
}
diff --git a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
index 8984258..78e52a2 100644
--- a/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
+++ b/jdk/src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
*/
/* Copyright (c) 2002 Graz University of Technology. All rights reserved.
@@ -474,6 +474,7 @@
jfieldID fieldID;
jclass jSsl3RandomDataClass;
jobject jRandomInfo, jRIClientRandom, jRIServerRandom, jVersion;
+ memset(&ckParam, 0, sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS));
/* get RandomInfo */
jSsl3MasterKeyDeriveParamsClass = (*env)->FindClass(env, CLASS_SSL3_MASTER_KEY_DERIVE_PARAMS);
@@ -527,6 +528,7 @@
CK_TLS_PRF_PARAMS ckParam;
jfieldID fieldID;
jobject jSeed, jLabel, jOutput;
+ memset(&ckParam, 0, sizeof(CK_TLS_PRF_PARAMS));
// TBD: what if jParam == NULL?!
@@ -592,6 +594,7 @@
jobject jRandomInfo, jRIClientRandom, jRIServerRandom;
jobject jReturnedKeyMaterial, jRMIvClient, jRMIvServer;
CK_ULONG ckTemp;
+ memset(&ckParam, 0, sizeof(CK_SSL3_KEY_MAT_PARAMS));
/* get ulMacSizeInBits */
jSsl3KeyMatParamsClass = (*env)->FindClass(env, CLASS_SSL3_KEY_MAT_PARAMS);
@@ -1355,6 +1358,7 @@
jlong jHashAlg, jMgf, jSource;
jobject jSourceData;
CK_BYTE_PTR ckpByte;
+ memset(&ckParam, 0, sizeof(CK_RSA_PKCS_OAEP_PARAMS));
/* get hashAlg */
jRsaPkcsOaepParamsClass = (*env)->FindClass(env, CLASS_RSA_PKCS_OAEP_PARAMS);
@@ -1404,6 +1408,7 @@
jlong jIteration;
jobject jInitVector, jPassword, jSalt;
CK_ULONG ckTemp;
+ memset(&ckParam, 0, sizeof(CK_PBE_PARAMS));
/* get pInitVector */
jPbeParamsClass = (*env)->FindClass(env, CLASS_PBE_PARAMS);
@@ -1522,6 +1527,7 @@
jfieldID fieldID;
jlong jSaltSource, jIteration, jPrf;
jobject jSaltSourceData, jPrfData;
+ memset(&ckParam, 0, sizeof(CK_PKCS5_PBKD2_PARAMS));
/* get saltSource */
jPkcs5Pbkd2ParamsClass = (*env)->FindClass(env, CLASS_PKCS5_PBKD2_PARAMS);
@@ -1734,6 +1740,7 @@
jfieldID fieldID;
jlong jKdf;
jobject jOtherInfo, jPublicData;
+ memset(&ckParam, 0, sizeof(CK_X9_42_DH1_DERIVE_PARAMS));
/* get kdf */
jX942Dh1DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH1_DERIVE_PARAMS);
@@ -1779,6 +1786,7 @@
jfieldID fieldID;
jlong jKdf, jPrivateDataLen, jPrivateData;
jobject jOtherInfo, jPublicData, jPublicData2;
+ memset(&ckParam, 0, sizeof(CK_X9_42_DH2_DERIVE_PARAMS));
/* get kdf */
jX942Dh2DeriveParamsClass = (*env)->FindClass(env, CLASS_X9_42_DH2_DERIVE_PARAMS);
diff --git a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
index 2c74dd9..7127c7c 100644
--- a/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
+++ b/jdk/src/solaris/classes/java/net/PlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -119,6 +119,8 @@
protected native void disconnect0(int family);
+ native int dataAvailable();
+
/**
* Perform class load-time initializations.
*/
diff --git a/jdk/src/solaris/classes/sun/awt/FcFontManager.java b/jdk/src/solaris/classes/sun/awt/FcFontManager.java
new file mode 100644
index 0000000..0b3ef6a
--- /dev/null
+++ b/jdk/src/solaris/classes/sun/awt/FcFontManager.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.awt;
+
+import sun.font.FcFontConfiguration;
+import sun.font.FontConfigManager;
+import sun.font.SunFontManager;
+
+/**
+ * A {@link sun.font.FontManager} that uses fontconfig to find system fonts.
+ */
+public class FcFontManager extends SunFontManager {
+
+ private FontConfigManager fcManager = null;
+
+ public synchronized FontConfigManager getFontConfigManager() {
+
+ if (fcManager == null) {
+ fcManager = new FontConfigManager();
+ }
+
+ return fcManager;
+ }
+
+ @Override
+ protected FontConfiguration createFontConfiguration() {
+ FcFontConfiguration fcFontConfig = new FcFontConfiguration(this);
+ if (fcFontConfig.init()) {
+ return fcFontConfig;
+ } else {
+ throw new InternalError("failed to initialize fontconfig");
+ }
+ }
+
+ @Override
+ public FontConfiguration createFontConfiguration(boolean preferLocaleFonts,
+ boolean preferPropFonts) {
+ FcFontConfiguration fcFontConfig =
+ new FcFontConfiguration(this, preferLocaleFonts, preferPropFonts);
+ if (fcFontConfig.init()) {
+ return fcFontConfig;
+ } else {
+ throw new InternalError("failed to initialize fontconfig");
+ }
+ }
+
+ @Override
+ protected String[] getDefaultPlatformFont() {
+ final String[] info = new String[2];
+ getFontConfigManager().initFontConfigFonts(false);
+ FontConfigManager.FcCompFont[] fontConfigFonts =
+ getFontConfigManager().getFontConfigFonts();
+ for (int i=0; i<fontConfigFonts.length; i++) {
+ if ("sans".equals(fontConfigFonts[i].fcFamily) &&
+ 0 == fontConfigFonts[i].style) {
+ info[0] = fontConfigFonts[i].firstFont.familyName;
+ info[1] = fontConfigFonts[i].firstFont.fontFile;
+ break;
+ }
+ }
+ /* Absolute last ditch attempt in the face of fontconfig problems.
+ * If we didn't match, pick the first, or just make something
+ * up so we don't NPE.
+ */
+ if (info[0] == null) {
+ if (fontConfigFonts.length > 0 &&
+ fontConfigFonts[0].firstFont.fontFile != null) {
+ info[0] = fontConfigFonts[0].firstFont.familyName;
+ info[1] = fontConfigFonts[0].firstFont.fontFile;
+ } else {
+ info[0] = "Dialog";
+ info[1] = "/dialog.ttf";
+ }
+ }
+ return info;
+ }
+
+ protected native String getFontPathNative(boolean noType1Fonts,
+ boolean isX11GE);
+
+ protected synchronized String getFontPath(boolean noType1Fonts) {
+ return getFontPathNative(noType1Fonts, false);
+ }
+
+}
diff --git a/jdk/src/solaris/classes/sun/awt/X11FontManager.java b/jdk/src/solaris/classes/sun/awt/X11FontManager.java
index b3a91df..0b001b3 100644
--- a/jdk/src/solaris/classes/sun/awt/X11FontManager.java
+++ b/jdk/src/solaris/classes/sun/awt/X11FontManager.java
@@ -54,7 +54,7 @@
/**
* The X11 implementation of {@link FontManager}.
*/
-public final class X11FontManager extends SunFontManager {
+public final class X11FontManager extends FcFontManager {
// constants identifying XLFD and font ID fields
private static final int FOUNDRY_FIELD = 1;
@@ -154,8 +154,6 @@
*/
private static String[] fontdirs = null;
- private FontConfigManager fcManager = null;
-
public static X11FontManager getInstance() {
return (X11FontManager) SunFontManager.getInstance();
}
@@ -784,51 +782,9 @@
preferLocaleFonts, preferPropFonts);
}
- public synchronized native String getFontPathNative(boolean noType1Fonts);
-
protected synchronized String getFontPath(boolean noType1Fonts) {
isHeadless(); // make sure GE is inited, as its the X11 lock.
- return getFontPathNative(noType1Fonts);
- }
-
- @Override
- protected String[] getDefaultPlatformFont() {
- final String[] info = new String[2];
- getFontConfigManager().initFontConfigFonts(false);
- FontConfigManager.FcCompFont[] fontConfigFonts =
- getFontConfigManager().getFontConfigFonts();
- for (int i=0; i<fontConfigFonts.length; i++) {
- if ("sans".equals(fontConfigFonts[i].fcFamily) &&
- 0 == fontConfigFonts[i].style) {
- info[0] = fontConfigFonts[i].firstFont.familyName;
- info[1] = fontConfigFonts[i].firstFont.fontFile;
- break;
- }
- }
- /* Absolute last ditch attempt in the face of fontconfig problems.
- * If we didn't match, pick the first, or just make something
- * up so we don't NPE.
- */
- if (info[0] == null) {
- if (fontConfigFonts.length > 0 &&
- fontConfigFonts[0].firstFont.fontFile != null) {
- info[0] = fontConfigFonts[0].firstFont.familyName;
- info[1] = fontConfigFonts[0].firstFont.fontFile;
- } else {
- info[0] = "Dialog";
- info[1] = "/dialog.ttf";
- }
- }
- return info;
- }
-
- public synchronized FontConfigManager getFontConfigManager() {
-
- if (fcManager == null) {
- fcManager = new FontConfigManager();
- }
-
- return fcManager;
+ return getFontPathNative(noType1Fonts, true);
}
@Override
diff --git a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java
index 34d8b7c..ecb813d 100644
--- a/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java
+++ b/jdk/src/solaris/classes/sun/font/FcFontConfiguration.java
@@ -39,10 +39,10 @@
import java.util.HashSet;
import java.util.Properties;
import java.util.Scanner;
+import sun.awt.FcFontManager;
import sun.awt.FontConfiguration;
import sun.awt.FontDescriptor;
import sun.awt.SunToolkit;
-import sun.awt.X11FontManager;
import sun.font.CompositeFontDescriptor;
import sun.font.FontManager;
import sun.font.FontConfigManager.FontConfigInfo;
@@ -92,7 +92,7 @@
setFontConfiguration();
readFcInfo();
- X11FontManager fm = (X11FontManager) fontManager;
+ FcFontManager fm = (FcFontManager) fontManager;
FontConfigManager fcm = fm.getFontConfigManager();
if (fcCompFonts == null) {
fcCompFonts = fcm.loadFontConfig();
@@ -194,7 +194,7 @@
@Override
public String[] getPlatformFontNames() {
HashSet<String> nameSet = new HashSet<String>();
- X11FontManager fm = (X11FontManager) fontManager;
+ FcFontManager fm = (FcFontManager) fontManager;
FontConfigManager fcm = fm.getFontConfigManager();
FcCompFont[] fcCompFonts = fcm.loadFontConfig();
for (int i=0; i<fcCompFonts.length; i++) {
@@ -235,7 +235,7 @@
@Override
public CompositeFontDescriptor[] get2DCompositeFontInfo() {
- X11FontManager fm = (X11FontManager) fontManager;
+ FcFontManager fm = (FcFontManager) fontManager;
FontConfigManager fcm = fm.getFontConfigManager();
FcCompFont[] fcCompFonts = fcm.loadFontConfig();
@@ -368,7 +368,7 @@
private void writeFcInfo() {
Properties props = new Properties();
props.setProperty("version", fileVersion);
- X11FontManager fm = (X11FontManager) fontManager;
+ FcFontManager fm = (FcFontManager) fontManager;
FontConfigManager fcm = fm.getFontConfigManager();
FontConfigInfo fcInfo = fcm.getFontConfigInfo();
props.setProperty("fcversion", Integer.toString(fcInfo.fcVersion));
@@ -427,7 +427,7 @@
return;
}
Properties props = new Properties();
- X11FontManager fm = (X11FontManager) fontManager;
+ FcFontManager fm = (FcFontManager) fontManager;
FontConfigManager fcm = fm.getFontConfigManager();
try {
FileInputStream fis = new FileInputStream(fcFile);
diff --git a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
index 81ae3f6..81db74f 100644
--- a/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
+++ b/jdk/src/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -68,9 +68,23 @@
long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32);
fd1 = (int) pipeFds;
- pollWrapper = new DevPollArrayWrapper();
- pollWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<Integer,SelectionKeyImpl>();
+ try {
+ pollWrapper = new DevPollArrayWrapper();
+ pollWrapper.initInterrupt(fd0, fd1);
+ fdToKey = new HashMap<>();
+ } catch (Throwable t) {
+ try {
+ FileDispatcherImpl.closeIntFD(fd0);
+ } catch (IOException ioe0) {
+ t.addSuppressed(ioe0);
+ }
+ try {
+ FileDispatcherImpl.closeIntFD(fd1);
+ } catch (IOException ioe1) {
+ t.addSuppressed(ioe1);
+ }
+ throw t;
+ }
}
protected int doSelect(long timeout)
diff --git a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
index d5f24e8..1528b9e 100644
--- a/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
+++ b/jdk/src/solaris/classes/sun/nio/ch/EPollSelectorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,9 +65,23 @@
long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32);
fd1 = (int) pipeFds;
- pollWrapper = new EPollArrayWrapper();
- pollWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<>();
+ try {
+ pollWrapper = new EPollArrayWrapper();
+ pollWrapper.initInterrupt(fd0, fd1);
+ fdToKey = new HashMap<>();
+ } catch (Throwable t) {
+ try {
+ FileDispatcherImpl.closeIntFD(fd0);
+ } catch (IOException ioe0) {
+ t.addSuppressed(ioe0);
+ }
+ try {
+ FileDispatcherImpl.closeIntFD(fd1);
+ } catch (IOException ioe1) {
+ t.addSuppressed(ioe1);
+ }
+ throw t;
+ }
}
protected int doSelect(long timeout) throws IOException {
diff --git a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java
index 17c9f03..1911c35 100644
--- a/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java
+++ b/jdk/src/solaris/classes/sun/nio/ch/PollSelectorImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -57,9 +57,23 @@
long pipeFds = IOUtil.makePipe(false);
fd0 = (int) (pipeFds >>> 32);
fd1 = (int) pipeFds;
- pollWrapper = new PollArrayWrapper(INIT_CAP);
- pollWrapper.initInterrupt(fd0, fd1);
- channelArray = new SelectionKeyImpl[INIT_CAP];
+ try {
+ pollWrapper = new PollArrayWrapper(INIT_CAP);
+ pollWrapper.initInterrupt(fd0, fd1);
+ channelArray = new SelectionKeyImpl[INIT_CAP];
+ } catch (Throwable t) {
+ try {
+ FileDispatcherImpl.closeIntFD(fd0);
+ } catch (IOException ioe0) {
+ t.addSuppressed(ioe0);
+ }
+ try {
+ FileDispatcherImpl.closeIntFD(fd1);
+ } catch (IOException ioe1) {
+ t.addSuppressed(ioe1);
+ }
+ throw t;
+ }
}
protected int doSelect(long timeout)
diff --git a/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java
index f455afe..de93310 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/GnomeFileTypeDetector.java
@@ -86,7 +86,7 @@
// GIO
private static native boolean initializeGio();
- private static native byte[] probeUsingGio(long pathAddress);
+ private static synchronized native byte[] probeUsingGio(long pathAddress);
// GNOME VFS
private static native boolean initializeGnomeVfs();
diff --git a/jdk/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java b/jdk/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
index 8878703..b16eb77 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/MimeTypesFileTypeDetector.java
@@ -171,7 +171,7 @@
final String EXTEQUAL = "exts=";
String extRegex = "\\b" + EXTEQUAL +
- "(\"[\\p{Graph}|\\p{Blank}]+?\"|\\p{Graph}+\\b)";
+ "(\"[\\p{Graph}\\p{Blank}]+?\"|\\p{Graph}+\\b)";
Pattern extPattern = Pattern.compile(extRegex);
Matcher extMatcher = extPattern.matcher(entry);
@@ -181,7 +181,7 @@
if (exts.charAt(0) == '"') {
exts = exts.substring(1, exts.length() - 1);
}
- String[] extList = exts.split("[\\p{Blank}|\\p{Punct}]+");
+ String[] extList = exts.split("[\\p{Blank}\\p{Punct}]+");
for (String ext : extList) {
putIfAbsent(ext, type);
}
diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java
index 98fc9ab..0532e4d 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -186,7 +186,8 @@
return false;
UnixFileStore other = (UnixFileStore)ob;
return (this.dev == other.dev) &&
- Arrays.equals(this.entry.dir(), other.entry.dir());
+ Arrays.equals(this.entry.dir(), other.entry.dir()) &&
+ this.entry.name().equals(other.entry.name());
}
@Override
diff --git a/jdk/src/solaris/native/common/jni_util_md.c b/jdk/src/solaris/native/common/jni_util_md.c
index 42ab2de..598dc41 100644
--- a/jdk/src/solaris/native/common/jni_util_md.c
+++ b/jdk/src/solaris/native/common/jni_util_md.c
@@ -37,6 +37,13 @@
return NULL;
}
+#if defined(LINUX) && (defined(_GNU_SOURCE) || \
+ (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L \
+ && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 600))
+extern int __xpg_strerror_r(int, char *, size_t);
+#define strerror_r(a, b, c) __xpg_strerror_r((a), (b), (c))
+#endif
+
void* getProcessHandle() {
static void *procHandle = NULL;
if (procHandle != NULL) {
@@ -59,3 +66,9 @@
}
}
+int
+getErrorString(int err, char *buf, size_t len)
+{
+ if (err == 0 || len < 1) return 0;
+ return strerror_r(err, buf, len);
+}
diff --git a/jdk/src/solaris/native/java/io/io_util_md.c b/jdk/src/solaris/native/java/io/io_util_md.c
index 5899a41..f8fdc46 100644
--- a/jdk/src/solaris/native/java/io/io_util_md.c
+++ b/jdk/src/solaris/native/java/io/io_util_md.c
@@ -216,13 +216,6 @@
getLastErrorString(char *buf, size_t len)
{
if (errno == 0 || len < 1) return 0;
-
- const char *err = strerror(errno);
- size_t n = strlen(err);
- if (n >= len)
- n = len - 1;
-
- strncpy(buf, err, n);
- buf[n] = '\0';
- return n;
+ getErrorString(errno, buf, len);
+ return strlen(buf);
}
diff --git a/jdk/src/solaris/native/java/lang/UNIXProcess_md.c b/jdk/src/solaris/native/java/lang/UNIXProcess_md.c
index bccd41d..7df5d59 100644
--- a/jdk/src/solaris/native/java/lang/UNIXProcess_md.c
+++ b/jdk/src/solaris/native/java/lang/UNIXProcess_md.c
@@ -292,12 +292,13 @@
static const char * const format = "error=%d, %s";
const char *detail = defaultDetail;
char *errmsg;
+ char tmpbuf[1024];
jstring s;
if (errnum != 0) {
- const char *s = strerror(errnum);
- if (strcmp(s, "Unknown error") != 0)
- detail = s;
+ int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
+ if (ret != EINVAL)
+ detail = tmpbuf;
}
/* ASCII Decimal representation uses 2.4 times as many bits as binary. */
errmsg = NEW(char, strlen(format) + strlen(detail) + 3 * sizeof(errnum));
diff --git a/jdk/src/solaris/native/java/net/AbstractPlainDatagramSocketImpl.c b/jdk/src/solaris/native/java/net/AbstractPlainDatagramSocketImpl.c
deleted file mode 100644
index 075fffc..0000000
--- a/jdk/src/solaris/native/java/net/AbstractPlainDatagramSocketImpl.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#ifdef __solaris__
-#include <unistd.h>
-#include <stropts.h>
-
-#ifndef BSD_COMP
-#define BSD_COMP
-#endif
-
-#endif
-
-#include <sys/ioctl.h>
-
-#include "jvm.h"
-#include "jni_util.h"
-#include "net_util.h"
-
-#include "java_net_AbstractPlainDatagramSocketImpl.h"
-
-static jfieldID IO_fd_fdID;
-
-static jfieldID apdsi_fdID;
-
-
-/*
- * Class: java_net_AbstractPlainDatagramSocketImpl
- * Method: init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-Java_java_net_AbstractPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
-
- apdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
- "Ljava/io/FileDescriptor;");
- CHECK_NULL(apdsi_fdID);
-
- IO_fd_fdID = NET_GetFileDescriptorID(env);
-}
-
-/*
- * Class: java_net_AbstractPlainDatagramSocketImpl
- * Method: dataAvailable
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_java_net_AbstractPlainDatagramSocketImpl_dataAvailable
-(JNIEnv *env, jobject this) {
- int fd, retval;
-
- jobject fdObj = (*env)->GetObjectField(env, this, apdsi_fdID);
-
- if (IS_NULL(fdObj)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return -1;
- }
- fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-
- if (ioctl(fd, FIONREAD, &retval) < 0) {
- return -1;
- }
- return retval;
-}
diff --git a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c
index 3f1714e..77899d6 100644
--- a/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c
+++ b/jdk/src/solaris/native/java/net/PlainDatagramSocketImpl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -32,6 +32,12 @@
#ifdef __solaris__
#include <fcntl.h>
+#include <unistd.h>
+#include <stropts.h>
+
+#ifndef BSD_COMP
+#define BSD_COMP
+#endif
#endif
#ifdef __linux__
#include <unistd.h>
@@ -52,6 +58,8 @@
#endif
#endif // __linux__
+#include <sys/ioctl.h>
+
#ifndef IPTOS_TOS_MASK
#define IPTOS_TOS_MASK 0x1e
#endif
@@ -946,6 +954,7 @@
jobject this) {
jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
int arg, fd, t = 1;
+ char tmpbuf[1024];
#ifdef AF_INET6
int domain = ipv6_available() ? AF_INET6 : AF_INET;
#else
@@ -981,14 +990,14 @@
arg = 65507;
if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_SNDBUF,
(char *)&arg, sizeof(arg)) < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
return;
}
if (JVM_SetSockOpt(fd, SOL_SOCKET, SO_RCVBUF,
(char *)&arg, sizeof(arg)) < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
return;
}
#endif /* __APPLE__ */
@@ -996,15 +1005,16 @@
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(int));
#if defined(__linux__)
- arg = 0;
- int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
- if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
- (errno != ENOPROTOOPT)) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- strerror(errno));
- close(fd);
- return;
- }
+ arg = 0;
+ int level = (domain == AF_INET6) ? IPPROTO_IPV6 : IPPROTO_IP;
+ if ((setsockopt(fd, level, IP_MULTICAST_ALL, (char*)&arg, sizeof(arg)) < 0) &&
+ (errno != ENOPROTOOPT))
+ {
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", tmpbuf);
+ close(fd);
+ return;
+ }
#endif
#if defined (__linux__) && defined (AF_INET6)
@@ -2265,3 +2275,28 @@
{
mcast_join_leave(env, this, iaObj, niObj, JNI_FALSE);
}
+
+/*
+ * Class: java_net_PlainDatagramSocketImpl
+ * Method: dataAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL
+Java_java_net_PlainDatagramSocketImpl_dataAvailable(JNIEnv *env, jobject this)
+{
+ int fd, retval;
+
+ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return -1;
+ }
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+
+ if (ioctl(fd, FIONREAD, &retval) < 0) {
+ return -1;
+ }
+ return retval;
+}
diff --git a/jdk/src/solaris/native/java/util/TimeZone_md.c b/jdk/src/solaris/native/java/util/TimeZone_md.c
index 76c3f39..3507c1c 100644
--- a/jdk/src/solaris/native/java/util/TimeZone_md.c
+++ b/jdk/src/solaris/native/java/util/TimeZone_md.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -35,14 +35,20 @@
#include <string.h>
#include <dirent.h>
#include <unistd.h>
-#ifdef __solaris__
+#if defined(__solaris__)
#include <libscf.h>
#endif
#include "jvm.h"
+#include "TimeZone_md.h"
#define SKIP_SPACE(p) while (*p == ' ' || *p == '\t') p++;
+#if defined(_ALLBSD_SOURCE)
+#define dirent64 dirent
+#define readdir64_r readdir_r
+#endif
+
#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
#define fileopen fopen
#define filegets fgets
@@ -50,19 +56,20 @@
#endif
#if defined(__linux__) || defined(_ALLBSD_SOURCE)
-
-
static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
static const char *ZONEINFO_DIR = "/usr/share/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/etc/localtime";
#else
-#ifdef _AIX
-static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
-#endif
static const char *SYS_INIT_FILE = "/etc/default/init";
static const char *ZONEINFO_DIR = "/usr/share/lib/zoneinfo";
static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
-#endif /*__linux__*/
+#endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
+
+#if defined(_AIX)
+static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
+#endif
+
+#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
/*
* Returns a pointer to the zone ID portion of the given zoneinfo file
@@ -108,8 +115,8 @@
{
DIR *dirp = NULL;
struct stat statbuf;
- struct dirent *dp = NULL;
- struct dirent *entry = NULL;
+ struct dirent64 *dp = NULL;
+ struct dirent64 *entry = NULL;
char *pathname = NULL;
int fd = -1;
char *dbuf = NULL;
@@ -120,19 +127,13 @@
return NULL;
}
- entry = (struct dirent *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
+ entry = (struct dirent64 *) malloc((size_t) pathconf(dir, _PC_NAME_MAX));
if (entry == NULL) {
(void) closedir(dirp);
return NULL;
}
-#if defined(_AIX) || defined(__linux__) || defined(MACOSX) || (defined(__solaris__) \
- && (defined(_POSIX_PTHREAD_SEMANTICS) || defined(_LP64)))
- while (readdir_r(dirp, entry, &dp) == 0 && dp != NULL) {
-#else
- while ((dp = readdir_r(dirp, entry)) != NULL) {
-#endif
-
+ while (readdir64_r(dirp, entry, &dp) == 0 && dp != NULL) {
/*
* Skip '.' and '..' (and possibly other .* files)
*/
@@ -145,7 +146,7 @@
*/
if ((strcmp(dp->d_name, "ROC") == 0)
|| (strcmp(dp->d_name, "posixrules") == 0)
-#ifdef __solaris__
+#if defined(__solaris__)
/*
* Skip the "src" and "tab" directories on Solaris.
*/
@@ -230,7 +231,7 @@
char *buf;
size_t size;
-#ifdef __linux__
+#if defined(__linux__)
/*
* Try reading the /etc/timezone file for Debian distros. There's
* no spec of the file format available. This parsing assumes that
@@ -254,7 +255,7 @@
return tz;
}
}
-#endif /* __linux__ */
+#endif /* defined(__linux__) */
/*
* Next, try /etc/localtime to find the zone ID.
@@ -318,8 +319,9 @@
free((void *) buf);
return tz;
}
-#else
-#ifdef __solaris__
+
+#elif defined(__solaris__)
+
#if !defined(__sparcv9) && !defined(amd64)
/*
@@ -444,8 +446,7 @@
}
/*NOTREACHED*/
}
-#endif /* not __sparcv9 */
-
+#endif /* !defined(__sparcv9) && !defined(amd64) */
/*
* Performs Solaris dependent mapping. Returns a zone ID if
@@ -546,7 +547,7 @@
}
/*
- * Retruns a zone ID of Solaris when the TZ value is "localtime".
+ * Returns a zone ID of Solaris when the TZ value is "localtime".
* First, it tries scf. If scf fails, it looks for the same file as
* /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
*/
@@ -615,10 +616,11 @@
free((void *) buf);
return tz;
}
-#endif /*__solaris__*/
-#endif /*__linux__*/
-#ifdef _AIX
+#endif /* defined(__solaris__) */
+
+#elif defined(_AIX)
+
static char *
getPlatformTimeZoneID()
{
@@ -644,175 +646,33 @@
return tz;
}
-static char *mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz);
-#endif
-/*
- * findJavaTZ_md() maps platform time zone ID to Java time zone ID
- * using <java_home>/lib/tzmappings. If the TZ value is not found, it
- * trys some libc implementation dependent mappings. If it still
- * can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm
- * form.
- */
-/*ARGSUSED1*/
-char *
-findJavaTZ_md(const char *java_home_dir)
-{
- char *tz;
- char *javatz = NULL;
- char *freetz = NULL;
-
- tz = getenv("TZ");
-
-#if defined(__linux__) || defined(_ALLBSD_SOURCE)
- if (tz == NULL) {
-#else
-#if defined (__solaris__) || defined(_AIX)
- if (tz == NULL || *tz == '\0') {
-#endif
-#endif
- tz = getPlatformTimeZoneID();
- freetz = tz;
- }
-
- /*
- * Remove any preceding ':'
- */
- if (tz != NULL && *tz == ':') {
- tz++;
- }
-
-#ifdef __solaris__
- if (tz != NULL && strcmp(tz, "localtime") == 0) {
- tz = getSolarisDefaultZoneID();
- freetz = tz;
- }
-#endif
-
- if (tz != NULL) {
-#ifdef __linux__
- /*
- * Ignore "posix/" prefix.
- */
- if (strncmp(tz, "posix/", 6) == 0) {
- tz += 6;
- }
-#endif
- javatz = strdup(tz);
- if (freetz != NULL) {
- free((void *) freetz);
- }
-
-#ifdef _AIX
- freetz = mapPlatformToJavaTimezone(java_home_dir, javatz);
- if (javatz != NULL) {
- free((void *) javatz);
- }
- javatz = freetz;
-#endif
- }
-
- return javatz;
-}
-
-/**
- * Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00")
- */
-
-#ifdef MACOSX
-
-char *
-getGMTOffsetID()
-{
- time_t offset;
- char sign, buf[32];
- struct tm *local_tm;
- time_t clock;
- time_t currenttime;
-
- clock = time(NULL);
- tzset();
- local_tm = localtime(&clock);
- if (local_tm->tm_gmtoff >= 0) {
- offset = (time_t) local_tm->tm_gmtoff;
- sign = "+";
- } else {
- offset = (time_t) -local_tm->tm_gmtoff;
- sign = "-";
- }
- sprintf(buf, (const char *)"GMT%c%02d:%02d",
- sign, (int)(offset/3600), (int)((offset%3600)/60));
- return strdup(buf);
-}
-#else
-
-char *
-getGMTOffsetID()
-{
- time_t offset;
- char sign, buf[32];
-#ifdef __solaris__
- struct tm localtm;
- time_t currenttime;
-
- currenttime = time(NULL);
- if (localtime_r(¤ttime, &localtm) == NULL) {
- return NULL;
- }
-
- offset = localtm.tm_isdst ? altzone : timezone;
-#else
- offset = timezone;
-#endif /*__linux__*/
-
- if (offset == 0) {
- return strdup("GMT");
- }
-
- /* Note that the time offset direction is opposite. */
- if (offset > 0) {
- sign = '-';
- } else {
- offset = -offset;
- sign = '+';
- }
- sprintf(buf, (const char *)"GMT%c%02d:%02d",
- sign, (int)(offset/3600), (int)((offset%3600)/60));
- return strdup(buf);
-}
-#endif /* MACOSX */
-
-#ifdef _AIX
static char *
mapPlatformToJavaTimezone(const char *java_home_dir, const char *tz) {
FILE *tzmapf;
- char mapfilename[PATH_MAX+1];
+ char mapfilename[PATH_MAX + 1];
char line[256];
int linecount = 0;
- char temp[100], *temp_tz;
+ char *tz_buf = NULL;
+ char *temp_tz = NULL;
char *javatz = NULL;
- char *str_tmp = NULL;
- size_t temp_tz_len = 0;
+ size_t tz_len = 0;
/* On AIX, the TZ environment variable may end with a comma
- * followed by modifier fields. These are ignored here.
- */
- strncpy(temp, tz, 100);
- temp_tz = strtok_r(temp, ",", &str_tmp);
+ * followed by modifier fields. These are ignored here. */
+ temp_tz = strchr(tz, ',');
+ tz_len = (temp_tz == NULL) ? strlen(tz) : temp_tz - tz;
+ tz_buf = (char *)malloc(tz_len + 1);
+ memcpy(tz_buf, tz, tz_len);
+ tz_buf[tz_len] = 0;
- if(temp_tz == NULL)
- goto tzerr;
-
- temp_tz_len = strlen(temp_tz);
-
- if (strlen(java_home_dir) >= (PATH_MAX - 15)) {
- jio_fprintf(stderr, "java.home longer than maximum path length \n");
+ /* Open tzmappings file, with buffer overrun check */
+ if ((strlen(java_home_dir) + 15) > PATH_MAX) {
+ jio_fprintf(stderr, "Path %s/lib/tzmappings exceeds maximum path length\n", java_home_dir);
goto tzerr;
}
-
- strncpy(mapfilename, java_home_dir, PATH_MAX);
+ strcpy(mapfilename, java_home_dir);
strcat(mapfilename, "/lib/tzmappings");
-
if ((tzmapf = fopen(mapfilename, "r")) == NULL) {
jio_fprintf(stderr, "can't open %s\n", mapfilename);
goto tzerr;
@@ -845,7 +705,7 @@
}
*p++ = '\0';
- if ((result = strncmp(temp_tz, sol, temp_tz_len)) == 0) {
+ if ((result = strncmp(tz_buf, sol, tz_len)) == 0) {
/*
* If this is the current platform zone ID,
* take the Java time zone ID (2nd field).
@@ -871,11 +731,150 @@
(void) fclose(tzmapf);
tzerr:
+ if (tz_buf != NULL ) {
+ free((void *) tz_buf);
+ }
+
if (javatz == NULL) {
return getGMTOffsetID();
}
return javatz;
}
+
+#endif /* defined(_AIX) */
+
+/*
+ * findJavaTZ_md() maps platform time zone ID to Java time zone ID
+ * using <java_home>/lib/tzmappings. If the TZ value is not found, it
+ * trys some libc implementation dependent mappings. If it still
+ * can't map to a Java time zone ID, it falls back to the GMT+/-hh:mm
+ * form.
+ */
+/*ARGSUSED1*/
+char *
+findJavaTZ_md(const char *java_home_dir)
+{
+ char *tz;
+ char *javatz = NULL;
+ char *freetz = NULL;
+
+ tz = getenv("TZ");
+
+ if (tz == NULL || *tz == '\0') {
+ tz = getPlatformTimeZoneID();
+ freetz = tz;
+ }
+
+ if (tz != NULL) {
+ /* Ignore preceding ':' */
+ if (*tz == ':') {
+ tz++;
+ }
+#if defined(__linux__)
+ /* Ignore "posix/" prefix on Linux. */
+ if (strncmp(tz, "posix/", 6) == 0) {
+ tz += 6;
+ }
#endif
+#if defined(_AIX)
+ /* On AIX do the platform to Java mapping. */
+ javatz = mapPlatformToJavaTimezone(java_home_dir, tz);
+ if (freetz != NULL) {
+ free((void *) freetz);
+ }
+#else
+#if defined(__solaris__)
+ /* Solaris might use localtime, so handle it here. */
+ if (strcmp(tz, "localtime") == 0) {
+ javatz = getSolarisDefaultZoneID();
+ if (freetz != NULL) {
+ free((void *) freetz);
+ }
+ } else
+#endif
+ if (freetz == NULL) {
+ /* strdup if we are still working on getenv result. */
+ javatz = strdup(tz);
+ } else if (freetz != tz) {
+ /* strdup and free the old buffer, if we moved the pointer. */
+ javatz = strdup(tz);
+ free((void *) freetz);
+ } else {
+ /* we are good if we already work on a freshly allocated buffer. */
+ javatz = tz;
+ }
+#endif
+ }
+
+ return javatz;
+}
+
+/**
+ * Returns a GMT-offset-based zone ID. (e.g., "GMT-08:00")
+ */
+
+#if defined(MACOSX)
+
+char *
+getGMTOffsetID()
+{
+ time_t offset;
+ char sign, buf[32];
+ struct tm *local_tm;
+ time_t clock;
+ time_t currenttime;
+
+ clock = time(NULL);
+ tzset();
+ local_tm = localtime(&clock);
+ if (local_tm->tm_gmtoff >= 0) {
+ offset = (time_t) local_tm->tm_gmtoff;
+ sign = '+';
+ } else {
+ offset = (time_t) -local_tm->tm_gmtoff;
+ sign = '-';
+ }
+ sprintf(buf, (const char *)"GMT%c%02d:%02d",
+ sign, (int)(offset/3600), (int)((offset%3600)/60));
+ return strdup(buf);
+}
+
+#else
+
+char *
+getGMTOffsetID()
+{
+ time_t offset;
+ char sign, buf[32];
+#if defined(__solaris__)
+ struct tm localtm;
+ time_t currenttime;
+
+ currenttime = time(NULL);
+ if (localtime_r(¤ttime, &localtm) == NULL) {
+ return NULL;
+ }
+
+ offset = localtm.tm_isdst ? altzone : timezone;
+#else
+ offset = timezone;
+#endif
+
+ if (offset == 0) {
+ return strdup("GMT");
+ }
+
+ /* Note that the time offset direction is opposite. */
+ if (offset > 0) {
+ sign = '-';
+ } else {
+ offset = -offset;
+ sign = '+';
+ }
+ sprintf(buf, (const char *)"GMT%c%02d:%02d",
+ sign, (int)(offset/3600), (int)((offset%3600)/60));
+ return strdup(buf);
+}
+#endif /* MACOSX */
diff --git a/jdk/src/solaris/native/sun/awt/fontpath.c b/jdk/src/solaris/native/sun/awt/fontpath.c
index ba19317..674931b 100644
--- a/jdk/src/solaris/native/sun/awt/fontpath.c
+++ b/jdk/src/solaris/native/sun/awt/fontpath.c
@@ -497,7 +497,7 @@
* This also frees us from X11 APIs as JRE is required to function in
* a "headless" mode where there is no Xserver.
*/
-static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1) {
+static char *getPlatformFontPathChars(JNIEnv *env, jboolean noType1, jboolean isX11) {
char **fcdirs = NULL, **x11dirs = NULL, **knowndirs = NULL, *path = NULL;
@@ -519,6 +519,7 @@
* be initialised.
*/
#ifndef HEADLESS
+ if (isX11) { // The following only works in an x11 environment.
#if defined(__linux__)
/* There's no headless build on linux ... */
if (!AWTIsHeadless()) { /* .. so need to call a function to check */
@@ -538,6 +539,7 @@
#if defined(__linux__)
}
#endif
+ }
#endif /* !HEADLESS */
path = mergePaths(fcdirs, x11dirs, knowndirs, noType1);
if (fcdirs != NULL) {
@@ -555,13 +557,13 @@
return path;
}
-JNIEXPORT jstring JNICALL Java_sun_awt_X11FontManager_getFontPathNative
-(JNIEnv *env, jobject thiz, jboolean noType1) {
+JNIEXPORT jstring JNICALL Java_sun_awt_FcFontManager_getFontPathNative
+(JNIEnv *env, jobject thiz, jboolean noType1, jboolean isX11) {
jstring ret;
static char *ptr = NULL; /* retain result across calls */
if (ptr == NULL) {
- ptr = getPlatformFontPathChars(env, noType1);
+ ptr = getPlatformFontPathChars(env, noType1, isX11);
}
ret = (*env)->NewStringUTF(env, ptr);
return ret;
@@ -1217,10 +1219,11 @@
minGlyphs = val;
}
}
+ FcCharSet *unionCharset = NULL;
for (j=0; j<nfonts; j++) {
FcPattern *fontPattern = fontset->fonts[j];
FcChar8 *fontformat;
- FcCharSet *unionCharset = NULL, *charset;
+ FcCharSet *charset = NULL;
fontformat = NULL;
(*FcPatternGetString)(fontPattern, FC_FONTFORMAT, 0, &fontformat);
@@ -1278,6 +1281,9 @@
if (!includeFallbacks) {
break;
}
+ if (fontCount == 254) {
+ break; // CompositeFont will only use up to 254 slots from here.
+ }
}
/* Once we get here 'fontCount' is the number of returned fonts
diff --git a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c
index 2f205c5..7bdaa52 100644
--- a/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c
+++ b/jdk/src/solaris/native/sun/management/LinuxOperatingSystem.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -76,14 +76,17 @@
static int get_totalticks(int which, ticks *pticks) {
FILE *fh;
uint64_t userTicks, niceTicks, systemTicks, idleTicks;
+ uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0;
int n;
if((fh = fopen("/proc/stat", "r")) == NULL) {
return -1;
}
- n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64,
- &userTicks, &niceTicks, &systemTicks, &idleTicks);
+ n = fscanf(fh, "cpu " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64,
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks);
// Move to next line
next_line(fh);
@@ -92,24 +95,30 @@
if (which != -1) {
int i;
for (i = 0; i < which; i++) {
- if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64, &userTicks, &niceTicks, &systemTicks, &idleTicks) != 4) {
+ if (fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64 " " DEC_64,
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks) < 4) {
fclose(fh);
return -2;
}
next_line(fh);
}
- n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 "\n",
- &userTicks, &niceTicks, &systemTicks, &idleTicks);
+ n = fscanf(fh, "cpu%*d " DEC_64 " " DEC_64 " " DEC_64 " " DEC_64 " "
+ DEC_64 " " DEC_64 " " DEC_64 "\n",
+ &userTicks, &niceTicks, &systemTicks, &idleTicks,
+ &iowTicks, &irqTicks, &sirqTicks);
}
fclose(fh);
- if (n != 4) {
+ if (n < 4) {
return -2;
}
pticks->used = userTicks + niceTicks;
- pticks->usedKernel = systemTicks;
- pticks->total = userTicks + niceTicks + systemTicks + idleTicks;
+ pticks->usedKernel = systemTicks + irqTicks + sirqTicks;
+ pticks->total = userTicks + niceTicks + systemTicks + idleTicks +
+ iowTicks + irqTicks + sirqTicks;
return 0;
}
diff --git a/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
index e8a1623..2799f9a 100644
--- a/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
+++ b/jdk/src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
@@ -308,21 +308,15 @@
JNIEXPORT jbyteArray
Java_sun_nio_fs_UnixNativeDispatcher_strerror(JNIEnv* env, jclass this, jint error)
{
- char* msg;
+ char tmpbuf[1024];
jsize len;
jbyteArray bytes;
-#ifdef _AIX
- /* strerror() is not thread-safe on AIX so we have to use strerror_r() */
- char buffer[256];
- msg = (strerror_r((int)error, buffer, 256) == 0) ? buffer : "Error while calling strerror_r";
-#else
- msg = strerror((int)error);
-#endif
- len = strlen(msg);
+ getErrorString((int)errno, tmpbuf, sizeof(tmpbuf));
+ len = strlen(tmpbuf);
bytes = (*env)->NewByteArray(env, len);
if (bytes != NULL) {
- (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)msg);
+ (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)tmpbuf);
}
return bytes;
}
diff --git a/jdk/src/windows/classes/java/net/DefaultDatagramSocketImplFactory.java b/jdk/src/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
index 62bf21e..84cdf5b 100644
--- a/jdk/src/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
+++ b/jdk/src/windows/classes/java/net/DefaultDatagramSocketImplFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -45,7 +45,7 @@
class DefaultDatagramSocketImplFactory
{
- static Class<?> prefixImplClass = null;
+ private final static Class<?> prefixImplClass;
/* the windows version. */
private static float version;
@@ -54,16 +54,19 @@
private static boolean preferIPv4Stack = false;
/* If the version supports a dual stack TCP implementation */
- private static boolean useDualStackImpl = false;
+ private final static boolean useDualStackImpl;
/* sun.net.useExclusiveBind */
private static String exclBindProp;
/* True if exclusive binding is on for Windows */
- private static boolean exclusiveBind = true;
-
+ private final static boolean exclusiveBind;
static {
+ Class<?> prefixImplClassLocal = null;
+ boolean useDualStackImplLocal = false;
+ boolean exclusiveBindLocal = true;
+
// Determine Windows Version.
java.security.AccessController.doPrivileged(
new PrivilegedAction<Object>() {
@@ -78,7 +81,7 @@
"java.net.preferIPv4Stack"));
exclBindProp = System.getProperty(
"sun.net.useExclusiveBind");
- } catch (NumberFormatException e ) {
+ } catch (NumberFormatException e) {
assert false : e;
}
return null; // nothing to return
@@ -87,14 +90,14 @@
// (version >= 6.0) implies Vista or greater.
if (version >= 6.0 && !preferIPv4Stack) {
- useDualStackImpl = true;
+ useDualStackImplLocal = true;
}
if (exclBindProp != null) {
// sun.net.useExclusiveBind is true
- exclusiveBind = exclBindProp.length() == 0 ? true
+ exclusiveBindLocal = exclBindProp.length() == 0 ? true
: Boolean.parseBoolean(exclBindProp);
} else if (version < 6.0) {
- exclusiveBind = false;
+ exclusiveBindLocal = false;
}
// impl.prefix
@@ -103,12 +106,16 @@
prefix = AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("impl.prefix", null));
if (prefix != null)
- prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
+ prefixImplClassLocal = Class.forName("java.net."+prefix+"DatagramSocketImpl");
} catch (Exception e) {
System.err.println("Can't find class: java.net." +
prefix +
"DatagramSocketImpl: check impl.prefix property");
}
+
+ prefixImplClass = prefixImplClassLocal;
+ useDualStackImpl = useDualStackImplLocal;
+ exclusiveBind = exclusiveBindLocal;
}
/**
@@ -126,12 +133,10 @@
throw new SocketException("can't instantiate DatagramSocketImpl");
}
} else {
- if (isMulticast)
- exclusiveBind = false;
if (useDualStackImpl && !isMulticast)
return new DualStackPlainDatagramSocketImpl(exclusiveBind);
else
- return new TwoStacksPlainDatagramSocketImpl(exclusiveBind);
+ return new TwoStacksPlainDatagramSocketImpl(exclusiveBind && !isMulticast);
}
}
}
diff --git a/jdk/src/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java b/jdk/src/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java
index 9c7ca9d..725337e 100644
--- a/jdk/src/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java
+++ b/jdk/src/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -45,6 +45,10 @@
{
static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
+ static {
+ initIDs();
+ }
+
// true if this socket is exclusively bound
private final boolean exclusiveBind;
@@ -288,4 +292,6 @@
int optionValue) throws SocketException;
private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
+
+ native int dataAvailable();
}
diff --git a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
index fc17f82..750abbf 100644
--- a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
+++ b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -207,6 +207,8 @@
protected native void disconnect0(int family);
+ native int dataAvailable();
+
/**
* Perform class load-time initializations.
*/
diff --git a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java
index 87bd76e..b92dd90 100644
--- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java
+++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java
@@ -248,14 +248,6 @@
}
}
- @SuppressWarnings("deprecation")
- public boolean requestFocusToEmbedder() {
- if (isEmbeddedInIE) {
- return ((WEmbeddedFramePeer) getPeer()).requestFocusToEmbedder();
- }
- return false;
- }
-
public void registerAccelerator(AWTKeyStroke stroke) {}
public void unregisterAccelerator(AWTKeyStroke stroke) {}
diff --git a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java
index 4cc3a4d..c0ef8a7 100644
--- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java
+++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFramePeer.java
@@ -79,10 +79,4 @@
return !Win32GraphicsEnvironment.isDWMCompositionEnabled();
}
- /**
- * Sets the focus to plugin control window, the parent of embedded frame.
- * Eventually, it will synthesizeWindowActivation to activate the embedded frame,
- * if plugin control window gets the focus.
- */
- public native boolean requestFocusToEmbedder();
}
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java
index f691ad5..5144ab8 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java
@@ -98,6 +98,7 @@
public static final int ERROR_DISK_FULL = 112;
public static final int ERROR_INSUFFICIENT_BUFFER = 122;
public static final int ERROR_INVALID_LEVEL = 124;
+ public static final int ERROR_DIR_NOT_ROOT = 144;
public static final int ERROR_DIR_NOT_EMPTY = 145;
public static final int ERROR_ALREADY_EXISTS = 183;
public static final int ERROR_MORE_DATA = 234;
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java
index a18af6d..18434b93 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileStore.java
@@ -86,14 +86,28 @@
WindowsFileAttributes.get(file, true);
target = file.getPathForWin32Calls();
}
- String root = GetVolumePathName(target);
- return new WindowsFileStore(root);
+ try {
+ return createFromPath(target);
+ } catch (WindowsException e) {
+ if (e.lastError() != ERROR_DIR_NOT_ROOT)
+ throw e;
+ target = WindowsLinkSupport.getFinalPath(file);
+ if (target == null)
+ throw new FileSystemException(file.getPathForExceptionMessage(),
+ null, "Couldn't resolve path");
+ return createFromPath(target);
+ }
} catch (WindowsException x) {
x.rethrowAsIOException(file);
return null; // keep compiler happy
}
}
+ private static WindowsFileStore createFromPath(String target) throws WindowsException {
+ String root = GetVolumePathName(target);
+ return new WindowsFileStore(root);
+ }
+
VolumeInformation volumeInformation() {
return volInfo;
}
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java
index 97dc347..56f996d 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsLinkSupport.java
@@ -66,7 +66,7 @@
* Returns the final path (all symbolic links resolved) or null if this
* operation is not supported.
*/
- private static String getFinalPath(WindowsPath input) throws IOException {
+ static String getFinalPath(WindowsPath input) throws IOException {
long h = 0;
try {
h = input.openForReadAttributeAccess(true);
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
index a380c3d..47d28f8 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java
@@ -37,6 +37,17 @@
private WindowsNativeDispatcher() { }
/**
+ * HANDLE CreateEvent(
+ * LPSECURITY_ATTRIBUTES lpEventAttributes,
+ * BOOL bManualReset,
+ * BOOL bInitialState,
+ * PCTSTR lpName
+ * );
+ */
+ static native long CreateEvent(boolean bManualReset, boolean bInitialState)
+ throws WindowsException;
+
+ /**
* HANDLE CreateFile(
* LPCTSTR lpFileName,
* DWORD dwDesiredAccess,
@@ -1041,6 +1052,25 @@
long pOverlapped)
throws WindowsException;
+
+ /**
+ * CancelIo(
+ * HANDLE hFile
+ * )
+ */
+ static native void CancelIo(long hFile) throws WindowsException;
+
+ /**
+ * GetOverlappedResult(
+ * HANDLE hFile,
+ * LPOVERLAPPED lpOverlapped,
+ * LPDWORD lpNumberOfBytesTransferred,
+ * BOOL bWait
+ * );
+ */
+ static native int GetOverlappedResult(long hFile, long lpOverlapped)
+ throws WindowsException;
+
/**
* BackupRead(
* HANDLE hFile,
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java
index 4ad1024..cf3a6de 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java
@@ -25,9 +25,16 @@
package sun.nio.fs;
-import java.nio.file.*;
import java.io.IOException;
-import java.util.*;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchKey;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
import com.sun.nio.file.ExtendedWatchEventModifier;
import sun.misc.Unsafe;
@@ -42,7 +49,6 @@
extends AbstractWatchService
{
private final static int WAKEUP_COMPLETION_KEY = 0;
- private final Unsafe unsafe = Unsafe.getUnsafe();
// background thread to service I/O completion port
private final Poller poller;
@@ -82,7 +88,7 @@
/**
* Windows implementation of WatchKey.
*/
- private class WindowsWatchKey extends AbstractWatchKey {
+ private static class WindowsWatchKey extends AbstractWatchKey {
// file key (used to detect existing registrations)
private final FileKey fileKey;
@@ -169,15 +175,9 @@
return completionKey;
}
- // close directory and release buffer
- void releaseResources() {
- CloseHandle(handle);
- buffer.cleaner().clean();
- }
-
- // Invalidate key by closing directory and releasing buffer
+ // Invalidate the key, assumes that resources have been released
void invalidate() {
- releaseResources();
+ ((WindowsWatchService)watcher()).poller.releaseResources(this);
handle = INVALID_HANDLE_VALUE;
buffer = null;
countAddress = 0;
@@ -193,7 +193,7 @@
public void cancel() {
if (isValid()) {
// delegate to poller
- poller.cancel(this);
+ ((WindowsWatchService)watcher()).poller.cancel(this);
}
}
}
@@ -241,18 +241,25 @@
/**
* Background thread to service I/O completion port.
*/
- private class Poller extends AbstractPoller {
+ private static class Poller extends AbstractPoller {
+ private final static Unsafe UNSAFE = Unsafe.getUnsafe();
+
/*
* typedef struct _OVERLAPPED {
- * DWORD Internal;
- * DWORD InternalHigh;
- * DWORD Offset;
- * DWORD OffsetHigh;
- * HANDLE hEvent;
+ * ULONG_PTR Internal;
+ * ULONG_PTR InternalHigh;
+ * union {
+ * struct { DWORD Offset; DWORD OffsetHigh; };
+ * PVOID Pointer;
+ * };
+ * HANDLE hEvent;
* } OVERLAPPED;
*/
private static final short SIZEOF_DWORD = 4;
private static final short SIZEOF_OVERLAPPED = 32; // 20 on 32-bit
+ private static final short OFFSETOF_HEVENT =
+ (UNSAFE.addressSize() == 4) ? (short) 16 : 24;
+
/*
* typedef struct _FILE_NOTIFY_INFORMATION {
@@ -276,10 +283,10 @@
private final long port;
// maps completion key to WatchKey
- private final Map<Integer,WindowsWatchKey> ck2key;
+ private final Map<Integer, WindowsWatchKey> ck2key;
// maps file key to WatchKey
- private final Map<FileKey,WindowsWatchKey> fk2key;
+ private final Map<FileKey, WindowsWatchKey> fk2key;
// unique completion key for each directory
// native completion key capacity is 64 bits on Win64.
@@ -393,8 +400,13 @@
long overlappedAddress = bufferAddress + size - SIZEOF_OVERLAPPED;
long countAddress = overlappedAddress - SIZEOF_DWORD;
+ // zero the overlapped structure
+ UNSAFE.setMemory(overlappedAddress, SIZEOF_OVERLAPPED, (byte)0);
+
// start async read of changes to directory
try {
+ createAndAttachEvent(overlappedAddress);
+
ReadDirectoryChangesW(handle,
bufferAddress,
CHANGES_BUFFER_SIZE,
@@ -403,6 +415,7 @@
countAddress,
overlappedAddress);
} catch (WindowsException x) {
+ closeAttachedEvent(overlappedAddress);
buffer.release();
return new IOException(x.getMessage());
}
@@ -421,7 +434,7 @@
// 2. release existing key's resources (handle/buffer)
// 3. re-initialize key with new handle/buffer
ck2key.remove(existing.completionKey());
- existing.releaseResources();
+ releaseResources(existing);
watchKey = existing.init(handle, events, watchSubtree, buffer,
countAddress, overlappedAddress, completionKey);
}
@@ -436,6 +449,42 @@
}
}
+ /**
+ * Cancels the outstanding I/O operation on the directory
+ * associated with the given key and releases the associated
+ * resources.
+ */
+ private void releaseResources(WindowsWatchKey key) {
+ try {
+ CancelIo(key.handle());
+ GetOverlappedResult(key.handle(), key.overlappedAddress());
+ } catch (WindowsException expected) {
+ // expected as I/O operation has been cancelled
+ }
+ CloseHandle(key.handle());
+ closeAttachedEvent(key.overlappedAddress());
+ key.buffer().cleaner().clean();
+ }
+
+ /**
+ * Creates an unnamed event and set it as the hEvent field
+ * in the given OVERLAPPED structure
+ */
+ private void createAndAttachEvent(long ov) throws WindowsException {
+ long hEvent = CreateEvent(false, false);
+ UNSAFE.putAddress(ov + OFFSETOF_HEVENT, hEvent);
+ }
+
+ /**
+ * Closes the event attached to the given OVERLAPPED structure. A
+ * no-op if there isn't an event attached.
+ */
+ private void closeAttachedEvent(long ov) {
+ long hEvent = UNSAFE.getAddress(ov + OFFSETOF_HEVENT);
+ if (hEvent != 0 && hEvent != INVALID_HANDLE_VALUE)
+ CloseHandle(hEvent);
+ }
+
// cancel single key
@Override
void implCancelKey(WatchKey obj) {
@@ -451,9 +500,8 @@
@Override
void implCloseAll() {
// cancel all keys
- for (Map.Entry<Integer, WindowsWatchKey> entry: ck2key.entrySet()) {
- entry.getValue().invalidate();
- }
+ ck2key.values().forEach(WindowsWatchKey::invalidate);
+
fk2key.clear();
ck2key.clear();
@@ -462,8 +510,7 @@
}
// Translate file change action into watch event
- private WatchEvent.Kind<?> translateActionToEvent(int action)
- {
+ private WatchEvent.Kind<?> translateActionToEvent(int action) {
switch (action) {
case FILE_ACTION_MODIFIED :
return StandardWatchEventKinds.ENTRY_MODIFY;
@@ -487,18 +534,18 @@
int nextOffset;
do {
- int action = unsafe.getInt(address + OFFSETOF_ACTION);
+ int action = UNSAFE.getInt(address + OFFSETOF_ACTION);
// map action to event
WatchEvent.Kind<?> kind = translateActionToEvent(action);
if (key.events().contains(kind)) {
// copy the name
- int nameLengthInBytes = unsafe.getInt(address + OFFSETOF_FILENAMELENGTH);
+ int nameLengthInBytes = UNSAFE.getInt(address + OFFSETOF_FILENAMELENGTH);
if ((nameLengthInBytes % 2) != 0) {
- throw new AssertionError("FileNameLength.FileNameLength is not a multiple of 2");
+ throw new AssertionError("FileNameLength is not a multiple of 2");
}
char[] nameAsArray = new char[nameLengthInBytes/2];
- unsafe.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray,
+ UNSAFE.copyMemory(null, address + OFFSETOF_FILENAME, nameAsArray,
Unsafe.ARRAY_CHAR_BASE_OFFSET, nameLengthInBytes);
// create FileName and queue event
@@ -508,7 +555,7 @@
}
// next event
- nextOffset = unsafe.getInt(address + OFFSETOF_NEXTENTRYOFFSET);
+ nextOffset = UNSAFE.getInt(address + OFFSETOF_NEXTENTRYOFFSET);
address += (long)nextOffset;
} while (nextOffset != 0);
}
diff --git a/jdk/src/windows/native/common/jni_util_md.c b/jdk/src/windows/native/common/jni_util_md.c
index cdaaa2b..161b903 100644
--- a/jdk/src/windows/native/common/jni_util_md.c
+++ b/jdk/src/windows/native/common/jni_util_md.c
@@ -142,6 +142,15 @@
return (void*)GetModuleHandle(NULL);
}
+int
+getErrorString(int err, char *buf, size_t len)
+{
+ int ret = 0;
+ if (err == 0 || len < 1) return 0;
+ ret = strerror_s(buf, len, err);
+ return ret;
+}
+
/*
* Windows symbols can be simple like JNI_OnLoad or __stdcall format
* like _JNI_OnLoad@8. We need to handle both.
diff --git a/jdk/src/windows/native/java/net/AbstractPlainDatagramSocketImpl.c b/jdk/src/windows/native/java/net/AbstractPlainDatagramSocketImpl.c
deleted file mode 100644
index dd2c7e8..0000000
--- a/jdk/src/windows/native/java/net/AbstractPlainDatagramSocketImpl.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include <windows.h>
-#include <winsock2.h>
-
-#include "jvm.h"
-#include "jni_util.h"
-#include "net_util.h"
-
-#include "java_net_AbstractPlainDatagramSocketImpl.h"
-
-static jfieldID IO_fd_fdID = NULL;
-static jfieldID apdsi_fdID = NULL;
-
-static jfieldID apdsi_fd1ID = NULL;
-static jclass two_stacks_clazz = NULL;
-
-
-/*
- * Class: java_net_AbstractPlainDatagramSocketImpl
- * Method: init
- * Signature: ()V
- */
-JNIEXPORT void JNICALL
-Java_java_net_AbstractPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
-
- apdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
- "Ljava/io/FileDescriptor;");
- CHECK_NULL(apdsi_fdID);
- IO_fd_fdID = NET_GetFileDescriptorID(env);
- CHECK_NULL(IO_fd_fdID);
-
- two_stacks_clazz = (*env)->FindClass(env, "java/net/TwoStacksPlainDatagramSocketImpl");
- CHECK_NULL(two_stacks_clazz);
-
- /* Handle both TwoStacks and DualStack here */
-
- if (JNU_Equals(env, cls, two_stacks_clazz)) {
- /* fd1 present only in TwoStack.. */
- apdsi_fd1ID = (*env)->GetFieldID(env, cls, "fd1",
- "Ljava/io/FileDescriptor;");
- CHECK_NULL(apdsi_fd1ID);
- }
-
- JNU_CHECK_EXCEPTION(env);
-}
-
-/*
- * Class: java_net_AbstractPlainDatagramSocketImpl
- * Method: dataAvailable
- * Signature: ()I
- */
-JNIEXPORT jint JNICALL Java_java_net_AbstractPlainDatagramSocketImpl_dataAvailable
-(JNIEnv *env, jobject this) {
- SOCKET fd;
- SOCKET fd1;
- int rv = -1, rv1 = -1;
- jobject fdObj = (*env)->GetObjectField(env, this, apdsi_fdID);
-
- if (!IS_NULL(fdObj)) {
- int retval = 0;
- fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
- rv = ioctlsocket(fd, FIONREAD, &retval);
- if (retval > 0) {
- return retval;
- }
- }
-
- if (!IS_NULL(apdsi_fd1ID)) {
- /* TwoStacks */
- jobject fd1Obj = (*env)->GetObjectField(env, this, apdsi_fd1ID);
- if (!IS_NULL(fd1Obj)) {
- int retval = 0;
- fd1 = (SOCKET)(*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
- rv1 = ioctlsocket(fd1, FIONREAD, &retval);
- if (retval > 0) {
- return retval;
- }
- }
- }
-
- if (rv < 0 && rv1 < 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- return -1;
- }
-
- return 0;
-}
-
diff --git a/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c b/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
index 108f0de..23d7ce2 100644
--- a/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
+++ b/jdk/src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -70,6 +70,25 @@
return got_icmp;
}
+static jfieldID IO_fd_fdID = NULL;
+static jfieldID pdsi_fdID = NULL;
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_initIDs
+ (JNIEnv *env, jclass clazz)
+{
+ pdsi_fdID = (*env)->GetFieldID(env, clazz, "fd",
+ "Ljava/io/FileDescriptor;");
+ CHECK_NULL(pdsi_fdID);
+ IO_fd_fdID = NET_GetFileDescriptorID(env);
+ CHECK_NULL(IO_fd_fdID);
+ JNU_CHECK_EXCEPTION(env);
+}
+
/*
* Class: java_net_DualStackPlainDatagramSocketImpl
* Method: socketCreate
@@ -498,3 +517,32 @@
return result;
}
+
+/*
+ * Class: java_net_DualStackPlainDatagramSocketImpl
+ * Method: dataAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_dataAvailable
+(JNIEnv *env, jobject this) {
+ SOCKET fd;
+ int rv = -1;
+ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
+
+ if (!IS_NULL(fdObj)) {
+ int retval = 0;
+ fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ rv = ioctlsocket(fd, FIONREAD, &retval);
+ if (retval > 0) {
+ return retval;
+ }
+ }
+
+ if (rv < 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/jdk/src/windows/native/java/net/Inet4AddressImpl.c b/jdk/src/windows/native/java/net/Inet4AddressImpl.c
index f23d0d2..71d2682 100644
--- a/jdk/src/windows/native/java/net/Inet4AddressImpl.c
+++ b/jdk/src/windows/native/java/net/Inet4AddressImpl.c
@@ -31,6 +31,8 @@
#include <malloc.h>
#include <sys/types.h>
#include <process.h>
+#include <iphlpapi.h>
+#include <icmpapi.h>
#include "java_net_InetAddress.h"
#include "java_net_Inet4AddressImpl.h"
@@ -297,114 +299,65 @@
* Returns true is an ECHO_REPLY is received, otherwise, false.
*/
static jboolean
-ping4(JNIEnv *env, jint fd, struct sockaddr_in* him, jint timeout,
- struct sockaddr_in* netif, jint ttl) {
- jint size;
- jint n, len, hlen1, icmplen;
- char sendbuf[1500];
- char recvbuf[1500];
- struct icmp *icmp;
- struct ip *ip;
- WSAEVENT hEvent;
- struct sockaddr sa_recv;
- jint tmout2;
- u_short pid, seq;
- int read_rv = 0;
+ping4(JNIEnv *env,
+ unsigned long src_addr,
+ unsigned long dest_addr,
+ jint timeout)
+{
+ // See https://msdn.microsoft.com/en-us/library/aa366050%28VS.85%29.aspx
- /* Initialize the sequence number to a suitable random number and
- shift right one place to allow sufficient room for increamenting. */
- seq = ((unsigned short)rand()) >> 1;
+ HANDLE hIcmpFile;
+ DWORD dwRetVal = 0;
+ char SendData[32] = {0};
+ LPVOID ReplyBuffer = NULL;
+ DWORD ReplySize = 0;
- /* icmp_id is a 16 bit data type, therefore down cast the pid */
- pid = (u_short) _getpid();
- size = 60*1024;
- setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *) &size, sizeof(size));
- /**
- * A TTL was specified, let's set the socket option.
- */
- if (ttl > 0) {
- setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *) &ttl, sizeof(ttl));
+ hIcmpFile = IcmpCreateFile();
+ if (hIcmpFile == INVALID_HANDLE_VALUE) {
+ NET_ThrowNew(env, WSAGetLastError(), "Unable to open handle");
+ return JNI_FALSE;
}
- /**
- * A network interface was specified, let's bind to it.
- */
- if (netif != NULL) {
- if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
- closesocket(fd);
+ ReplySize = sizeof(ICMP_ECHO_REPLY) + sizeof(SendData);
+ ReplyBuffer = (VOID*) malloc(ReplySize);
+ if (ReplyBuffer == NULL) {
+ IcmpCloseHandle(hIcmpFile);
+ NET_ThrowNew(env, WSAGetLastError(), "Unable to allocate memory");
return JNI_FALSE;
- }
}
- /**
- * Let's make the socket non blocking
- */
- hEvent = WSACreateEvent();
- WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
+ if (src_addr == 0) {
+ dwRetVal = IcmpSendEcho(hIcmpFile, // HANDLE IcmpHandle,
+ dest_addr, // IPAddr DestinationAddress,
+ SendData, // LPVOID RequestData,
+ sizeof(SendData), // WORD RequestSize,
+ NULL, // PIP_OPTION_INFORMATION RequestOptions,
+ ReplyBuffer,// LPVOID ReplyBuffer,
+ ReplySize, // DWORD ReplySize,
+ timeout); // DWORD Timeout
+ } else {
+ dwRetVal = IcmpSendEcho2Ex(hIcmpFile, // HANDLE IcmpHandle,
+ NULL, // HANDLE Event
+ NULL, // PIO_APC_ROUTINE ApcRoutine
+ NULL, // ApcContext
+ src_addr, // IPAddr SourceAddress,
+ dest_addr, // IPAddr DestinationAddress,
+ SendData, // LPVOID RequestData,
+ sizeof(SendData), // WORD RequestSize,
+ NULL, // PIP_OPTION_INFORMATION RequestOptions,
+ ReplyBuffer,// LPVOID ReplyBuffer,
+ ReplySize, // DWORD ReplySize,
+ timeout); // DWORD Timeout
+ }
- /**
- * send 1 ICMP REQUEST every second until either we get a valid reply
- * or the timeout expired.
- */
- do {
- /**
- * construct the ICMP header
- */
- memset(sendbuf, 0, 1500);
- icmp = (struct icmp *) sendbuf;
- icmp->icmp_type = ICMP_ECHO;
- icmp->icmp_code = 0;
- icmp->icmp_id = htons(pid);
- icmp->icmp_seq = htons(seq);
- /**
- * checksum has to be set to zero before we can calculate the
- * real checksum!
- */
- icmp->icmp_cksum = 0;
- icmp->icmp_cksum = in_cksum((u_short *)icmp, 64);
- /**
- * Ping!
- */
- n = sendto(fd, sendbuf, 64, 0, (struct sockaddr *)him,
- sizeof(struct sockaddr));
- if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
- NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet");
- closesocket(fd);
- WSACloseEvent(hEvent);
+ free(ReplyBuffer);
+ IcmpCloseHandle(hIcmpFile);
+
+ if (dwRetVal != 0) {
+ return JNI_TRUE;
+ } else {
return JNI_FALSE;
- }
-
- /*
- * wait for 1 second at most
- */
- tmout2 = timeout > 1000 ? 1000 : timeout;
- do {
- tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
- if (tmout2 >= 0) {
- len = sizeof(sa_recv);
- n = recvfrom(fd, recvbuf, sizeof(recvbuf), 0, &sa_recv, &len);
- ip = (struct ip*) recvbuf;
- hlen1 = (ip->ip_hl) << 2;
- icmp = (struct icmp *) (recvbuf + hlen1);
- icmplen = n - hlen1;
- /**
- * Is that a proper ICMP reply?
- */
- if (icmplen >= 8 && icmp->icmp_type == ICMP_ECHOREPLY &&
- (ntohs(icmp->icmp_seq) == seq) && (ntohs(icmp->icmp_id) == pid)) {
- closesocket(fd);
- WSACloseEvent(hEvent);
- return JNI_TRUE;
- }
- }
- } while (tmout2 > 0);
- timeout -= 1000;
- seq++;
- } while (timeout > 0);
- closesocket(fd);
- WSACloseEvent(hEvent);
- return JNI_FALSE;
+ }
}
/*
@@ -418,15 +371,9 @@
jint timeout,
jbyteArray ifArray,
jint ttl) {
- jint addr;
+ jint src_addr = 0;
+ jint dest_addr = 0;
jbyte caddr[4];
- jint fd;
- struct sockaddr_in him;
- struct sockaddr_in* netif = NULL;
- struct sockaddr_in inf;
- int len = 0;
- WSAEVENT hEvent;
- int connect_rv = -1;
int sz;
/**
@@ -436,143 +383,27 @@
if (sz != 4) {
return JNI_FALSE;
}
- memset((char *) &him, 0, sizeof(him));
memset((char *) caddr, 0, sizeof(caddr));
(*env)->GetByteArrayRegion(env, addrArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
- addr |= (caddr[3] & 0xff);
- addr = htonl(addr);
- /**
- * Socket address
- */
- him.sin_addr.s_addr = addr;
- him.sin_family = AF_INET;
- len = sizeof(him);
+ dest_addr = ((caddr[0]<<24) & 0xff000000);
+ dest_addr |= ((caddr[1] <<16) & 0xff0000);
+ dest_addr |= ((caddr[2] <<8) & 0xff00);
+ dest_addr |= (caddr[3] & 0xff);
+ dest_addr = htonl(dest_addr);
/**
* If a network interface was specified, let's convert its address
* as well.
*/
if (!(IS_NULL(ifArray))) {
- memset((char *) caddr, 0, sizeof(caddr));
- (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
- addr = ((caddr[0]<<24) & 0xff000000);
- addr |= ((caddr[1] <<16) & 0xff0000);
- addr |= ((caddr[2] <<8) & 0xff00);
- addr |= (caddr[3] & 0xff);
- addr = htonl(addr);
- inf.sin_addr.s_addr = addr;
- inf.sin_family = AF_INET;
- inf.sin_port = 0;
- netif = &inf;
+ memset((char *) caddr, 0, sizeof(caddr));
+ (*env)->GetByteArrayRegion(env, ifArray, 0, 4, caddr);
+ src_addr = ((caddr[0]<<24) & 0xff000000);
+ src_addr |= ((caddr[1] <<16) & 0xff0000);
+ src_addr |= ((caddr[2] <<8) & 0xff00);
+ src_addr |= (caddr[3] & 0xff);
+ src_addr = htonl(src_addr);
}
-#if 0
- /*
- * Windows implementation of ICMP & RAW sockets is too unreliable for now.
- * Therefore it's best not to try it at all and rely only on TCP
- * We may revisit and enable this code in the future.
- */
-
- /*
- * Let's try to create a RAW socket to send ICMP packets
- * This usually requires "root" privileges, so it's likely to fail.
- */
- fd = NET_Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- if (fd != -1) {
- /*
- * It didn't fail, so we can use ICMP_ECHO requests.
- */
- return ping4(env, fd, &him, timeout, netif, ttl);
- }
-#endif
-
- /*
- * Can't create a raw socket, so let's try a TCP socket
- */
- fd = NET_Socket(AF_INET, SOCK_STREAM, 0);
- if (fd == JVM_IO_ERR) {
- /* note: if you run out of fds, you may not be able to load
- * the exception class, and get a NoClassDefFoundError
- * instead.
- */
- NET_ThrowNew(env, WSAGetLastError(), "Can't create socket");
- return JNI_FALSE;
- }
- if (ttl > 0) {
- setsockopt(fd, IPPROTO_IP, IP_TTL, (const char *)&ttl, sizeof(ttl));
- }
- /*
- * A network interface was specified, so let's bind to it.
- */
- if (netif != NULL) {
- if (bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in)) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket");
- closesocket(fd);
- return JNI_FALSE;
- }
- }
-
- /*
- * Make the socket non blocking so we can use select/poll.
- */
- hEvent = WSACreateEvent();
- WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
-
- /* no need to use NET_Connect as non-blocking */
- him.sin_port = htons(7); /* Echo */
- connect_rv = connect(fd, (struct sockaddr *)&him, len);
-
- /**
- * connection established or refused immediately, either way it means
- * we were able to reach the host!
- */
- if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_TRUE;
- } else {
- int optlen;
-
- switch (WSAGetLastError()) {
- case WSAEHOSTUNREACH: /* Host Unreachable */
- case WSAENETUNREACH: /* Network Unreachable */
- case WSAENETDOWN: /* Network is down */
- case WSAEPFNOSUPPORT: /* Protocol Family unsupported */
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_FALSE;
- }
-
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
- "connect failed");
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_FALSE;
- }
-
- timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
-
- /* has connection been established */
-
- if (timeout >= 0) {
- optlen = sizeof(connect_rv);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
- &optlen) <0) {
- connect_rv = WSAGetLastError();
- }
-
- if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_TRUE;
- }
- }
- }
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_FALSE;
+ return ping4(env, src_addr, dest_addr, timeout);
}
diff --git a/jdk/src/windows/native/java/net/Inet6AddressImpl.c b/jdk/src/windows/native/java/net/Inet6AddressImpl.c
index 8cb46aa..ff24d7f 100644
--- a/jdk/src/windows/native/java/net/Inet6AddressImpl.c
+++ b/jdk/src/windows/native/java/net/Inet6AddressImpl.c
@@ -31,6 +31,8 @@
#include <malloc.h>
#include <sys/types.h>
#include <process.h>
+#include <iphlpapi.h>
+#include <icmpapi.h>
#include "java_net_InetAddress.h"
#include "java_net_Inet4AddressImpl.h"
@@ -366,139 +368,61 @@
* Returns true is an ECHO_REPLY is received, otherwise, false.
*/
static jboolean
-ping6(JNIEnv *env, jint fd, struct SOCKADDR_IN6* him, jint timeout,
- struct SOCKADDR_IN6* netif, jint ttl) {
- jint size;
- jint n, len, i;
- char sendbuf[1500];
- char auxbuf[1500];
- unsigned char recvbuf[1500];
- struct icmp6_hdr *icmp6;
- struct SOCKADDR_IN6 sa_recv;
- unsigned short pid, seq;
- int read_rv = 0;
- WSAEVENT hEvent;
- struct ip6_pseudo_hdr *pseudo_ip6;
- int timestamp;
- int tmout2;
+ping6(JNIEnv *env,
+ struct sockaddr_in6* src,
+ struct sockaddr_in6* dest,
+ jint timeout)
+{
+ HANDLE hIcmpFile;
+ DWORD dwRetVal = 0;
+ char SendData[32] = {0};
+ LPVOID ReplyBuffer = NULL;
+ DWORD ReplySize = 0;
+ IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL};
+ struct sockaddr_in6 sa6Source;
- /* Initialize the sequence number to a suitable random number and
- shift right one place to allow sufficient room for increamenting. */
- seq = ((unsigned short)rand()) >> 1;
-
- /* icmp_id is a 16 bit data type, therefore down cast the pid */
- pid = (unsigned short) _getpid();
-
- size = 60*1024;
- setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&size, sizeof(size));
- /**
- * A TTL was specified, let's set the socket option.
- */
- if (ttl > 0) {
- setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *) &ttl, sizeof(ttl));
+ hIcmpFile = Icmp6CreateFile();
+ if (hIcmpFile == INVALID_HANDLE_VALUE) {
+ NET_ThrowNew(env, WSAGetLastError(), "Unable to open handle");
+ return JNI_FALSE;
}
- /**
- * A network interface was specified, let's bind to it.
- */
- if (netif != NULL) {
- if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0){
- NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
- closesocket(fd);
+ ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData);
+ ReplyBuffer = (VOID*) malloc(ReplySize);
+ if (ReplyBuffer == NULL) {
+ IcmpCloseHandle(hIcmpFile);
+ NET_ThrowNew(env, WSAGetLastError(), "Unable to allocate memory");
return JNI_FALSE;
- }
}
- /*
- * Make the socket non blocking
- */
- hEvent = WSACreateEvent();
- WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
+ //define local source information
+ sa6Source.sin6_addr = in6addr_any;
+ sa6Source.sin6_family = AF_INET6;
+ sa6Source.sin6_flowinfo = 0;
+ sa6Source.sin6_port = 0;
- /**
- * send 1 ICMP REQUEST every second until either we get a valid reply
- * or the timeout expired.
- */
- do {
- /* let's tag the ECHO packet with our pid so we can identify it */
- timestamp = GetCurrentTime();
- memset(sendbuf, 0, 1500);
- icmp6 = (struct icmp6_hdr *) sendbuf;
- icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
- icmp6->icmp6_code = 0;
- icmp6->icmp6_id = htons(pid);
- icmp6->icmp6_seq = htons(seq);
- icmp6->icmp6_cksum = 0;
- memcpy((icmp6 + 1), ×tamp, sizeof(int));
- if (netif != NULL) {
- memset(auxbuf, 0, 1500);
- pseudo_ip6 = (struct ip6_pseudo_hdr*) auxbuf;
- memcpy(&pseudo_ip6->ip6_src, &netif->sin6_addr, sizeof(struct in6_addr));
- memcpy(&pseudo_ip6->ip6_dst, &him->sin6_addr, sizeof(struct in6_addr));
- pseudo_ip6->ip6_plen= htonl( 64 );
- pseudo_ip6->ip6_nxt = htonl( IPPROTO_ICMPV6 );
- memcpy(auxbuf + sizeof(struct ip6_pseudo_hdr), icmp6, 64);
- /**
- * We shouldn't have to do that as computing the checksum is supposed
- * to be done by the IPv6 stack. Unfortunately windows, here too, is
- * uterly broken, or non compliant, so let's do it.
- * Problem is to compute the checksum I need to know the source address
- * which happens only if I know the interface to be used...
- */
- icmp6->icmp6_cksum = in_cksum((u_short *)pseudo_ip6, sizeof(struct ip6_pseudo_hdr) + 64);
- }
+ dwRetVal = Icmp6SendEcho2(hIcmpFile, // HANDLE IcmpHandle,
+ NULL, // HANDLE Event,
+ NULL, // PIO_APC_ROUTINE ApcRoutine,
+ NULL, // PVOID ApcContext,
+ &sa6Source, // struct sockaddr_in6 *SourceAddress,
+ dest, // struct sockaddr_in6 *DestinationAddress,
+ SendData, // LPVOID RequestData,
+ sizeof(SendData), // WORD RequestSize,
+ &ipInfo, // PIP_OPTION_INFORMATION RequestOptions,
+ ReplyBuffer, // LPVOID ReplyBuffer,
+ ReplySize, // DWORD ReplySize,
+ timeout); // DWORD Timeout
- /**
- * Ping!
- */
- n = sendto(fd, sendbuf, 64, 0, (struct sockaddr*) him, sizeof(struct sockaddr_in6));
- if (n < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEADDRNOTAVAIL)) {
- // Happens when using a "tunnel interface" for instance.
- // Or trying to send a packet on a different scope.
- closesocket(fd);
- WSACloseEvent(hEvent);
+ free(ReplyBuffer);
+ IcmpCloseHandle(hIcmpFile);
+
+
+ if (dwRetVal != 0) {
+ return JNI_TRUE;
+ } else {
return JNI_FALSE;
- }
- if (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
- NET_ThrowNew(env, WSAGetLastError(), "Can't send ICMP packet");
- closesocket(fd);
- WSACloseEvent(hEvent);
- return JNI_FALSE;
- }
-
- tmout2 = timeout > 1000 ? 1000 : timeout;
- do {
- tmout2 = NET_Wait(env, fd, NET_WAIT_READ, tmout2);
-
- if (tmout2 >= 0) {
- len = sizeof(sa_recv);
- memset(recvbuf, 0, 1500);
- /**
- * For some unknown reason, besides plain stupidity, windows
- * truncates the first 4 bytes of the icmpv6 header some we can't
- * check for the ICMP_ECHOREPLY value.
- * we'll check the other values, though
- */
- n = recvfrom(fd, recvbuf + 4, sizeof(recvbuf) - 4, 0, (struct sockaddr*) &sa_recv, &len);
- icmp6 = (struct icmp6_hdr *) (recvbuf);
- memcpy(&i, (icmp6 + 1), sizeof(int));
- /**
- * Is that the reply we were expecting?
- */
- if (n >= 8 && ntohs(icmp6->icmp6_seq) == seq &&
- ntohs(icmp6->icmp6_id) == pid && i == timestamp) {
- closesocket(fd);
- WSACloseEvent(hEvent);
- return JNI_TRUE;
- }
- }
- } while (tmout2 > 0);
- timeout -= 1000;
- seq++;
- } while (timeout > 0);
- closesocket(fd);
- WSACloseEvent(hEvent);
- return JNI_FALSE;
+ }
}
#endif /* AF_INET6 */
@@ -516,11 +440,10 @@
jint ttl, jint if_scope) {
#ifdef AF_INET6
jbyte caddr[16];
- jint fd, sz;
+ jint sz;
struct sockaddr_in6 him6;
struct sockaddr_in6* netif = NULL;
struct sockaddr_in6 inf6;
- WSAEVENT hEvent;
int len = 0;
int connect_rv = -1;
@@ -552,6 +475,7 @@
him6.sin6_scope_id = scope;
}
len = sizeof(struct sockaddr_in6);
+
/**
* A network interface was specified, let's convert the address
*/
@@ -565,123 +489,7 @@
inf6.sin6_scope_id = if_scope;
netif = &inf6;
}
-
-#if 0
- /*
- * Windows implementation of ICMP & RAW sockets is too unreliable for now.
- * Therefore it's best not to try it at all and rely only on TCP
- * We may revisit and enable this code in the future.
- */
-
- /*
- * Right now, windows doesn't generate the ICMP checksum automatically
- * so we have to compute it, but we can do it only if we know which
- * interface will be used. Therefore, don't try to use ICMP if no
- * interface was specified.
- * When ICMPv6 support improves in windows, we may change this.
- */
- if (!(IS_NULL(ifArray))) {
- /*
- * If we can create a RAW socket, then when can use the ICMP ECHO_REQUEST
- * otherwise we'll try a tcp socket to the Echo port (7).
- * Note that this is empiric, and not connecting could mean it's blocked
- * or the echo servioe has been disabled.
- */
- fd = NET_Socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
-
- if (fd != -1) { /* Good to go, let's do a ping */
- return ping6(env, fd, &him6, timeout, netif, ttl);
- }
- }
-#endif
-
- /* No good, let's fall back on TCP */
- fd = NET_Socket(AF_INET6, SOCK_STREAM, 0);
- if (fd == JVM_IO_ERR) {
- /* note: if you run out of fds, you may not be able to load
- * the exception class, and get a NoClassDefFoundError
- * instead.
- */
- NET_ThrowNew(env, errno, "Can't create socket");
- return JNI_FALSE;
- }
-
- /**
- * A TTL was specified, let's set the socket option.
- */
- if (ttl > 0) {
- setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (const char *)&ttl, sizeof(ttl));
- }
-
- /**
- * A network interface was specified, let's bind to it.
- */
- if (netif != NULL) {
- if (NET_Bind(fd, (struct sockaddr*)netif, sizeof(struct sockaddr_in6)) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "Can't bind socket to interface");
- closesocket(fd);
- return JNI_FALSE;
- }
- }
-
- /**
- * Make the socket non blocking.
- */
- hEvent = WSACreateEvent();
- WSAEventSelect(fd, hEvent, FD_READ|FD_CONNECT|FD_CLOSE);
-
- /* no need to use NET_Connect as non-blocking */
- him6.sin6_port = htons((short) 7); /* Echo port */
- connect_rv = connect(fd, (struct sockaddr *)&him6, len);
-
- /**
- * connection established or refused immediately, either way it means
- * we were able to reach the host!
- */
- if (connect_rv == 0 || WSAGetLastError() == WSAECONNREFUSED) {
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_TRUE;
- } else {
- int optlen;
-
- switch (WSAGetLastError()) {
- case WSAEHOSTUNREACH: /* Host Unreachable */
- case WSAENETUNREACH: /* Network Unreachable */
- case WSAENETDOWN: /* Network is down */
- case WSAEPFNOSUPPORT: /* Protocol Family unsupported */
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_FALSE;
- }
-
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "ConnectException",
- "connect failed");
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_FALSE;
- }
-
- timeout = NET_Wait(env, fd, NET_WAIT_CONNECT, timeout);
-
- if (timeout >= 0) {
- /* has connection been established? */
- optlen = sizeof(connect_rv);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&connect_rv,
- &optlen) <0) {
- connect_rv = WSAGetLastError();
- }
-
- if (connect_rv == 0 || connect_rv == WSAECONNREFUSED) {
- WSACloseEvent(hEvent);
- closesocket(fd);
- return JNI_TRUE;
- }
- }
- }
- WSACloseEvent(hEvent);
- closesocket(fd);
+ return ping6(env, netif, &him6, timeout);
#endif /* AF_INET6 */
return JNI_FALSE;
}
diff --git a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
index 6922d3d..3b1994d 100644
--- a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
+++ b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -2239,8 +2239,11 @@
optlen = sizeof(optval.i);
if (NET_GetSockOpt(fd, level, optname, (void *)&optval, &optlen) < 0) {
- char errmsg[255];
- sprintf(errmsg, "error getting socket option: %s\n", strerror(errno));
+ char tmpbuf[255];
+ int size = 0;
+ char errmsg[255 + 31];
+ getErrorString(errno, tmpbuf, sizeof(tmpbuf));
+ sprintf(errmsg, "error getting socket option: %s", tmpbuf);
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", errmsg);
return NULL;
}
@@ -2591,3 +2594,44 @@
{
mcast_join_leave (env, this, iaObj, niObj, JNI_FALSE);
}
+
+/*
+ * Class: java_net_TwoStacksPlainDatagramSocketImpl
+ * Method: dataAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainDatagramSocketImpl_dataAvailable
+(JNIEnv *env, jobject this) {
+ SOCKET fd;
+ SOCKET fd1;
+ int rv = -1, rv1 = -1;
+ jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
+ jobject fd1Obj;
+
+ if (!IS_NULL(fdObj)) {
+ int retval = 0;
+ fd = (SOCKET)(*env)->GetIntField(env, fdObj, IO_fd_fdID);
+ rv = ioctlsocket(fd, FIONREAD, &retval);
+ if (retval > 0) {
+ return retval;
+ }
+ }
+
+ fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
+ if (!IS_NULL(fd1Obj)) {
+ int retval = 0;
+ fd1 = (SOCKET)(*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
+ rv1 = ioctlsocket(fd1, FIONREAD, &retval);
+ if (retval > 0) {
+ return retval;
+ }
+ }
+
+ if (rv < 0 && rv1 < 0) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp b/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp
index 5afb5b3..1b5b71f 100644
--- a/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp
+++ b/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -114,8 +114,9 @@
// which may've been disposed by this time, and we have
// no means of checking against it.
if (oldhDC != NULL) {
- MoveDCToPassiveList(oldhDC);
+ MoveDCToPassiveList(oldhDC, info->hWnd);
info->hDC = NULL;
+ info->hWnd = NULL;
}
if (wsdo->window != NULL){
@@ -150,6 +151,7 @@
// Finally, set these new values in the info for this thread
info->hDC = hDC;
+ info->hWnd = wsdo->window;
}
// cached brush and pen are not associated with any DC, and can be
@@ -187,7 +189,7 @@
if (info->hDC != NULL) {
// move the DC from the active dcs list to
// the passive dc list to be released later
- MoveDCToPassiveList(info->hDC);
+ MoveDCToPassiveList(info->hDC, info->hWnd);
}
if (info->clip != NULL) {
diff --git a/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h b/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h
index 3dfaa16..a954874 100644
--- a/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h
+++ b/jdk/src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -196,6 +196,7 @@
*/
typedef struct {
HDC hDC;
+ HWND hWnd;
GDIWinSDOps *wsdo;
LONG wsdoTimeStamp; // wsdo creation time stamp.
// Other threads may deallocate wsdo
diff --git a/jdk/src/windows/native/sun/nio/ch/Net.c b/jdk/src/windows/native/sun/nio/ch/Net.c
index e68951b..6ff0e54 100644
--- a/jdk/src/windows/native/sun/nio/ch/Net.c
+++ b/jdk/src/windows/native/sun/nio/ch/Net.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -157,7 +157,7 @@
if (loopback_available) {
int rv = NET_EnableFastTcpLoopback((jint)s);
if (rv) {
- if (rv == WSAEOPNOTSUPP) {
+ if (rv == WSAEOPNOTSUPP || rv == WSAEINVAL) {
loopback_available = 0;
} else {
NET_ThrowNew(env, rv, "fastLoopback");
diff --git a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
index 94e060f..8075d04 100644
--- a/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
+++ b/jdk/src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
@@ -195,6 +195,17 @@
}
}
+JNIEXPORT jlong JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CreateEvent(JNIEnv* env, jclass this,
+ jboolean bManualReset, jboolean bInitialState)
+{
+ HANDLE hEvent = CreateEventW(NULL, bManualReset, bInitialState, NULL);
+ if (hEvent == NULL) {
+ throwWindowsException(env, GetLastError());
+ }
+ return ptr_to_jlong(hEvent);
+}
+
JNIEXPORT jstring JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_FormatMessage(JNIEnv* env, jclass this, jint errorCode) {
WCHAR message[255];
@@ -1230,23 +1241,38 @@
}
JNIEXPORT void JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_CancelIo(JNIEnv* env, jclass this, jlong hFile) {
+ if (CancelIo((HANDLE)jlong_to_ptr(hFile)) == 0) {
+ throwWindowsException(env, GetLastError());
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_WindowsNativeDispatcher_GetOverlappedResult(JNIEnv *env, jclass this,
+ jlong hFile, jlong lpOverlapped)
+{
+ BOOL res;
+ DWORD bytesTransferred = -1;
+
+ res = GetOverlappedResult((HANDLE)jlong_to_ptr(hFile),
+ (LPOVERLAPPED)jlong_to_ptr(lpOverlapped),
+ &bytesTransferred,
+ TRUE);
+ if (res == 0) {
+ throwWindowsException(env, GetLastError());
+ }
+
+ return (jint)bytesTransferred;
+}
+
+JNIEXPORT void JNICALL
Java_sun_nio_fs_WindowsNativeDispatcher_ReadDirectoryChangesW(JNIEnv* env, jclass this,
jlong hDirectory, jlong bufferAddress, jint bufferLength, jboolean watchSubTree, jint filter,
jlong bytesReturnedAddress, jlong pOverlapped)
{
BOOL res;
BOOL subtree = (watchSubTree == JNI_TRUE) ? TRUE : FALSE;
-
- /* Any unused members of [OVERLAPPED] structure should always be initialized to zero
- before the structure is used in a function call.
- Otherwise, the function may fail and return ERROR_INVALID_PARAMETER.
- http://msdn.microsoft.com/en-us/library/windows/desktop/ms684342%28v=vs.85%29.aspx
-
- The [Offset] and [OffsetHigh] members of this structure are not used.
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465%28v=vs.85%29.aspx
-
- [hEvent] should be zero, other fields are the return values. */
- ZeroMemory((LPOVERLAPPED)jlong_to_ptr(pOverlapped), sizeof(OVERLAPPED));
+ LPOVERLAPPED ov = (LPOVERLAPPED)jlong_to_ptr(pOverlapped);
res = ReadDirectoryChangesW((HANDLE)jlong_to_ptr(hDirectory),
(LPVOID)jlong_to_ptr(bufferAddress),
diff --git a/jdk/src/windows/native/sun/windows/awt_Component.cpp b/jdk/src/windows/native/sun/windows/awt_Component.cpp
index 5a29590..f51c22e 100644
--- a/jdk/src/windows/native/sun/windows/awt_Component.cpp
+++ b/jdk/src/windows/native/sun/windows/awt_Component.cpp
@@ -1382,7 +1382,7 @@
case WM_AWT_RELEASEDC:
{
HDC hDC = (HDC)wParam;
- MoveDCToPassiveList(hDC);
+ MoveDCToPassiveList(hDC, GetHWnd());
ReleaseDCList(GetHWnd(), passiveDCList);
mr = mrConsume;
break;
@@ -7174,8 +7174,8 @@
}
/**
- * Given a DC, remove it from the DC list and return
- * TRUE if it exists on the current list. Otherwise
+ * Given a DC and window handle, remove the DC from the DC list
+ * and return TRUE if it exists on the current list. Otherwise
* return FALSE.
* A DC may not exist on the list because it has already
* been released elsewhere (for example, the window
@@ -7183,14 +7183,14 @@
* thread may also want to release a DC when it notices that
* its DC is obsolete for the current window).
*/
-DCItem *DCList::RemoveDC(HDC hDC)
+DCItem *DCList::RemoveDC(HDC hDC, HWND hWnd)
{
listLock.Enter();
DCItem **prevPtrPtr = &head;
DCItem *listPtr = head;
while (listPtr) {
DCItem *nextPtr = listPtr->next;
- if (listPtr->hDC == hDC) {
+ if (listPtr->hDC == hDC && listPtr->hWnd == hWnd) {
*prevPtrPtr = nextPtr;
break;
}
@@ -7244,9 +7244,9 @@
listLock.Leave();
}
-void MoveDCToPassiveList(HDC hDC) {
+void MoveDCToPassiveList(HDC hDC, HWND hWnd) {
DCItem *removedDC;
- if ((removedDC = activeDCList.RemoveDC(hDC)) != NULL) {
+ if ((removedDC = activeDCList.RemoveDC(hDC, hWnd)) != NULL) {
passiveDCList.AddDCItem(removedDC);
}
}
diff --git a/jdk/src/windows/native/sun/windows/awt_Component.h b/jdk/src/windows/native/sun/windows/awt_Component.h
index f3f3409..b914ef1 100644
--- a/jdk/src/windows/native/sun/windows/awt_Component.h
+++ b/jdk/src/windows/native/sun/windows/awt_Component.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -900,13 +900,13 @@
void AddDC(HDC hDC, HWND hWnd);
void AddDCItem(DCItem *newItem);
- DCItem *RemoveDC(HDC hDC);
+ DCItem *RemoveDC(HDC hDC, HWND hWnd);
DCItem *RemoveAllDCs(HWND hWnd);
void RealizePalettes(int screen);
};
void ReleaseDCList(HWND hwnd, DCList &list);
-void MoveDCToPassiveList(HDC hDC);
+void MoveDCToPassiveList(HDC hDC, HWND hWnd);
namespace TimeHelper{
jlong getMessageTimeUTC();
diff --git a/jdk/src/windows/native/sun/windows/awt_Frame.cpp b/jdk/src/windows/native/sun/windows/awt_Frame.cpp
index 2c25e97..53f6a50 100644
--- a/jdk/src/windows/native/sun/windows/awt_Frame.cpp
+++ b/jdk/src/windows/native/sun/windows/awt_Frame.cpp
@@ -1961,29 +1961,6 @@
CATCH_BAD_ALLOC;
}
-JNIEXPORT jboolean JNICALL
-Java_sun_awt_windows_WEmbeddedFramePeer_requestFocusToEmbedder(JNIEnv *env, jobject self)
-{
- jboolean result = JNI_FALSE;
-
- TRY;
-
- AwtFrame *frame = NULL;
-
- PDATA pData;
- JNI_CHECK_PEER_GOTO(self, ret);
- frame = (AwtFrame *)pData;
-
- // JDK-8056915: During initial applet activation, set focus to plugin control window
- HWND hwndParent = ::GetParent(frame->GetHWnd());
-
- result = SetFocusToPluginControl(hwndParent);
-
- CATCH_BAD_ALLOC_RET(JNI_FALSE);
-ret:
- return result;
-}
-
} /* extern "C" */
static bool SetFocusToPluginControl(HWND hwndPlugin)
diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups
index d1b858f..d857a4d 100644
--- a/jdk/test/TEST.groups
+++ b/jdk/test/TEST.groups
@@ -327,6 +327,7 @@
java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java \
java/lang/invoke/lambda/LambdaAccessControlTest.java \
java/lang/invoke/lambda/LambdaAsm.java \
+ java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java \
java/lang/System/MacEncoding/TestFileEncoding.java \
java/net/URLClassLoader/closetest/GetResourceAsStream.java \
java/util/Collections/EmptyIterator.java \
@@ -489,7 +490,6 @@
java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java \
java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java \
java/lang/System/MacEncoding/TestFileEncoding.java \
- java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java \
java/nio/channels/AsynchronousSocketChannel/Leaky.java \
java/security/PermissionCollection/Concurrent.java \
java/security/Principal/Implies.java \
diff --git a/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.java b/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.java
new file mode 100644
index 0000000..b1c0237
--- /dev/null
+++ b/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.java
@@ -0,0 +1,75 @@
+/*
+ * 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 8081485
+ @summary tests that a program terminates automatically after EventQueue.push()
+ @author Anton Nashatyrev : area=toolkit
+*/
+
+import java.awt.*;
+
+public class EventQueuePushAutoshutdown implements Runnable {
+ private volatile int status = 2;
+
+ public EventQueuePushAutoshutdown() throws Exception {
+ Runtime.getRuntime().addShutdownHook(new Thread(this));
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ status = 0;
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } finally {
+ status = 1;
+ System.exit(status);
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+
+ System.setProperty("java.awt.headless", "true");
+ final EventQueue systemQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
+ systemQueue.push(new EventQueue());
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("Activated EDT");
+ }
+ });
+ System.out.println("After EDT activation");
+ }
+
+ public static void main(String[] args) throws Exception {
+ new EventQueuePushAutoshutdown();
+ }
+
+ @Override
+ public void run() {
+ Runtime.getRuntime().halt(status);
+ }
+}
diff --git a/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh b/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh
new file mode 100644
index 0000000..b88becb
--- /dev/null
+++ b/jdk/test/java/awt/Toolkit/AutoShutdown/EventQueuePush/EventQueuePushAutoshutdown.sh
@@ -0,0 +1,159 @@
+#!/bin/ksh -p
+
+#
+# Copyright (c) 20015, 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 EventQueuePushAutoshutdown.sh
+# @bug 8081485
+# @summary tests that a program terminates automatically
+# after EventQueue.push()
+# @author Anton Nashatyrev : area=toolkit
+#
+# @compile EventQueuePushAutoshutdown.java
+# @run shell EventQueuePushAutoshutdown.sh
+
+
+# Beginning of subroutines:
+status=1
+
+#Call this from anywhere to fail the test with an error message
+# usage: fail "reason why the test failed"
+fail()
+ { echo "The test failed :-("
+ echo "$*" 1>&2
+ echo "exit status was $status"
+ exit $status
+ } #end of fail()
+
+#Call this from anywhere to pass the test with a message
+# usage: pass "reason why the test passed if applicable"
+pass()
+ { echo "The test passed!!!"
+ echo "$*" 1>&2
+ exit 0
+ } #end of pass()
+
+# end of subroutines
+
+
+# The beginning of the script proper
+OS=`uname -s`
+case "$OS" in
+ SunOS | Linux | Darwin | CYGWIN* )
+ FILESEP="/"
+ ;;
+
+ Windows_95 | Windows_98 | Windows_NT | Windows_ME )
+ FILESEP="\\"
+ ;;
+
+ # catch all other OSs
+ * )
+ echo "Unrecognized system! $OS"
+ fail "Unrecognized system! $OS"
+ ;;
+esac
+
+
+# Want this test to run standalone as well as in the harness, so do the
+# following to copy the test's directory into the harness's scratch directory
+# and set all appropriate variables:
+
+if [ -z "${TESTJAVA}" ] ; then
+ # TESTJAVA is not set, so the test is running stand-alone.
+ # TESTJAVA holds the path to the root directory of the build of the JDK
+ # to be tested. That is, any java files run explicitly in this shell
+ # should use TESTJAVA in the path to the java interpreter.
+ # So, we'll set this to the JDK spec'd on the command line. If none
+ # is given on the command line, tell the user that and use a cheesy
+ # default.
+ # THIS IS THE JDK BEING TESTED.
+ if [ -n "$1" ] ;
+ then TESTJAVA=$1
+ else fail "no JDK specified on command line!"
+ fi
+ TESTSRC=.
+ TESTCLASSES=.
+ STANDALONE=1;
+fi
+echo "JDK under test is: $TESTJAVA"
+
+#Deal with .class files:
+if [ -n "${STANDALONE}" ] ;
+ then
+ #if standalone, remind user to cd to dir. containing test before running it
+ echo "Just a reminder: cd to the dir containing this test when running it"
+ # then compile all .java files (if there are any) into .class files
+ if [ -a *.java ] ;
+ then echo "Reminder, this test should be in its own directory with all"
+ echo "supporting files it needs in the directory with it."
+ ${TESTJAVA}/bin/javac ./*.java ;
+ fi
+ # else in harness so copy all the class files from where jtreg put them
+ # over to the scratch directory this test is running in.
+ else cp ${TESTCLASSES}/*.class . ;
+fi
+
+#if in test harness, then copy the entire directory that the test is in over
+# to the scratch directory. This catches any support files needed by the test.
+if [ -z "${STANDALONE}" ] ;
+ then cp ${TESTSRC}/* .
+fi
+
+#Just before executing anything, make sure it has executable permission!
+chmod 777 ./*
+
+############### YOUR TEST CODE HERE!!!!!!! #############
+
+#All files required for the test should be in the same directory with
+# this file. If converting a standalone test to run with the harness,
+# as long as all files are in the same directory and it returns 0 for
+# pass, you should be able to cut and paste it into here and it will
+# run with the test harness.
+
+${TESTJAVA}/bin/java EventQueuePushAutoshutdown
+
+############### END YOUR TEST CODE !!!!! ############
+#Be sure the last command executed above this line returns 0 for success,
+# something non-zero for failure.
+status=$?
+
+# pass or fail the test based on status of the command
+case "$status" in
+ 0 )
+ pass ""
+ ;;
+
+ 1 )
+ fail "The program didn't automatically shut down"
+ ;;
+
+ * )
+ fail "The program terminated unexpectedly!"
+ ;;
+esac
+
+#For additional examples of how to write platform independent KSH scripts,
+# see the jtreg file itself. It is a KSH script for both Solaris and Win32
+
diff --git a/jdk/test/java/awt/datatransfer/DataFlavor/MacOsXFileAndMultipleFileCopingTest/MacOsXFileAndMultipleFileCopingTest.java b/jdk/test/java/awt/datatransfer/DataFlavor/MacOsXFileAndMultipleFileCopingTest/MacOsXFileAndMultipleFileCopingTest.java
new file mode 100644
index 0000000..18b7012
--- /dev/null
+++ b/jdk/test/java/awt/datatransfer/DataFlavor/MacOsXFileAndMultipleFileCopingTest/MacOsXFileAndMultipleFileCopingTest.java
@@ -0,0 +1,368 @@
+/*
+ * 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 8081787 8136763
+ @author Mikhail Cherkasov
+ @run main/manual MacOsXFileAndMultipleFileCopingTest
+*/
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.URL;
+
+public class MacOsXFileAndMultipleFileCopingTest {
+ private static void init() {
+ String[] instructions =
+ {"Test for MacOS X only:",
+ "1. The aim is to test that java works fine with \"application/" +
+ "x-java-url;class=java.net.URL\"falvor and support coping of multiple files",
+ "2. Open finder and select any file.",
+ "3. Press CMD+C or press \"Copy\" in context menu",
+ "4. Focus window with \"Test URL\" Button.",
+ "5. If you see URL for selected file, then test PASSED,",
+ "otherwise test FAILED.",
+
+ "6. Open finder again and select several files.",
+ "7. Press CMD+C or press \"Copy\" in context menu",
+ "8. Focus window with \"Test multiple files coping\" Button.",
+ "9. If you see list of selected files, then test PASSED,",
+ "otherwise test FAILED.",
+
+ };
+
+ Sysout.createDialog();
+ Sysout.printInstructions(instructions);
+
+ final Frame frame = new Frame();
+ Panel panel = new Panel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
+
+ frame.add(panel);
+ Button testUrlBtn = new Button("Test URL");
+ final TextArea textArea = new TextArea(5, 80);
+ testUrlBtn.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ try {
+ Clipboard board = Toolkit.getDefaultToolkit().getSystemClipboard();
+ URL url = (URL) board.getData(new DataFlavor("application/x-java-url;class=java.net.URL"));
+ textArea.setText(url.toString());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ panel.add(testUrlBtn);
+ Button testUriList = new Button("Test multiple files coping");
+ testUriList.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ try {
+ Clipboard board = Toolkit.getDefaultToolkit().getSystemClipboard();
+ String files = (String) board.getData(new DataFlavor("text/uri-list;class=java.lang.String"));
+ textArea.setText(files);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ panel.add(testUriList);
+ panel.add(textArea);
+ frame.setBounds(200, 200, 400, 400);
+ frame.setVisible(true);
+
+ }//End init()
+
+
+ /*****************************************************
+ * Standard Test Machinery Section
+ * DO NOT modify anything in this section -- it's a
+ * standard chunk of code which has all of the
+ * synchronisation necessary for the test harness.
+ * By keeping it the same in all tests, it is easier
+ * to read and understand someone else's test, as
+ * well as insuring that all tests behave correctly
+ * with the test harness.
+ * There is a section following this for test-defined
+ * classes
+ ******************************************************/
+ private static boolean theTestPassed = false;
+ private static boolean testGeneratedInterrupt = false;
+ private static String failureMessage = "";
+
+ private static Thread mainThread = null;
+
+ private static int sleepTime = 300000;
+
+ public static void main(String args[]) throws InterruptedException {
+ if (!System.getProperty("os.name").startsWith("Mac")) {
+ return;
+ }
+ mainThread = Thread.currentThread();
+ try {
+ init();
+ } catch (TestPassedException e) {
+ //The test passed, so just return from main and harness will
+ // interepret this return as a pass
+ return;
+ }
+ //At this point, neither test passed nor test failed has been
+ // called -- either would have thrown an exception and ended the
+ // test, so we know we have multiple threads.
+
+ //Test involves other threads, so sleep and wait for them to
+ // called pass() or fail()
+ try {
+ Thread.sleep(sleepTime);
+ //Timed out, so fail the test
+ throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
+ } catch (InterruptedException e) {
+ if (!testGeneratedInterrupt) throw e;
+
+ //reset flag in case hit this code more than once for some reason (just safety)
+ testGeneratedInterrupt = false;
+ if (theTestPassed == false) {
+ throw new RuntimeException(failureMessage);
+ }
+ }
+
+ }//main
+
+ public static synchronized void setTimeoutTo(int seconds) {
+ sleepTime = seconds * 1000;
+ }
+
+ public static synchronized void pass() {
+ Sysout.println("The test passed.");
+ Sysout.println("The test is over, hit Ctl-C to stop Java VM");
+ //first check if this is executing in main thread
+ if (mainThread == Thread.currentThread()) {
+ //Still in the main thread, so set the flag just for kicks,
+ // and throw a test passed exception which will be caught
+ // and end the test.
+ theTestPassed = true;
+ throw new TestPassedException();
+ }
+ //pass was called from a different thread, so set the flag and interrupt
+ // the main thead.
+ theTestPassed = true;
+ testGeneratedInterrupt = true;
+ if (mainThread != null) {
+ mainThread.interrupt();
+ }
+ }//pass()
+
+ public static synchronized void fail() {
+ //test writer didn't specify why test failed, so give generic
+ fail("it just plain failed! :-)");
+ }
+
+ public static synchronized void fail(String whyFailed) {
+ Sysout.println("The test failed: " + whyFailed);
+ Sysout.println("The test is over, hit Ctl-C to stop Java VM");
+ //check if this called from main thread
+ if (mainThread == Thread.currentThread()) {
+ //If main thread, fail now 'cause not sleeping
+ throw new RuntimeException(whyFailed);
+ }
+ theTestPassed = false;
+ testGeneratedInterrupt = true;
+ failureMessage = whyFailed;
+ mainThread.interrupt();
+ }//fail()
+
+}// class ManualMainTest
+
+//This exception is used to exit from any level of call nesting
+// when it's determined that the test has passed, and immediately
+// end the test.
+class TestPassedException extends RuntimeException {
+}
+
+//*********** End Standard Test Machinery Section **********
+
+
+/****************************************************
+ * Standard Test Machinery
+ * DO NOT modify anything below -- it's a standard
+ * chunk of code whose purpose is to make user
+ * interaction uniform, and thereby make it simpler
+ * to read and understand someone else's test.
+ ****************************************************/
+
+/**
+ This is part of the standard test machinery.
+ It creates a dialog (with the instructions), and is the interface
+ for sending text messages to the user.
+ To print the instructions, send an array of strings to Sysout.createDialog
+ WithInstructions method. Put one line of instructions per array entry.
+ To display a message for the tester to see, simply call Sysout.println
+ with the string to be displayed.
+ This mimics System.out.println but works within the test harness as well
+ as standalone.
+ */
+
+class Sysout {
+ private static TestDialog dialog;
+ private static boolean numbering = false;
+ private static int messageNumber = 0;
+
+ public static void createDialogWithInstructions(String[] instructions) {
+ dialog = new TestDialog(new Frame(), "Instructions");
+ dialog.printInstructions(instructions);
+ dialog.setVisible(true);
+ println("Any messages for the tester will display here.");
+ }
+
+ public static void createDialog() {
+ dialog = new TestDialog(new Frame(), "Instructions");
+ String[] defInstr = {"Instructions will appear here. ", ""};
+ dialog.printInstructions(defInstr);
+ dialog.setVisible(true);
+ println("Any messages for the tester will display here.");
+ }
+
+
+ /* Enables message counting for the tester. */
+ public static void enableNumbering(boolean enable) {
+ numbering = enable;
+ }
+
+ public static void printInstructions(String[] instructions) {
+ dialog.printInstructions(instructions);
+ }
+
+
+ public static void println(String messageIn) {
+ if (numbering) {
+ messageIn = "" + messageNumber + " " + messageIn;
+ messageNumber++;
+ }
+ dialog.displayMessage(messageIn);
+ }
+
+}// Sysout class
+
+/**
+ This is part of the standard test machinery. It provides a place for the
+ test instructions to be displayed, and a place for interactive messages
+ to the user to be displayed.
+ To have the test instructions displayed, see Sysout.
+ To have a message to the user be displayed, see Sysout.
+ Do not call anything in this dialog directly.
+ */
+class TestDialog extends Dialog implements ActionListener {
+
+ TextArea instructionsText;
+ TextArea messageText;
+ int maxStringLength = 80;
+ Panel buttonP = new Panel();
+ Button passB = new Button("pass");
+ Button failB = new Button("fail");
+
+ //DO NOT call this directly, go through Sysout
+ public TestDialog(Frame frame, String name) {
+ super(frame, name);
+ int scrollBoth = TextArea.SCROLLBARS_BOTH;
+ instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
+ add("North", instructionsText);
+
+ messageText = new TextArea("", 5, maxStringLength, scrollBoth);
+ add("Center", messageText);
+
+ passB = new Button("pass");
+ passB.setActionCommand("pass");
+ passB.addActionListener(this);
+ buttonP.add("East", passB);
+
+ failB = new Button("fail");
+ failB.setActionCommand("fail");
+ failB.addActionListener(this);
+ buttonP.add("West", failB);
+
+ add("South", buttonP);
+ pack();
+
+ setVisible(true);
+ }// TestDialog()
+
+ //DO NOT call this directly, go through Sysout
+ public void printInstructions(String[] instructions) {
+ //Clear out any current instructions
+ instructionsText.setText("");
+
+ //Go down array of instruction strings
+
+ String printStr, remainingStr;
+ for (int i = 0; i < instructions.length; i++) {
+ //chop up each into pieces maxSringLength long
+ remainingStr = instructions[i];
+ while (remainingStr.length() > 0) {
+ //if longer than max then chop off first max chars to print
+ if (remainingStr.length() >= maxStringLength) {
+ //Try to chop on a word boundary
+ int posOfSpace = remainingStr.
+ lastIndexOf(' ', maxStringLength - 1);
+
+ if (posOfSpace <= 0) posOfSpace = maxStringLength - 1;
+
+ printStr = remainingStr.substring(0, posOfSpace + 1);
+ remainingStr = remainingStr.substring(posOfSpace + 1);
+ }
+ //else just print
+ else {
+ printStr = remainingStr;
+ remainingStr = "";
+ }
+
+ instructionsText.append(printStr + "\n");
+
+ }// while
+
+ }// for
+
+ }//printInstructions()
+
+ //DO NOT call this directly, go through Sysout
+ public void displayMessage(String messageIn) {
+ messageText.append(messageIn + "\n");
+ System.out.println(messageIn);
+ }
+
+ //catch presses of the passed and failed buttons.
+ //simply call the standard pass() or fail() static methods of
+ //ManualMainTest
+ public void actionPerformed(ActionEvent e) {
+ if (e.getActionCommand() == "pass") {
+ MacOsXFileAndMultipleFileCopingTest.pass();
+ } else {
+ MacOsXFileAndMultipleFileCopingTest.fail();
+ }
+ }
+
+}// TestDialog class
\ No newline at end of file
diff --git a/jdk/test/java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java b/jdk/test/java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java
new file mode 100644
index 0000000..ee28fcc
--- /dev/null
+++ b/jdk/test/java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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.awt.Dialog;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.Window;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DragGestureEvent;
+import java.awt.dnd.DragGestureListener;
+import java.awt.dnd.DragSource;
+import java.awt.dnd.DropTarget;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+/*
+ * @test
+ * @bug 8134917
+ * @summary [macosx] JOptionPane doesn't receive mouse events when opened from a drop event
+ * @author Alexandr Scherbatiy
+ */
+public class MissingEventsOnModalDialogTest {
+
+ private static volatile boolean passed = false;
+
+ public static void main(String[] args) throws Exception {
+ Frame sourceFrame = createFrame("Source Frame", 0, 0);
+ Frame targetFrame = createFrame("Target Frame", 250, 250);
+
+ DragSource defaultDragSource
+ = DragSource.getDefaultDragSource();
+ defaultDragSource.createDefaultDragGestureRecognizer(sourceFrame,
+ DnDConstants.ACTION_COPY_OR_MOVE,
+ new TestDragGestureListener());
+ new DropTarget(targetFrame, DnDConstants.ACTION_COPY_OR_MOVE,
+ new TestDropTargetListener(targetFrame));
+
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+
+ sourceFrame.toFront();
+ robot.waitForIdle();
+
+ Point point = getCenterPoint(sourceFrame);
+ robot.mouseMove(point.x, point.y);
+ robot.waitForIdle();
+
+ mouseDragAndDrop(robot, point, getCenterPoint(targetFrame));
+
+ long time = System.currentTimeMillis() + 200;
+
+ while (!passed) {
+ if (time < System.currentTimeMillis()) {
+ sourceFrame.dispose();
+ targetFrame.dispose();
+ throw new RuntimeException("Mouse clicked event is lost!");
+ }
+ Thread.sleep(10);
+ }
+ sourceFrame.dispose();
+ targetFrame.dispose();
+ }
+
+ private static Frame createFrame(String title, int x, int y) {
+ Frame frame = new Frame();
+ frame.setSize(200, 200);
+ frame.setLocation(x, y);
+ frame.setTitle(title);
+ frame.setVisible(true);
+ return frame;
+ }
+
+ private static Point getCenterPoint(Window window) {
+ Point centerPoint = window.getLocationOnScreen();
+ centerPoint.translate(window.getWidth() / 2, window.getHeight() / 2);
+ return centerPoint;
+ }
+
+ public static void mouseDragAndDrop(Robot robot, Point from, Point to) {
+ mouseDND(robot, from.x, from.y, to.x, to.y);
+ }
+
+ public static void mouseDND(Robot robot, int x1, int y1, int x2, int y2) {
+
+ int N = 20;
+ int x = x1;
+ int y = y1;
+ int dx = (x2 - x1) / N;
+ int dy = (y2 - y1) / N;
+
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+
+ for (int i = 0; i < N; i++) {
+ robot.mouseMove(x += dx, y += dy);
+ }
+
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ }
+
+ private static class TestDragGestureListener implements DragGestureListener {
+
+ public void dragGestureRecognized(DragGestureEvent dge) {
+ dge.startDrag(null, new StringTransferable());
+ }
+ }
+
+ static class StringTransferable implements Transferable {
+
+ @Override
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[]{DataFlavor.stringFlavor};
+ }
+
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor flavor) {
+ return flavor.equals(DataFlavor.stringFlavor);
+ }
+
+ @Override
+ public Object getTransferData(DataFlavor flavor) {
+ return "Hello World!";
+ }
+ }
+
+ private static class TestDropTargetListener implements DropTargetListener {
+
+ private final Frame targetFrame;
+
+ public TestDropTargetListener(Frame targetFrame) {
+ this.targetFrame = targetFrame;
+ }
+
+ @Override
+ public void dragEnter(DropTargetDragEvent dtde) {
+ dtde.acceptDrag(dtde.getDropAction());
+ }
+
+ @Override
+ public void dragOver(DropTargetDragEvent dtde) {
+ dtde.acceptDrag(dtde.getDropAction());
+ }
+
+ @Override
+ public void dropActionChanged(DropTargetDragEvent dtde) {
+ dtde.acceptDrag(dtde.getDropAction());
+ }
+
+ @Override
+ public void dragExit(DropTargetEvent dte) {
+ }
+
+ @Override
+ public void drop(DropTargetDropEvent dtde) {
+ dtde.acceptDrop(dtde.getDropAction());
+ showModalDialog(targetFrame);
+ dtde.dropComplete(true);
+ }
+ }
+
+ private static void showModalDialog(Frame targetFrame) {
+
+ Dialog dialog = new Dialog(targetFrame, true);
+
+ dialog.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ passed = true;
+ dialog.dispose();
+ }
+ });
+
+ dialog.setSize(400, 300);
+ dialog.setTitle("Modal Dialog!");
+
+ clickOnModalDialog(dialog);
+ dialog.setVisible(true);
+ }
+
+ private static void clickOnModalDialog(Dialog dialog) {
+ new Thread(() -> {
+ clickOnDialog(dialog);
+ }).start();
+ }
+
+ private static void clickOnDialog(Dialog dialog) {
+ try {
+ long time = System.currentTimeMillis() + 200;
+
+ while (!dialog.isVisible()) {
+ if (time < System.currentTimeMillis()) {
+ throw new RuntimeException("Dialog is not visible!");
+ }
+ Thread.sleep(10);
+ }
+
+ Point point = getCenterPoint(dialog);
+ Robot robot = new Robot();
+ robot.setAutoDelay(50);
+
+ robot.mouseMove(point.x, point.y);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java b/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java
new file mode 100644
index 0000000..3e24673
--- /dev/null
+++ b/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 java.lang.invoke;
+
+/* @test
+ * @summary Assertion in LambdaFormEditor.bindArgumentType is too strong
+ *
+ * @run main/bootclasspath -esa java.lang.invoke.CustomizedLambdaFormTest
+ */
+public class CustomizedLambdaFormTest {
+
+ static void testExtendCustomizedBMH() throws Exception {
+ // Construct BMH
+ MethodHandle mh = MethodHandles.Lookup.IMPL_LOOKUP.findVirtual(String.class, "concat",
+ MethodType.methodType(String.class, String.class))
+ .bindTo("a");
+ mh.customize();
+ mh.bindTo("b"); // Try to extend customized BMH
+ }
+
+ public static void main(String[] args) throws Throwable {
+ testExtendCustomizedBMH();
+ }
+}
diff --git a/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java b/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java
index 045ec15..315f789 100644
--- a/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java
+++ b/jdk/test/java/lang/invoke/ExplicitCastArgumentsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -21,79 +21,582 @@
* questions.
*/
-package java.lang.invoke;
-
+import com.oracle.testlibrary.jsr292.Helper;
+import java.io.File;
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.WrongMethodTypeException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
import sun.invoke.util.Wrapper;
-/* @test
+/*
+ * @test
+ * @bug 8060483 8066746
+ * @library /lib/testlibrary /lib/testlibrary/jsr292
* @summary unit tests for MethodHandles.explicitCastArguments()
- *
- * @run main/bootclasspath java.lang.invoke.ExplicitCastArgumentsTest
+ * @run main ExplicitCastArgumentsTest
+ */
+
+/**
+ * Tests for MethodHandles.explicitCastArguments().
*/
public class ExplicitCastArgumentsTest {
- private static final boolean VERBOSE = Boolean.getBoolean("verbose");
+
+ private static final boolean VERBOSE = Helper.IS_VERBOSE;
private static final Class<?> THIS_CLASS = ExplicitCastArgumentsTest.class;
+ private static final Random RNG = Helper.RNG;
+ private static final Map<Wrapper, Object> RANDOM_VALUES = new HashMap<>(9);
+
+ static {
+ RANDOM_VALUES.put(Wrapper.BOOLEAN, RNG.nextBoolean());
+ RANDOM_VALUES.put(Wrapper.BYTE, (byte) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.SHORT, (short) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.CHAR, (char) RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.INT, RNG.nextInt());
+ RANDOM_VALUES.put(Wrapper.LONG, RNG.nextLong());
+ RANDOM_VALUES.put(Wrapper.FLOAT, RNG.nextFloat());
+ RANDOM_VALUES.put(Wrapper.DOUBLE, RNG.nextDouble());
+ RANDOM_VALUES.put(Wrapper.OBJECT, new Object());
+ }
public static void main(String[] args) throws Throwable {
testVarargsCollector();
+ testNullRef2Prim();
testRef2Prim();
+ testPrim2Ref();
+ testPrim2Prim();
+ testNonBCPRef2NonBCPRef();
+ testBCPRef2BCPRef();
+ testNonBCPRef2BCPRef();
+ testReturnAny2Void();
+ testReturnVoid2Any();
+ testMultipleArgs();
System.out.println("TEST PASSED");
}
- public static String[] f(String... args) { return args; }
-
- public static void testVarargsCollector() throws Throwable {
- MethodType mt = MethodType.methodType(String[].class, String[].class);
- MethodHandle mh = MethodHandles.publicLookup().findStatic(THIS_CLASS, "f", mt);
- mh = MethodHandles.explicitCastArguments(mh, MethodType.methodType(Object.class, Object.class));
- mh.invokeWithArguments((Object)(new String[] {"str1", "str2"}));
+ /**
+ * Dummy method used in {@link #testVarargsCollector} test to form a method
+ * handle.
+ *
+ * @param args - any args
+ * @return - returns args
+ */
+ public static String[] f(String... args) {
+ return args;
}
- public static void testRef2Prim() throws Throwable {
+ /**
+ * Tests that MHs.explicitCastArguments does incorrect type checks for
+ * VarargsCollector. Bug 8066746.
+ *
+ * @throws java.lang.Throwable
+ */
+ public static void testVarargsCollector() throws Throwable {
+ MethodType mt = MethodType.methodType(String[].class, String[].class);
+ MethodHandle mh = MethodHandles.publicLookup()
+ .findStatic(THIS_CLASS, "f", mt);
+ mh = MethodHandles.explicitCastArguments(mh,
+ MethodType.methodType(Object.class, Object.class));
+ mh.invokeWithArguments((Object) (new String[]{"str1", "str2"}));
+ }
+
+ /**
+ * Tests that null wrapper reference is successfully converted to primitive
+ * types. Converted result should be zero for a primitive. Bug 8060483.
+ */
+ public static void testNullRef2Prim() {
for (Wrapper from : Wrapper.values()) {
for (Wrapper to : Wrapper.values()) {
- if (from == Wrapper.VOID || to == Wrapper.VOID) continue;
- testRef2Prim(from, to);
+ if (from == Wrapper.VOID || to == Wrapper.VOID) {
+ continue;
+ }
+ // MHs.eCA javadoc:
+ // If T0 is a reference and T1 a primitive, and if the reference
+ // is null at runtime, a zero value is introduced.
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ testConversion(mode, from.wrapperType(),
+ to.primitiveType(), null, to.zero(), false, null);
+ }
}
}
}
- public static void testRef2Prim(Wrapper from, Wrapper to) throws Throwable {
- // MHs.eCA javadoc:
- // If T0 is a reference and T1 a primitive, and if the reference is null at runtime, a zero value is introduced.
- test(from.wrapperType(), to.primitiveType(), null, false);
+ /**
+ * Tests that non-null wrapper reference is successfully converted to
+ * primitive types.
+ */
+ public static void testRef2Prim() {
+ for (Wrapper from : Wrapper.values()) {
+ for (Wrapper to : Wrapper.values()) {
+ if (from == Wrapper.VOID || to == Wrapper.VOID
+ || to == Wrapper.OBJECT) {
+ continue;
+ }
+ Object value = RANDOM_VALUES.get(from);
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ if (from != Wrapper.OBJECT) {
+ Object convValue = to.wrap(value);
+ testConversion(mode, from.wrapperType(),
+ to.primitiveType(), value, convValue, false, null);
+ } else {
+ testConversion(mode, from.wrapperType(),
+ to.primitiveType(), value, null,
+ true, ClassCastException.class);
+ }
+ }
+ }
+ }
}
- public static void test(Class<?> from, Class<?> to, Object param, boolean failureExpected) throws Throwable {
- if (VERBOSE) System.out.printf("%-10s => %-10s: %5s: ", from.getSimpleName(), to.getSimpleName(), param);
+ /**
+ * Tests that primitive is successfully converted to wrapper reference
+ * types, to the Number type (if possible) and to the Object type.
+ */
+ public static void testPrim2Ref() {
+ for (Wrapper from : Wrapper.values()) {
+ for (Wrapper to : Wrapper.values()) {
+ if (from == Wrapper.VOID || from == Wrapper.OBJECT
+ || to == Wrapper.VOID || to == Wrapper.OBJECT) {
+ continue;
+ }
+ Object value = RANDOM_VALUES.get(from);
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ if (from == to) {
+ testConversion(mode, from.primitiveType(),
+ to.wrapperType(), value, value, false, null);
+ } else {
+ testConversion(mode, from.primitiveType(),
+ to.wrapperType(), value, null, true, ClassCastException.class);
+ }
+ if (from != Wrapper.BOOLEAN && from != Wrapper.CHAR) {
+ testConversion(mode, from.primitiveType(),
+ Number.class, value, value, false, null);
+ } else {
+ testConversion(mode, from.primitiveType(),
+ Number.class, value, null,
+ true, ClassCastException.class);
+ }
+ testConversion(mode, from.primitiveType(),
+ Object.class, value, value, false, null);
+ }
+ }
+ }
+ }
- MethodHandle original = MethodHandles.identity(from);
- MethodType newType = original.type().changeReturnType(to);
+ /**
+ * Tests that primitive is successfully converted to other primitive type.
+ */
+ public static void testPrim2Prim() {
+ for (Wrapper from : Wrapper.values()) {
+ for (Wrapper to : Wrapper.values()) {
+ if (from == Wrapper.VOID || to == Wrapper.VOID
+ || from == Wrapper.OBJECT || to == Wrapper.OBJECT) {
+ continue;
+ }
+ Object value = RANDOM_VALUES.get(from);
+ Object convValue = to.wrap(value);
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ testConversion(mode, from.primitiveType(),
+ to.primitiveType(), value, convValue, false, null);
+ }
+ }
+ }
+ }
+ /**
+ * Dummy interface for {@link #testNonBCPRef2Ref} test.
+ */
+ public static interface TestInterface {}
+
+ /**
+ * Dummy class for {@link #testNonBCPRef2Ref} test.
+ */
+ public static class TestSuperClass implements TestInterface {}
+
+ /**
+ * Dummy class for {@link #testNonBCPRef2Ref} test.
+ */
+ public static class TestSubClass1 extends TestSuperClass {}
+
+ /**
+ * Dummy class for {@link #testNonBCPRef2Ref} test.
+ */
+ public static class TestSubClass2 extends TestSuperClass {}
+
+ /**
+ * Tests non-bootclasspath reference to reference conversions.
+ *
+ * @throws java.lang.Throwable
+ */
+ public static void testNonBCPRef2NonBCPRef() throws Throwable {
+ Class testInterface = TestInterface.class;
+ Class testSuperClass = TestSuperClass.class;
+ Class testSubClass1 = TestSubClass1.class;
+ Class testSubClass2 = TestSubClass2.class;
+ Object testSuperObj = new TestSuperClass();
+ Object testObj01 = new TestSubClass1();
+ Object testObj02 = new TestSubClass2();
+ Class[] parents = {testInterface, testSuperClass};
+ Class[] children = {testSubClass1, testSubClass2};
+ Object[] childInst = {testObj01, testObj02};
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ for (Class parent : parents) {
+ for (int j = 0; j < children.length; j++) {
+ // Child type to parent type non-null conversion, shoud succeed
+ testConversion(mode, children[j], parent, childInst[j], childInst[j], false, null);
+ // Child type to parent type null conversion, shoud succeed
+ testConversion(mode, children[j], parent, null, null, false, null);
+ // Parent type to child type non-null conversion with parent
+ // type instance, should fail
+ testConversion(mode, parent, children[j], testSuperObj, null, true, ClassCastException.class);
+ // Parent type to child type non-null conversion with child
+ // type instance, should succeed
+ testConversion(mode, parent, children[j], childInst[j], childInst[j], false, null);
+ // Parent type to child type null conversion, should succeed
+ testConversion(mode, parent, children[j], null, null, false, null);
+ }
+ // Parent type to child type non-null conversion with sibling
+ // type instance, should fail
+ testConversion(mode, parent, testSubClass1, testObj02, null, true, ClassCastException.class);
+ }
+ // Sibling type non-null conversion, should fail
+ testConversion(mode, testSubClass1,
+ testSubClass2, testObj01, null, true,
+ ClassCastException.class);
+ // Sibling type null conversion, should succeed
+ testConversion(mode, testSubClass1,
+ testSubClass2, null, null, false, null);
+ }
+ }
+
+ /**
+ * Dummy interface for {@link #testNonBCPRef2BCPRef} test.
+ */
+ public static interface TestSerializableInterface extends Serializable {}
+
+ /**
+ * Dummy class for {@link #testNonBCPRef2BCPRef} test.
+ */
+ public static class TestSerializableClass
+ implements TestSerializableInterface {}
+
+ /**
+ * Dummy class for {@link #testNonBCPRef2BCPRef} test.
+ */
+ public static class TestFileChildClass extends File
+ implements TestSerializableInterface {
+ public TestFileChildClass(String pathname) {
+ super(pathname);
+ }
+ }
+
+ /**
+ * Tests non-bootclasspath reference to bootclasspath reference conversions
+ * and vice-versa.
+ *
+ * @throws java.lang.Throwable
+ */
+ public static void testNonBCPRef2BCPRef() throws Throwable {
+ Class bcpInterface = Serializable.class;
+ Class bcpSuperClass = File.class;
+ Class nonBcpInterface = TestSerializableInterface.class;
+ Class nonBcpSuperSiblingClass = TestSerializableClass.class;
+ Class nonBcpSubClass = TestFileChildClass.class;
+ Object bcpSuperObj = new File(".");
+ Object testSuperSiblingObj = new TestSerializableClass();
+ Object testSubObj = new TestFileChildClass(".");
+ Class[] parents = {bcpInterface, bcpSuperClass};
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ for (Class parent : parents) {
+ // Child type to parent type non-null conversion, shoud succeed
+ testConversion(mode, nonBcpSubClass, parent, testSubObj,
+ testSubObj, false, null);
+ // Child type to parent type null conversion, shoud succeed
+ testConversion(mode, nonBcpSubClass, parent, null, null,
+ false, null);
+ // Parent type to child type non-null conversion with parent
+ // type instance, should fail
+ testConversion(mode, parent, nonBcpSubClass, bcpSuperObj, null,
+ true, ClassCastException.class);
+ // Parent type to child type non-null conversion with child
+ // type instance, should succeed
+ testConversion(mode, parent, nonBcpSubClass, testSubObj,
+ testSubObj, false, null);
+ // Parent type to child type null conversion, should succeed
+ testConversion(mode, parent, nonBcpSubClass, null, null,
+ false, null);
+ }
+ // Parent type to child type non-null conversion with
+ // super sibling type instance, should fail
+ testConversion(mode, bcpInterface, nonBcpSubClass,
+ testSuperSiblingObj, null, true, ClassCastException.class);
+ Class[] siblings = {nonBcpSubClass, bcpSuperClass};
+ for (Class sibling : siblings) {
+ // Non-bcp class to bcp/non-bcp sibling class non-null
+ // conversion with nonBcpSuperSiblingClass instance, should fail
+ testConversion(mode, nonBcpSuperSiblingClass, sibling,
+ testSuperSiblingObj, null, true, ClassCastException.class);
+ // Non-bcp class to bcp/non-bcp sibling class null conversion,
+ // should succeed
+ testConversion(mode, nonBcpSuperSiblingClass, sibling,
+ null, null, false, null);
+ // Non-bcp interface to bcp/non-bcp sibling class non-null
+ // conversion with nonBcpSubClass instance, should succeed
+ testConversion(mode, nonBcpInterface, sibling, testSubObj,
+ testSubObj, false, null);
+ // Non-bcp interface to bcp/non-bcp sibling class
+ // null conversion, should succeed
+ testConversion(mode, nonBcpInterface, sibling, null, null,
+ false, null);
+ // Non-bcp interface to bcp/non-bcp sibling class non-null
+ // conversion with nonBcpSuperSiblingClass instance, should fail
+ testConversion(mode, nonBcpInterface, sibling,
+ testSuperSiblingObj, testSubObj,
+ true, ClassCastException.class);
+ }
+ }
+ }
+
+ /**
+ * Tests bootclasspath reference to reference conversions.
+ */
+ public static void testBCPRef2BCPRef() {
+ Class bcpInterface = CharSequence.class;
+ Class bcpSubClass1 = String.class;
+ Class bcpSubClass2 = StringBuffer.class;
+ Object testObj01 = new String("test");
+ Object testObj02 = new StringBuffer("test");
+ Class[] children = {bcpSubClass1, bcpSubClass2};
+ Object[] childInst = {testObj01, testObj02};
+ for (TestConversionMode mode : TestConversionMode.values()) {
+ for (int i = 0; i < children.length; i++) {
+ // Child type to parent type non-null conversion, shoud succeed
+ testConversion(mode, children[i], bcpInterface, childInst[i],
+ childInst[i], false, null);
+ // Child type to parent type null conversion, shoud succeed
+ testConversion(mode, children[i], bcpInterface, null,
+ null, false, null);
+ // Parent type to child type non-null conversion with child
+ // type instance, should succeed
+ testConversion(mode, bcpInterface,
+ children[i], childInst[i], childInst[i], false, null);
+ // Parent type to child type null conversion, should succeed
+ testConversion(mode, bcpInterface,
+ children[i], null, null, false, null);
+ }
+ // Sibling type non-null conversion, should fail
+ testConversion(mode, bcpSubClass1,
+ bcpSubClass2, testObj01, null, true,
+ ClassCastException.class);
+ // Sibling type null conversion, should succeed
+ testConversion(mode, bcpSubClass1,
+ bcpSubClass2, null, null, false, null);
+ // Parent type to child type non-null conversion with sibling
+ // type instance, should fail
+ testConversion(mode, bcpInterface, bcpSubClass1, testObj02,
+ null, true, ClassCastException.class);
+ }
+ }
+
+ /**
+ * Dummy method used in {@link #testReturnAny2Void} and
+ * {@link #testReturnVoid2Any} tests to form a method handle.
+ */
+ public static void retVoid() {}
+
+ /**
+ * Tests that non-null any return is successfully converted to non-type
+ * void.
+ */
+ public static void testReturnAny2Void() {
+ for (Wrapper from : Wrapper.values()) {
+ testConversion(TestConversionMode.RETURN_VALUE, from.wrapperType(),
+ void.class, RANDOM_VALUES.get(from),
+ null, false, null);
+ testConversion(TestConversionMode.RETURN_VALUE, from.primitiveType(),
+ void.class, RANDOM_VALUES.get(from),
+ null, false, null);
+ }
+ }
+
+ /**
+ * Tests that void return is successfully converted to primitive and
+ * reference. Result should be zero for primitives and null for references.
+ */
+ public static void testReturnVoid2Any() {
+ for (Wrapper to : Wrapper.values()) {
+ testConversion(TestConversionMode.RETURN_VALUE, void.class,
+ to.primitiveType(), null,
+ to.zero(), false, null);
+ testConversion(TestConversionMode.RETURN_VALUE, void.class,
+ to.wrapperType(), null,
+ null, false, null);
+ }
+ }
+
+ private static void checkForWrongMethodTypeException(MethodHandle mh, MethodType mt) {
try {
- MethodHandle target = MethodHandles.explicitCastArguments(original, newType);
- Object result = target.invokeWithArguments(param);
+ MethodHandles.explicitCastArguments(mh, mt);
+ throw new AssertionError("Expected WrongMethodTypeException is not thrown");
+ } catch (WrongMethodTypeException wmte) {
+ if (VERBOSE) {
+ System.out.printf("Expected exception %s: %s\n",
+ wmte.getClass(), wmte.getMessage());
+ }
+ }
+ }
+ /**
+ * Tests that MHs.eCA method works correctly with MHs with multiple arguments.
+ * @throws Throwable
+ */
+ public static void testMultipleArgs() throws Throwable {
+ int arity = 1 + RNG.nextInt(Helper.MAX_ARITY / 2 - 2);
+ int arityMinus = RNG.nextInt(arity);
+ int arityPlus = arity + RNG.nextInt(Helper.MAX_ARITY / 2 - arity) + 1;
+ MethodType mType = Helper.randomMethodTypeGenerator(arity);
+ MethodType mTypeNew = Helper.randomMethodTypeGenerator(arity);
+ MethodType mTypeNewMinus = Helper.randomMethodTypeGenerator(arityMinus);
+ MethodType mTypeNewPlus = Helper.randomMethodTypeGenerator(arityPlus);
+ Class<?> rType = mType.returnType();
+ MethodHandle original;
+ if (rType.equals(void.class)) {
+ MethodType mt = MethodType.methodType(void.class);
+ original = MethodHandles.publicLookup()
+ .findStatic(THIS_CLASS, "retVoid", mt);
+ } else {
+ Object rValue = Helper.castToWrapper(1, rType);
+ original = MethodHandles.constant(rType, rValue);
+ }
+ original = Helper.addTrailingArgs(original, arity, mType.parameterList());
+ MethodHandle target = MethodHandles
+ .explicitCastArguments(original, mTypeNew);
+ Object[] parList = Helper.randomArgs(mTypeNew.parameterList());
+ for (int i = 0; i < parList.length; i++) {
+ if (parList[i] instanceof String) {
+ parList[i] = null; //getting rid of Stings produced by randomArgs
+ }
+ }
+ target.invokeWithArguments(parList);
+ checkForWrongMethodTypeException(original, mTypeNewMinus);
+ checkForWrongMethodTypeException(original, mTypeNewPlus);
+ }
+
+ /**
+ * Enumeration of test conversion modes.
+ */
+ public enum TestConversionMode {
+ RETURN_VALUE,
+ ARGUMENT;
+ }
+
+ /**
+ * Tests type and value conversion. Comparing with the given expected result.
+ *
+ * @param mode - test conversion mode. See {@link #TestConversionMode}.
+ * @param from - source type.
+ * @param to - destination type.
+ * @param param - value to be converted.
+ * @param expectedResult - expected value after conversion.
+ * @param failureExpected - true if conversion failure expected.
+ * @param expectedException - expected exception class if
+ * {@code failureExpected} is true.
+ */
+ public static void testConversion(TestConversionMode mode,
+ Class<?> from, Class<?> to, Object param,
+ Object expectedResult, boolean failureExpected,
+ Class<? extends Throwable> expectedException) {
+ if (VERBOSE) {
+ System.out.printf("Testing return value conversion: "
+ + "%-10s => %-10s: %5s: ", from.getSimpleName(),
+ to.getSimpleName(), param);
+ }
+ MethodHandle original = null;
+ MethodType newType = null;
+ switch (mode) {
+ case RETURN_VALUE:
+ if (from.equals(void.class)) {
+ MethodType mt = MethodType.methodType(void.class);
+ try {
+ original = MethodHandles.publicLookup()
+ .findStatic(THIS_CLASS, "retVoid", mt);
+ } catch (NoSuchMethodException | IllegalAccessException ex) {
+ throw new Error("Unexpected issue", ex);
+ }
+ } else {
+ original = MethodHandles.constant(from, param);
+ }
+ newType = original.type().changeReturnType(to);
+ break;
+ case ARGUMENT:
+ if (from.equals(void.class) || to.equals(void.class)) {
+ throw new Error("Test issue: argument conversion does not"
+ + " work with non-type void");
+ }
+ original = MethodHandles.identity(to);
+ newType = original.type().changeParameterType(0, from);
+ break;
+ default:
+ String msg = String.format("Test issue: unknown test"
+ + " convertion mode %s.", mode.name());
+ throw new Error(msg);
+ }
+ try {
+ MethodHandle target = MethodHandles
+ .explicitCastArguments(original, newType);
+ Object result;
+ switch (mode) {
+ case RETURN_VALUE:
+ result = target.invokeWithArguments();
+ break;
+ case ARGUMENT:
+ result = target.invokeWithArguments(param);
+ break;
+ default:
+ String msg = String.format("Test issue: unknown test"
+ + " convertion mode %s.", mode.name());
+ throw new Error(msg);
+ }
+ if (!failureExpected
+ && (expectedResult != null && !expectedResult.equals(result)
+ || expectedResult == null && result != null)) {
+ String msg = String.format("Conversion result %s is not equal"
+ + " to the expected result %10s",
+ result, expectedResult);
+ throw new AssertionError(msg);
+ }
if (VERBOSE) {
String resultStr;
if (result != null) {
- resultStr = String.format("%10s (%10s)", "'"+result+"'", result.getClass().getSimpleName());
+ resultStr = String.format("Converted value and type are"
+ + " %10s (%10s)", "'" + result + "'",
+ result.getClass().getSimpleName());
} else {
- resultStr = String.format("%10s", result);
+ resultStr = String.format("Converted value is %10s", result);
}
System.out.println(resultStr);
}
-
if (failureExpected) {
- String msg = String.format("No exception thrown: %s => %s; parameter: %s", from, to, param);
+ String msg = String.format("No exception thrown while testing"
+ + " return value conversion: %10s => %10s;"
+ + " parameter: %10s",
+ from, to, param);
throw new AssertionError(msg);
}
} catch (AssertionError e) {
throw e; // report test failure
} catch (Throwable e) {
- if (VERBOSE) System.out.printf("%s: %s\n", e.getClass(), e.getMessage());
- if (!failureExpected) {
- String msg = String.format("Unexpected exception was thrown: %s => %s; parameter: %s", from, to, param);
+ if (VERBOSE) {
+ System.out.printf("%s: %s\n", e.getClass(), e.getMessage());
+ }
+ if (!failureExpected || !e.getClass().equals(expectedException)) {
+ String msg = String.format("Unexpected exception was thrown"
+ + " while testing return value conversion:"
+ + " %s => %s; parameter: %s", from, to, param);
throw new AssertionError(msg, e);
}
}
diff --git a/jdk/test/java/lang/invoke/LFCaching/TestMethods.java b/jdk/test/java/lang/invoke/LFCaching/TestMethods.java
index 8753073..fe63b25 100644
--- a/jdk/test/java/lang/invoke/LFCaching/TestMethods.java
+++ b/jdk/test/java/lang/invoke/LFCaching/TestMethods.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -207,7 +207,7 @@
return MethodHandles.filterReturnValue(target, filter);
}
},
- INSERT_ARGUMENTS("insertArguments") {
+ INSERT_ARGUMENTS("insertArguments", Helper.MAX_ARITY - 3) {
@Override
public Map<String, Object> getTestCaseData() {
Map<String, Object> data = new HashMap<>();
@@ -610,26 +610,7 @@
* @return MethodType generated randomly.
*/
private static MethodType randomMethodTypeGenerator(int arity) {
- final Class<?>[] CLASSES = {
- Object.class,
- int.class,
- boolean.class,
- byte.class,
- short.class,
- char.class,
- long.class,
- float.class,
- double.class
- };
- if (arity > Helper.MAX_ARITY) {
- throw new IllegalArgumentException(
- String.format("Arity should not exceed %d!", Helper.MAX_ARITY));
- }
- List<Class<?>> list = Helper.randomClasses(CLASSES, arity);
- list = Helper.getParams(list, false, arity);
- int i = Helper.RNG.nextInt(CLASSES.length + 1);
- Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i];
- return MethodType.methodType(rtype, list);
+ return Helper.randomMethodTypeGenerator(arity);
}
/**
diff --git a/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java
index ecfca10..408cf99 100644
--- a/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java
+++ b/jdk/test/java/lang/invoke/MethodHandles/CatchExceptionTest.java
@@ -168,6 +168,11 @@
try {
returned = target.invokeWithArguments(args);
} catch (Throwable ex) {
+ if (CodeCacheOverflowProcessor.isThrowableCausedByVME(ex)) {
+ // This error will be treated by CodeCacheOverflowProcessor
+ // to prevent the test from failing because of code cache overflow.
+ throw new Error(ex);
+ }
testCase.assertCatch(ex);
returned = ex;
}
diff --git a/jdk/test/java/lang/management/ThreadMXBean/ThreadInfoArray.java b/jdk/test/java/lang/management/ThreadMXBean/ThreadInfoArray.java
index 8b50434..14ff985 100644
--- a/jdk/test/java/lang/management/ThreadMXBean/ThreadInfoArray.java
+++ b/jdk/test/java/lang/management/ThreadMXBean/ThreadInfoArray.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -23,11 +23,12 @@
/*
* @test
- * @bug 5058327
- * @summary Test if getThreadInfo(long[]) returns a ThreadInfo[]
- * with null elements with no exception.
+ * @bug 5058327 8074368
+ * @summary Tests the correct behaviour of getThreadInfo(long[]) for non-existent
+ * thread IDs and the empty thread id array.
*
* @author Mandy Chung
+ * @author Jaroslav Bachorik
*
* @build ThreadInfoArray
* @run main ThreadInfoArray
@@ -35,15 +36,30 @@
import java.lang.management.*;
import javax.management.*;
-import java.util.*;
import static java.lang.management.ManagementFactory.*;
public class ThreadInfoArray {
public static void main(String[] argv) throws Exception {
- ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
+ MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+ ObjectName on = new ObjectName(THREAD_MXBEAN_NAME);
+ ThreadMXBean mbean = ManagementFactory.getThreadMXBean();
+ ThreadMXBean proxy = newPlatformMXBeanProxy(mbs,
+ on.toString(),
+ ThreadMXBean.class);
+
+ checkNullElement(mbean, proxy, mbs, on);
+ checkEmptyArray(mbean, proxy, mbs, on);
+ System.out.println("Test passed");
+ }
+
+ private static void checkNullElement(ThreadMXBean mbean, ThreadMXBean proxy,
+ MBeanServer mbs, ObjectName on)
+ throws Exception {
+ System.out.println("--- Check null element");
// ID for a new thread
long [] ids = {new Thread().getId()};
+ // direct call
ThreadInfo[] tinfos = mbean.getThreadInfo(ids);
if (tinfos[0] != null) {
@@ -52,8 +68,6 @@
}
// call getThreadInfo through MBeanServer
- MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
- ObjectName on = new ObjectName(THREAD_MXBEAN_NAME);
Object[] params = {ids};
String[] sigs = {"[J"};
Object[] result = (Object[]) mbs.invoke(on, "getThreadInfo", params, sigs);
@@ -64,14 +78,57 @@
}
// call getThreadInfo through proxy
- ThreadMXBean proxy = newPlatformMXBeanProxy(mbs,
- on.toString(),
- ThreadMXBean.class);
tinfos = proxy.getThreadInfo(ids);
if (tinfos[0] != null) {
throw new RuntimeException("TEST FAILED: " +
"Expected to have a null element");
}
- System.out.println("Test passed");
+ System.out.println("--- PASSED");
+ }
+
+ private static void checkEmptyArray(ThreadMXBean mbean, ThreadMXBean proxy,
+ MBeanServer mbs, ObjectName on)
+ throws Exception {
+ System.out.println("--- Check empty TID array");
+
+ long[] ids = new long[0];
+ // direct call
+ assertEmptyArray(mbean.getThreadInfo(ids), "Expected empty ThreadInfo array");
+ assertEmptyArray(mbean.getThreadInfo(ids, 1), "Expected empty ThreadInfo array");
+ assertEmptyArray(mbean.getThreadInfo(ids, true, true), "Expected empty ThreadInfo array");
+
+ // call getThreadInfo through MBeanServer
+ assertEmptyArray(
+ (Object[]) mbs.invoke(
+ on, "getThreadInfo", new Object[]{ids}, new String[]{"[J"}
+ ),
+ "Expected empty ThreadInfo array via MBeanServer"
+ );
+ assertEmptyArray(
+ (Object[]) mbs.invoke(
+ on, "getThreadInfo", new Object[]{ids, 1},
+ new String[]{"[J", "int"}
+ ),
+ "Expected empty ThreadInfo array via MBeanServer"
+ );
+ assertEmptyArray(
+ (Object[]) mbs.invoke(
+ on, "getThreadInfo", new Object[]{ids, true, true},
+ new String[]{"[J", "boolean", "boolean"}
+ ),
+ "Expected empty ThreadInfo array via MBeanServer"
+ );
+
+ // call getThreadInfo through proxy
+ assertEmptyArray(proxy.getThreadInfo(ids), "Expected empty ThreadInfo array");
+ assertEmptyArray(proxy.getThreadInfo(ids, 1), "Expected empty ThreadInfo array");
+ assertEmptyArray(proxy.getThreadInfo(ids, true, true), "Expected empty ThreadInfo array");
+ System.out.println("--- PASSED");
+ }
+
+ private static void assertEmptyArray(Object[] arr, String message) throws Exception {
+ if (arr.length > 0) {
+ throw new RuntimeException("TEST FAILED: " + message);
+ }
}
}
diff --git a/jdk/test/java/net/Inet4Address/PingThis.java b/jdk/test/java/net/Inet4Address/PingThis.java
index d302df5..4f9f3de 100644
--- a/jdk/test/java/net/Inet4Address/PingThis.java
+++ b/jdk/test/java/net/Inet4Address/PingThis.java
@@ -26,7 +26,7 @@
*/
/* @test
- * @bug 7163874
+ * @bug 7163874 8133015
* @summary InetAddress.isReachable is returning false
* for InetAdress 0.0.0.0 and ::0
* @run main PingThis
diff --git a/jdk/test/java/net/Inet4Address/textToNumericFormat.java b/jdk/test/java/net/Inet4Address/textToNumericFormat.java
index be5d8ab..25022c0 100644
--- a/jdk/test/java/net/Inet4Address/textToNumericFormat.java
+++ b/jdk/test/java/net/Inet4Address/textToNumericFormat.java
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 4749938
+ * @bug 4749938 8087190
* @summary Bug in the parsing IPv4 literal addresses
* @compile -XDignore.symbol.file=true DummyNameService.java DummyNameServiceDescriptor.java
* @run main/othervm -Dsun.net.spi.nameservice.provider.1=dummy,oracle textToNumericFormat
@@ -62,7 +62,11 @@
"2380.255.255.255",
"239.255.65536",
"239.16777216",
- "4294967296" };
+ "4294967296",
+ ".1.1.1",
+ "1..1.1",
+ "1.1.1.",
+ "..." };
for (int i=0; i<goodAddrs.length; i++) {
try {
diff --git a/jdk/test/java/net/InetAddress/IsHostReachableBug.java b/jdk/test/java/net/InetAddress/IsHostReachableBug.java
index c761b01..8f133ca 100644
--- a/jdk/test/java/net/InetAddress/IsHostReachableBug.java
+++ b/jdk/test/java/net/InetAddress/IsHostReachableBug.java
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4922568
+ * @bug 4922568 8133015
* @run main/othervm -Djava.net.preferIPv4Stack=true IsHostReachableBug
* @summary isReachable returns true for IPv6
*/
diff --git a/jdk/test/java/net/InetAddress/IsReachable.java b/jdk/test/java/net/InetAddress/IsReachable.java
index da868c5..138ae53 100644
--- a/jdk/test/java/net/InetAddress/IsReachable.java
+++ b/jdk/test/java/net/InetAddress/IsReachable.java
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4639861
+ * @bug 4639861 8133015
* @summary API to test reachability of a host
*/
import java.net.InetAddress;
diff --git a/jdk/test/java/net/InetAddress/IsReachableViaLoopbackTest.java b/jdk/test/java/net/InetAddress/IsReachableViaLoopbackTest.java
new file mode 100644
index 0000000..4d7f266
--- /dev/null
+++ b/jdk/test/java/net/InetAddress/IsReachableViaLoopbackTest.java
@@ -0,0 +1,40 @@
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * @test
+ * @bug 8135305
+ * @summary ensure we can't ping external hosts via loopback if
+ */
+
+public class IsReachableViaLoopbackTest {
+ public static void main(String[] args) {
+ try {
+ InetAddress addr = InetAddress.getByName("localhost");
+ InetAddress remoteAddr = InetAddress.getByName("bugs.openjdk.java.net");
+ if (!addr.isReachable(10000))
+ throw new RuntimeException("Localhost should always be reachable");
+ NetworkInterface inf = NetworkInterface.getByInetAddress(addr);
+ if (inf != null) {
+ if (!addr.isReachable(inf, 20, 10000)) {
+ throw new RuntimeException("Localhost should always be reachable");
+ } else {
+ System.out.println(addr + " is reachable");
+ }
+ if (remoteAddr.isReachable(inf, 20, 10000)) {
+ throw new RuntimeException(remoteAddr + " is reachable");
+ } else {
+ System.out.println(remoteAddr + " is NOT reachable");
+ }
+ } else {
+ System.out.println("inf == null");
+ }
+
+ } catch (IOException e) {
+ throw new RuntimeException("Unexpected exception:" + e);
+ }
+ System.out.println("IsReachableViaLoopbackTest EXIT");
+ }
+}
+
diff --git a/jdk/test/java/net/MulticastSocket/MultiDead.java b/jdk/test/java/net/MulticastSocket/MultiDead.java
new file mode 100644
index 0000000..d542b22
--- /dev/null
+++ b/jdk/test/java/net/MulticastSocket/MultiDead.java
@@ -0,0 +1,128 @@
+/*
+ * 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 8072466
+ * @summary Deadlock when initializing MulticastSocket and DatagramSocket
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @run main/othervm MultiDead
+ */
+
+import java.net.DatagramSocket;
+import java.net.MulticastSocket;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import jdk.testlibrary.JDKToolLauncher;
+import jdk.testlibrary.Utils;
+
+public class MultiDead {
+ private static final int THREAD_PAIR_COUNT = 4;
+ private static final int CHILDREN_COUNT = 20;
+ // at least 2.5 seconds for a child to complete
+ private static final long CHILD_TIMEOUT = 2500;
+ private static final long TIMEOUT =
+ Utils.adjustTimeout(CHILDREN_COUNT * CHILD_TIMEOUT * 2);
+
+ public static void main(String[] args) throws Throwable {
+ if (args.length == 0 || args[0].equals("parent")) {
+ parentProcess();
+ }
+
+ if (args.length > 0 && args[0].equals("child")) {
+ childProcess();
+ }
+ }
+
+ private static void parentProcess() throws Throwable {
+ JDKToolLauncher launcher = JDKToolLauncher
+ .createUsingTestJDK("java")
+ .addToolArg("MultiDead")
+ .addToolArg("child");
+ ProcessBuilder pb = new ProcessBuilder(launcher.getCommand());
+
+ AtomicReference<Process> child = new AtomicReference<>();
+ AtomicBoolean stopFlag = new AtomicBoolean(false);
+
+ Thread th = new Thread(() -> {
+ for (int i = 0; i < CHILDREN_COUNT; ++i) {
+ System.out.println("child #" + (i + 1) + " of " +
+ CHILDREN_COUNT);
+ long start = System.nanoTime();
+ try {
+ child.set(pb.start());
+ child.get().waitFor();
+ if (stopFlag.get()) {
+ break;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ if (System.nanoTime() - start >
+ MILLISECONDS.toNanos(CHILD_TIMEOUT)) {
+ System.err.println("Machine is too slow, " +
+ "skipping the test...");
+ break;
+ }
+ }
+ });
+
+ th.start();
+ th.join(TIMEOUT);
+
+ stopFlag.set(true);
+ if (th.isAlive()) {
+ if (child.get() != null) {
+ child.get().destroyForcibly();
+ }
+ throw new RuntimeException("Failed to complete on time.");
+ }
+ }
+
+ private static void childProcess() {
+ CountDownLatch latch = new CountDownLatch(1);
+ for (int i = 0; i < THREAD_PAIR_COUNT; ++i) {
+ new Thread(() -> {
+ try {
+ latch.await();
+ try (MulticastSocket a = new MulticastSocket(6000)) {
+ }
+ } catch (Exception ignore) {
+ }
+ }).start();
+
+ new Thread(() -> {
+ try {
+ latch.await();
+ try (DatagramSocket b = new DatagramSocket(6000)) {
+ }
+ } catch (Exception ignore) {
+ }
+ }).start();
+ }
+ latch.countDown();
+ }
+}
diff --git a/jdk/test/java/nio/Buffer/DirectBufferAllocTest.java b/jdk/test/java/nio/Buffer/DirectBufferAllocTest.java
new file mode 100644
index 0000000..3a4d815
--- /dev/null
+++ b/jdk/test/java/nio/Buffer/DirectBufferAllocTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 6857566
+ * @summary DirectByteBuffer garbage creation can outpace reclamation
+ *
+ * @run main/othervm -XX:MaxDirectMemorySize=128m DirectBufferAllocTest
+ */
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class DirectBufferAllocTest {
+ // defaults
+ static final int RUN_TIME_SECONDS = 5;
+ static final int MIN_THREADS = 4;
+ static final int MAX_THREADS = 64;
+ static final int CAPACITY = 1024 * 1024; // bytes
+
+ /**
+ * This test spawns multiple threads that constantly allocate direct
+ * {@link ByteBuffer}s in a loop, trying to provoke {@link OutOfMemoryError}.<p>
+ * When run without command-line arguments, it runs as a regression test
+ * for at most 5 seconds.<p>
+ * Command line arguments:
+ * <pre>
+ * -r run-time-seconds <i>(duration of successful test - default 5 s)</i>
+ * -t threads <i>(default is 2 * # of CPUs, at least 4 but no more than 64)</i>
+ * -c capacity <i>(of direct buffers in bytes - default is 1MB)</i>
+ * -p print-alloc-time-batch-size <i>(every "batch size" iterations,
+ * average time per allocation is printed)</i>
+ * </pre>
+ * Use something like the following to run a 10 minute stress test and
+ * print allocation times as it goes:
+ * <pre>
+ * java -XX:MaxDirectMemorySize=128m DirectBufferAllocTest -r 600 -t 32 -p 5000
+ * </pre>
+ */
+ public static void main(String[] args) throws Exception {
+ int runTimeSeconds = RUN_TIME_SECONDS;
+ int threads = Math.max(
+ Math.min(
+ Runtime.getRuntime().availableProcessors() * 2,
+ MAX_THREADS
+ ),
+ MIN_THREADS
+ );
+ int capacity = CAPACITY;
+ int printBatchSize = 0;
+
+ // override with command line arguments
+ for (int i = 0; i < args.length; i++) {
+ switch (args[i]) {
+ case "-r":
+ runTimeSeconds = Integer.parseInt(args[++i]);
+ break;
+ case "-t":
+ threads = Integer.parseInt(args[++i]);
+ break;
+ case "-c":
+ capacity = Integer.parseInt(args[++i]);
+ break;
+ case "-p":
+ printBatchSize = Integer.parseInt(args[++i]);
+ break;
+ default:
+ System.err.println(
+ "Usage: java" +
+ " [-XX:MaxDirectMemorySize=XXXm]" +
+ " DirectBufferAllocTest" +
+ " [-r run-time-seconds]" +
+ " [-t threads]" +
+ " [-c capacity-of-direct-buffers]" +
+ " [-p print-alloc-time-batch-size]"
+ );
+ System.exit(-1);
+ }
+ }
+
+ System.out.printf(
+ "Allocating direct ByteBuffers with capacity %d bytes, using %d threads for %d seconds...\n",
+ capacity, threads, runTimeSeconds
+ );
+
+ ExecutorService executor = Executors.newFixedThreadPool(threads);
+
+ int pbs = printBatchSize;
+ int cap = capacity;
+
+ List<Future<Void>> futures =
+ IntStream.range(0, threads)
+ .mapToObj(
+ i -> (Callable<Void>) () -> {
+ long t0 = System.nanoTime();
+ loop:
+ while (true) {
+ for (int n = 0; pbs == 0 || n < pbs; n++) {
+ if (Thread.interrupted()) {
+ break loop;
+ }
+ ByteBuffer.allocateDirect(cap);
+ }
+ long t1 = System.nanoTime();
+ if (pbs > 0) {
+ System.out.printf(
+ "Thread %2d: %5.2f ms/allocation\n",
+ i, ((double) (t1 - t0) / (1_000_000d * pbs))
+ );
+ }
+ t0 = t1;
+ }
+ return null;
+ }
+ )
+ .map(executor::submit)
+ .collect(Collectors.toList());
+
+ for (int i = 0; i < runTimeSeconds; i++) {
+ if (futures.stream().anyMatch(Future::isDone)) {
+ break;
+ }
+ Thread.sleep(1000L);
+ }
+
+ Exception exception = null;
+ for (Future<Void> future : futures) {
+ if (future.isDone()) {
+ try {
+ future.get();
+ } catch (ExecutionException e) {
+ if (exception == null) {
+ exception = new RuntimeException("Errors encountered!");
+ }
+ exception.addSuppressed(e.getCause());
+ }
+ } else {
+ future.cancel(true);
+ }
+ }
+
+ executor.shutdown();
+
+ if (exception != null) {
+ throw exception;
+ } else {
+ System.out.printf("No errors after %d seconds.\n", runTimeSeconds);
+ }
+ }
+}
diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java
index 4627aaa..642435d 100644
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/StressLoopback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 6834246 6842687
+ * @bug 6834246 6842687 8133647
* @summary Stress test connections through the loopback interface
* @run main StressLoopback
* @run main/othervm -Djdk.net.useFastTcpLoopback StressLoopback
diff --git a/jdk/test/java/nio/channels/FileChannel/LoopingTruncate.java b/jdk/test/java/nio/channels/FileChannel/LoopingTruncate.java
new file mode 100644
index 0000000..f81712c
--- /dev/null
+++ b/jdk/test/java/nio/channels/FileChannel/LoopingTruncate.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 8137121 8137230
+ * @summary (fc) Infinite loop FileChannel.truncate
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.Utils
+ * @run main/othervm LoopingTruncate
+ */
+
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import static java.nio.file.StandardOpenOption.*;
+import static jdk.testlibrary.Utils.adjustTimeout;
+
+public class LoopingTruncate {
+
+ // (int)FATEFUL_SIZE == -3 == IOStatus.INTERRUPTED
+ static long FATEFUL_SIZE = 0x1FFFFFFFDL;
+
+ // At least 20 seconds
+ static long TIMEOUT = adjustTimeout(20_000);
+
+ public static void main(String[] args) throws Throwable {
+ Path path = Files.createTempFile("LoopingTruncate.tmp", null);
+ try (FileChannel fc = FileChannel.open(path, CREATE, WRITE)) {
+ fc.position(FATEFUL_SIZE + 1L);
+ fc.write(ByteBuffer.wrap(new byte[] {0}));
+
+ Thread th = new Thread(() -> {
+ try {
+ fc.truncate(FATEFUL_SIZE);
+ } catch (ClosedByInterruptException ignore) {
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }});
+ th.start();
+ th.join(TIMEOUT);
+
+ if (th.isAlive()) {
+ System.err.println("=== Stack trace of the guilty thread:");
+ for (StackTraceElement el : th.getStackTrace()) {
+ System.err.println("\t" + el);
+ }
+ System.err.println("===");
+
+ th.interrupt();
+ th.join();
+ throw new RuntimeException("Failed to complete on time");
+ }
+ } finally {
+ Files.deleteIfExists(path);
+ }
+ }
+}
diff --git a/jdk/test/java/nio/file/Files/probeContentType/ParallelProbes.java b/jdk/test/java/nio/file/Files/probeContentType/ParallelProbes.java
new file mode 100644
index 0000000..bfa1ec9
--- /dev/null
+++ b/jdk/test/java/nio/file/Files/probeContentType/ParallelProbes.java
@@ -0,0 +1,96 @@
+/*
+ * 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.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+
+/* @test
+ * @summary Test probing content type simultaneously from multiple threads.
+ * @requires (os.family == "linux") | (os.family == "solaris")
+ * @run main/othervm ParallelProbes 10
+ */
+public class ParallelProbes {
+
+ private static final int REPEATS = 1000;
+
+ private int numThreads = 0;
+ private ArrayList<Thread> threads;
+
+ public ParallelProbes(int numThreads) {
+ System.out.println("Using <" + numThreads + "> threads.");
+ this.numThreads = numThreads;
+ this.threads = new ArrayList<Thread>(numThreads);
+ }
+
+ private Path createTmpFile() throws IOException {
+ final Path p = Files.createTempFile("prefix", ".json");
+ Files.write(p, "{\"test\"}".getBytes());
+ System.out.println("Write test file <" + p + ">");
+ return p;
+ }
+
+ private Runnable createRunnable(final Path p) {
+ Runnable r = new Runnable() {
+ public void run() {
+ for (int i = 0; i < REPEATS; i++) {
+ try {
+ System.out.println(Thread.currentThread().getName()
+ + " -> " + Files.probeContentType(p));
+ } catch (IOException ioException) {
+ ioException.printStackTrace();
+ }
+ }
+ }
+ };
+ return r;
+ }
+
+ public void start() throws IOException {
+ for (int i = 0; i < numThreads; i++) {
+ final Path p = createTmpFile();
+ Runnable r = createRunnable(p);
+ Thread thread = new Thread(r, "thread-" + i);
+ thread.start();
+ threads.add(thread);
+ }
+ }
+
+ public void join() {
+ for (Thread thread : threads) {
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ // ignore it and proceed to the next one
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ ParallelProbes probes =
+ new ParallelProbes(args.length < 1 ? 1 : Integer.parseInt(args[0]));
+ probes.start();
+ probes.join();
+ }
+}
diff --git a/jdk/test/java/nio/file/WatchService/LotsOfCancels.java b/jdk/test/java/nio/file/WatchService/LotsOfCancels.java
new file mode 100644
index 0000000..cb7f9ef
--- /dev/null
+++ b/jdk/test/java/nio/file/WatchService/LotsOfCancels.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 8029516
+ * @summary Bash on WatchKey.cancel with a view to causing a crash when
+ * an outstanding I/O operation on directory completes after the
+ * directory has been closed
+ */
+
+import java.nio.file.ClosedWatchServiceException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import static java.nio.file.StandardWatchEventKinds.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class LotsOfCancels {
+
+ // set to true for any exceptions
+ static volatile boolean failed;
+
+ public static void main(String[] args) throws Exception {
+
+ // create a bunch of directories. Create two tasks for each directory,
+ // one to bash on cancel, the other to poll the events
+ ExecutorService pool = Executors.newCachedThreadPool();
+ try {
+ Path top = Files.createTempDirectory("work");
+ top.toFile().deleteOnExit();
+ for (int i=1; i<=16; i++) {
+ Path dir = Files.createDirectory(top.resolve("dir-" + i));
+ WatchService watcher = FileSystems.getDefault().newWatchService();
+ pool.submit(() -> handle(dir, watcher));
+ pool.submit(() -> poll(watcher));
+ }
+ } finally {
+ pool.shutdown();
+ }
+
+ // give thread pool lots of time to terminate
+ if (!pool.awaitTermination(5L, TimeUnit.MINUTES))
+ throw new RuntimeException("Thread pool did not terminate");
+
+ if (failed)
+ throw new RuntimeException("Test failed, see log for details");
+ }
+
+ /**
+ * Stress the given WatchService, specifically the cancel method, in
+ * the given directory. Closes the WatchService when done.
+ */
+ static void handle(Path dir, WatchService watcher) {
+ try {
+ try {
+ Path file = dir.resolve("anyfile");
+ for (int i=0; i<2000; i++) {
+ WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE);
+ Files.createFile(file);
+ Files.delete(file);
+ key.cancel();
+ }
+ } finally {
+ watcher.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ failed = true;
+ }
+ }
+
+ /**
+ * Polls the given WatchService in a tight loop. This keeps the event
+ * queue drained, it also hogs a CPU core which seems necessary to
+ * tickle the original bug.
+ */
+ static void poll(WatchService watcher) {
+ try {
+ for (;;) {
+ WatchKey key = watcher.take();
+ if (key != null) {
+ key.pollEvents();
+ key.reset();
+ }
+ }
+ } catch (ClosedWatchServiceException expected) {
+ // nothing to do
+ } catch (Exception e) {
+ e.printStackTrace();
+ failed = true;
+ }
+ }
+
+}
+
diff --git a/jdk/test/java/security/KeyStore/CheckInputStream.java b/jdk/test/java/security/KeyStore/CheckInputStream.java
new file mode 100644
index 0000000..64b8539
--- /dev/null
+++ b/jdk/test/java/security/KeyStore/CheckInputStream.java
@@ -0,0 +1,49 @@
+/*
+ * 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 8136534
+ * @summary The input stream supplied to KeyStore.load should remain open.
+ */
+
+import java.io.*;
+import java.security.*;
+
+public class CheckInputStream {
+ private final static String DIR = System.getProperty("test.src", ".");
+ private static final char[] PASSWORD = "passphrase".toCharArray();
+ private static final String KEYSTORE = DIR + "/keystore.jks";
+
+ public static final void main(String[] args) throws Exception {
+
+ KeyStore keystore = KeyStore.getInstance("JKS");
+ try (FileInputStream inStream = new FileInputStream(KEYSTORE)) {
+ System.out.println("Loading JKS keystore: " + KEYSTORE);
+ keystore.load(inStream, PASSWORD);
+ // check that the stream is still open
+ inStream.available();
+ System.out.println("OK");
+ }
+ }
+}
diff --git a/jdk/test/java/text/Format/DateFormat/Bug8081794.java b/jdk/test/java/text/Format/DateFormat/Bug8081794.java
new file mode 100644
index 0000000..f134b20
--- /dev/null
+++ b/jdk/test/java/text/Format/DateFormat/Bug8081794.java
@@ -0,0 +1,51 @@
+/*
+ * 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 8081794
+ * @summary ParsePosition getErrorIndex should return correct index
+ */
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class Bug8081794 {
+
+ public static void main(String[] args) {
+ String date = "13 Jan 2005 21:45:34 ABC";
+ String format = "dd MMM yyyy HH:mm:ss z";
+ ParsePosition pp = new ParsePosition(0);
+ pp.setIndex(0);
+ SimpleDateFormat sd = new SimpleDateFormat(format, Locale.ENGLISH);
+ Date d = sd.parse(date, pp);
+ int errorIndex = pp.getErrorIndex();
+ if (errorIndex == 21) {
+ System.out.println(": passed");
+ } else {
+ System.out.println(": failed");
+ throw new RuntimeException("Failed with wrong index: " + errorIndex);
+ }
+ }
+}
diff --git a/jdk/test/java/time/tck/java/time/TCKInstant.java b/jdk/test/java/time/tck/java/time/TCKInstant.java
index ee3898e..3fbead4 100644
--- a/jdk/test/java/time/tck/java/time/TCKInstant.java
+++ b/jdk/test/java/time/tck/java/time/TCKInstant.java
@@ -112,6 +112,8 @@
/**
* Test Instant.
+ *
+ * @bug 8133022
*/
@Test
public class TCKInstant extends AbstractDateTimeTest {
@@ -1928,6 +1930,16 @@
Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
}
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow() {
+ Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 809_000_000).toEpochMilli();
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow2() {
+ Instant.ofEpochSecond(-9223372036854776L, 1).toEpochMilli();
+ }
+
//-----------------------------------------------------------------------
// compareTo()
//-----------------------------------------------------------------------
diff --git a/jdk/test/java/time/test/java/time/TestInstant.java b/jdk/test/java/time/test/java/time/TestInstant.java
index cf135a1..203bb57 100644
--- a/jdk/test/java/time/test/java/time/TestInstant.java
+++ b/jdk/test/java/time/test/java/time/TestInstant.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -62,6 +62,8 @@
import java.time.Instant;
import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
/**
* Test Instant.
@@ -74,4 +76,24 @@
assertImmutable(Instant.class);
}
+ @DataProvider(name="sampleEpochMillis")
+ private Object[][] provider_sampleEpochMillis() {
+ return new Object[][] {
+ {"Long.MAX_VALUE", Long.MAX_VALUE},
+ {"Long.MAX_VALUE-1", Long.MAX_VALUE - 1},
+ {"1", 1L},
+ {"0", 0L},
+ {"-1", -1L},
+ {"Long.MIN_VALUE+1", Long.MIN_VALUE + 1},
+ {"Long.MIN_VALUE", Long.MIN_VALUE}
+ };
+ }
+
+ @Test(dataProvider="sampleEpochMillis")
+ public void test_epochMillis(String name, long millis) {
+ Instant t1 = Instant.ofEpochMilli(millis);
+ long m = t1.toEpochMilli();
+ assertEquals(millis, m, name);
+ }
+
}
diff --git a/jdk/test/java/util/zip/ZipFile/ZipEntryFreeTest.java b/jdk/test/java/util/zip/ZipFile/ZipEntryFreeTest.java
new file mode 100644
index 0000000..7695a33
--- /dev/null
+++ b/jdk/test/java/util/zip/ZipFile/ZipEntryFreeTest.java
@@ -0,0 +1,130 @@
+/*
+ * 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 6907252
+ * @summary ZipFileInputStream Not Thread-Safe
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @run main ZipEntryFreeTest
+ */
+
+import java.io.*;
+import java.nio.file.Paths;
+import java.util.Random;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.zip.*;
+import jdk.testlibrary.FileUtils;
+
+public class ZipEntryFreeTest extends Thread {
+
+ private static final int NUM_THREADS = 5;
+ private static final int TEST_ITERATIONS = 5;
+ private static final String ZIPFILE_NAME = "large.zip";
+ private static final String ZIPENTRY_NAME = "random.txt";
+ private static InputStream is = null;
+ final Timer timer = new Timer();
+
+ public static void main(String args[]) throws Exception {
+ createZipFile();
+ try {
+ for (int i = 0; i < TEST_ITERATIONS; i++) {
+ runTest();
+ }
+ } finally {
+ FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME));
+ }
+ }
+
+ private static void runTest() throws Exception {
+ try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) {
+ is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME + "_0"));
+ Thread[] threadArray = new Thread[NUM_THREADS];
+ for (int i = 0; i < threadArray.length; i++) {
+ threadArray[i] = new ZipEntryFreeTest();
+ }
+ for (int i = 0; i < threadArray.length; i++) {
+ threadArray[i].start();
+ }
+ for (int i = 0; i < threadArray.length; i++) {
+ threadArray[i].join();
+ }
+ }
+ }
+
+ private static void createZipFile() throws Exception {
+ Random rnd = new Random(1000L);
+ byte[] contents = new byte[2_000_000];
+ ZipEntry ze = null;
+
+ try (ZipOutputStream zos =
+ new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) {
+ // uncompressed mode seemed to tickle the crash
+ zos.setMethod(ZipOutputStream.STORED);
+ for (int ze_count = 0; ze_count < 10; ze_count++) {
+ rnd.nextBytes(contents);
+ ze = createZipEntry(contents, ze_count);
+ zos.putNextEntry(ze);
+ zos.write(contents, 0, contents.length);
+ }
+ zos.flush();
+ }
+ }
+
+ private static ZipEntry createZipEntry(byte[] b, int i) {
+ ZipEntry ze = new ZipEntry(ZIPENTRY_NAME + "_" + i);
+ ze.setCompressedSize(b.length);
+ ze.setSize(b.length);
+ CRC32 crc = new CRC32();
+ crc.update(b);
+ ze.setCrc(crc.getValue());
+ return ze;
+ }
+
+ @Override
+ public void run() {
+ try {
+ int iteration = 0;
+ TimerTask tt = (new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ is.close();
+ } catch (Exception ex) {
+ ex.printStackTrace(System.out);
+ }
+ }
+ });
+ timer.schedule(tt, 50);
+ while (is.read() != -1 && iteration++ < 1_000) { }
+ } catch (ZipException ze) {
+ // ZipException now expected instead of ZIP_Read crash
+ System.out.println(ze);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ } finally {
+ timer.cancel();
+ }
+ }
+}
diff --git a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java
index 5285716..f875497 100644
--- a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java
+++ b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java
@@ -85,7 +85,7 @@
private static final boolean DEBUG = false;
private static void testPrintAndExit() {
- String expected = "<e4> 7.44 100.0 100.0 S";
+ String expected = "<e4>";
String content = "";
File file = new File("out.ps");
diff --git a/jdk/test/javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java b/jdk/test/javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java
new file mode 100644
index 0000000..4d147ac
--- /dev/null
+++ b/jdk/test/javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 8134828
+ @summary Scrollbar thumb disappears with Nimbus L&F
+ @author Semyon Sadetsky
+*/
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ScrollBarThumbVisibleTest
+{
+ private static JFrame frame;
+ private static Point point;
+ private static JScrollBar bar;
+
+ public static void main(String[] args) throws Exception {
+ for (UIManager.LookAndFeelInfo info : UIManager
+ .getInstalledLookAndFeels()) {
+ if ("Nimbus".equals(info.getName())) {
+ try {
+ UIManager.setLookAndFeel(info.getClassName());
+ } catch (Exception ex) {
+ }
+ break;
+ }
+ }
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ frame = new JFrame();
+ frame.setUndecorated(true);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setup(frame);
+ }
+ });
+ final Robot robot = new Robot();
+ robot.delay(200);
+ robot.waitForIdle();
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ point = bar.getLocationOnScreen();
+ }
+ });
+ Color color1 = robot.getPixelColor(point.x + 48, point.y + 55);
+ Color color2 = robot.getPixelColor(point.x + 48, point.y + 125);
+ System.out.println(color1);
+ System.out.println(color2);
+ if (color1.equals(color2)) {
+ throw new RuntimeException("Thump is not visible");
+ }
+ } finally {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ frame.dispose();
+ }
+ });
+ }
+ System.out.println("ok");
+ }
+
+ static void setup(JFrame frame) {
+ bar = new JScrollBar(Adjustable.VERTICAL, 500, 0, 0, 1000);
+ frame.getContentPane().add(bar);
+ frame.setSize(50, 250);
+ frame.setLocation(100, 100);
+ frame.setVisible(true);
+ }
+}
diff --git a/jdk/test/javax/xml/bind/jxc/8073519/InputWithError.java b/jdk/test/javax/xml/bind/jxc/8073519/InputWithError.java
new file mode 100644
index 0000000..d970eed
--- /dev/null
+++ b/jdk/test/javax/xml/bind/jxc/8073519/InputWithError.java
@@ -0,0 +1,30 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlType;
+
+@XmlType
+public class InputWithError {
+ public int a;
+ int compile-error;
+}
+
diff --git a/jdk/test/javax/xml/bind/jxc/8073519/SchemagenErrorReporting.java b/jdk/test/javax/xml/bind/jxc/8073519/SchemagenErrorReporting.java
new file mode 100644
index 0000000..226aea5
--- /dev/null
+++ b/jdk/test/javax/xml/bind/jxc/8073519/SchemagenErrorReporting.java
@@ -0,0 +1,91 @@
+/*
+ * 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 8073519
+ * @summary test that schemagen tool reports errors during
+ * xsd generation process
+ * @library /lib/testlibrary
+ * @run testng/othervm SchemagenErrorReporting
+ */
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+import jdk.testlibrary.JDKToolLauncher;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class SchemagenErrorReporting {
+
+ @Test
+ public void schemagenErrorReporting() throws Exception {
+ //schemagen tool output file name
+ final String SCHEMA_FILE = "schema1.xsd";
+ //Schemagen input java file with not compilable source
+ final String CLASS_FILE = "InputWithError.java";
+ //Test working, src directories and test output file
+ Path testWorkDir, testSrcDir, testOutput;
+
+ //Prepare test environment
+ //Create test directory inside scratch
+ testWorkDir = Paths.get(System.getProperty("user.dir", "."))
+ .resolve("SchemagenErrorReporting");
+ //Get test source directory
+ testSrcDir = Paths.get(System.getProperty("test.src", "."));
+ //Set test output file path
+ testOutput = testWorkDir.resolve("stdErrContent");
+ //Create test directory inside scratch directory
+ Files.createDirectory(testWorkDir);
+ //Copy java source from test.src to the test directory
+ Files.copy(testSrcDir.resolve(CLASS_FILE), testWorkDir.resolve(CLASS_FILE),
+ StandardCopyOption.REPLACE_EXISTING);
+
+ //Prepare process builder to run schemagen tool and save its output
+ JDKToolLauncher sgl = JDKToolLauncher.createUsingTestJDK("schemagen");
+ sgl.addToolArg(CLASS_FILE);
+ System.out.println("Executing: " + Arrays.asList(sgl.getCommand()));
+ ProcessBuilder pb = new ProcessBuilder(sgl.getCommand());
+ //Set schemagen work directory with the input java file
+ pb.directory(testWorkDir.toFile());
+ //Redirect schemagen output to file
+ pb.redirectError(testOutput.toFile());
+ Process p = pb.start();
+ int result = p.waitFor();
+ p.destroy();
+
+ //Read schemagen output from the file
+ String stdErrContent = Files.lines(testOutput)
+ .collect(Collectors.joining(System.lineSeparator(), System.lineSeparator(), ""));
+ System.out.println("Schemagen return value:" + result);
+ System.out.println("Error output:" + stdErrContent);
+ //Check test results:
+ //Schemagen finished with non-0 return value
+ Assert.assertNotEquals(result, 0);
+ //Schemagen output contains compile error message
+ Assert.assertTrue(stdErrContent.contains("InputWithError.java:28: error"));
+ }
+}
diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java
index c769e70..67af0cd 100644
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java
@@ -66,7 +66,7 @@
public static final double TIMEOUT_FACTOR;
static {
String toFactor = System.getProperty("test.timeout.factor", "1.0");
- TIMEOUT_FACTOR = Double.parseDouble(toFactor);
+ TIMEOUT_FACTOR = Double.parseDouble(toFactor);
}
/**
diff --git a/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java
index 3d720b3..1f82399 100644
--- a/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java
+++ b/jdk/test/lib/testlibrary/jsr292/com/oracle/testlibrary/jsr292/Helper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -315,4 +315,33 @@
}
return null;
}
+
+ /**
+ * Routine used to obtain a randomly generated method type.
+ *
+ * @param arity Arity of returned method type.
+ * @return MethodType generated randomly.
+ */
+ public static MethodType randomMethodTypeGenerator(int arity) {
+ final Class<?>[] CLASSES = {
+ Object.class,
+ int.class,
+ boolean.class,
+ byte.class,
+ short.class,
+ char.class,
+ long.class,
+ float.class,
+ double.class
+ };
+ if (arity > MAX_ARITY) {
+ throw new IllegalArgumentException(
+ String.format("Arity should not exceed %d!", MAX_ARITY));
+ }
+ List<Class<?>> list = randomClasses(CLASSES, arity);
+ list = getParams(list, false, arity);
+ int i = RNG.nextInt(CLASSES.length + 1);
+ Class<?> rtype = i == CLASSES.length ? void.class : CLASSES[i];
+ return MethodType.methodType(rtype, list);
+ }
}
diff --git a/jdk/test/sun/net/util/IPAddressUtilTest.java b/jdk/test/sun/net/util/IPAddressUtilTest.java
index 889518a..8c35ac7 100644
--- a/jdk/test/sun/net/util/IPAddressUtilTest.java
+++ b/jdk/test/sun/net/util/IPAddressUtilTest.java
@@ -21,6 +21,12 @@
* questions.
*/
+/*
+ * @test
+ * @bug 8087190
+ * @summary Exercise the sun.net.util.IPAddressUtil class
+ */
+
import sun.net.util.*;
/*
@@ -39,6 +45,10 @@
{"238.255.2550.255", bad},
{"238.2550.255.255", bad},
{"2380.255.255.255", bad},
+ {".1.1.1", bad},
+ {"1..1.1", bad},
+ {"1.1.1.", bad},
+ {"...", bad},
{"10::10", good},
{"10::10.1", bad},
{"10::10.1.2", bad},
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/BuildPath.java b/jdk/test/sun/security/provider/certpath/ReverseBuilder/BuildPath.java
deleted file mode 100644
index 28ff643..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/BuildPath.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2007, 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 6511784
- * @summary Make sure that building a path to a CRL issuer works in the
- * reverse direction
- * @library ../../../../../java/security/testlibrary
- * @build CertUtils
- * @run main BuildPath
- */
-import java.security.cert.*;
-import java.util.Collections;
-import sun.security.provider.certpath.SunCertPathBuilderParameters;
-
-public class BuildPath {
-
- public static void main(String[] args) throws Exception {
-
- TrustAnchor anchor =
- new TrustAnchor(CertUtils.getCertFromFile("mgrM2mgrM"), null);
- X509Certificate target = CertUtils.getCertFromFile("mgrM2leadMA");
- X509CertSelector xcs = new X509CertSelector();
- xcs.setSubject("CN=leadMA,CN=mgrM,OU=prjM,OU=divE,OU=Comp,O=sun,C=us");
- xcs.setCertificate(target);
- SunCertPathBuilderParameters params =
- new SunCertPathBuilderParameters(Collections.singleton(anchor),xcs);
- params.setBuildForward(false);
- CertStore cs = CertUtils.createStore(new String[]
- {"mgrM2prjM", "prjM2mgrM", "prjM2divE", "mgrM2leadMA" });
- params.addCertStore(cs);
- CertStore cs2 = CertUtils.createCRLStore
- (new String[] {"mgrMcrl", "prjMcrl"});
- params.addCertStore(cs2);
- PKIXCertPathBuilderResult res = CertUtils.build(params);
- }
-}
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/ReverseBuild.java b/jdk/test/sun/security/provider/certpath/ReverseBuilder/ReverseBuild.java
deleted file mode 100644
index 21736ea..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/ReverseBuild.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (c) 2012, 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 7167988
- * @summary PKIX CertPathBuilder in reverse mode doesn't work if more than
- * one trust anchor is specified
- */
-import java.io.*;
-import java.util.*;
-import java.security.cert.*;
-
-import sun.security.provider.certpath.SunCertPathBuilderParameters;
-
-public class ReverseBuild {
- // Certificate information:
- // Issuer: C=US, ST=Some-State, L=Some-City, O=Some-Org
- // Validity
- // Not Before: Dec 8 02:43:36 2008 GMT
- // Not After : Aug 25 02:43:36 2028 GMT
- // Subject: C=US, ST=Some-State, L=Some-City, O=Some-Org
- // X509v3 Subject Key Identifier:
- // FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
- // X509v3 Authority Key Identifier:
- // keyid:FA:B9:51:BF:4C:E7:D9:86:98:33:F9:E7:CB:1E:F1:33:49:F7:A8:14
- // DirName:/C=US/ST=Some-State/L=Some-City/O=Some-Org
- // serial:00
- static String NoiceTrusedCertStr =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICrDCCAhWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBJMQswCQYDVQQGEwJVUzET\n" +
- "MBEGA1UECBMKU29tZS1TdGF0ZTESMBAGA1UEBxMJU29tZS1DaXR5MREwDwYDVQQK\n" +
- "EwhTb21lLU9yZzAeFw0wODEyMDgwMjQzMzZaFw0yODA4MjUwMjQzMzZaMEkxCzAJ\n" +
- "BgNVBAYTAlVTMRMwEQYDVQQIEwpTb21lLVN0YXRlMRIwEAYDVQQHEwlTb21lLUNp\n" +
- "dHkxETAPBgNVBAoTCFNvbWUtT3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB\n" +
- "gQDLxDggB76Ip5OwoUNRLdeOha9U3a2ieyNbz5kTU5lFfe5tui2/461uPZ8a+QOX\n" +
- "4BdVrhEmV94BKY4FPyH35zboLjfXSKxT1mAOx1Bt9sWF94umxZE1cjyU7vEX8HHj\n" +
- "7BvOyk5AQrBt7moO1uWtPA/JuoJPePiJl4kqlRJM2Akq6QIDAQABo4GjMIGgMB0G\n" +
- "A1UdDgQWBBT6uVG/TOfZhpgz+efLHvEzSfeoFDBxBgNVHSMEajBogBT6uVG/TOfZ\n" +
- "hpgz+efLHvEzSfeoFKFNpEswSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUt\n" +
- "U3RhdGUxEjAQBgNVBAcTCVNvbWUtQ2l0eTERMA8GA1UEChMIU29tZS1PcmeCAQAw\n" +
- "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQBcIm534U123Hz+rtyYO5uA\n" +
- "ofd81G6FnTfEAV8Kw9fGyyEbQZclBv34A9JsFKeMvU4OFIaixD7nLZ/NZ+IWbhmZ\n" +
- "LovmJXyCkOufea73pNiZ+f/4/ScZaIlM/PRycQSqbFNd4j9Wott+08qxHPLpsf3P\n" +
- "6Mvf0r1PNTY2hwTJLJmKtg==\n" +
- "-----END CERTIFICATE-----";
-
- // Certificate information:
- // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce
- // Validity
- // Not Before: Aug 19 01:52:19 2011 GMT
- // Not After : Jul 29 01:52:19 2032 GMT
- // Subject: C=US, O=Java, OU=SunJSSE Test Serivce
-
- // X509v3 Subject Key Identifier:
- // B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1
- // X509v3 Authority Key Identifier:
- // keyid:B9:7C:D5:D9:DF:A7:4C:03:AE:FD:0E:27:5B:31:95:6C:C7:F3:75:E1
- // DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
- // serial:00
- static String NoiceTrusedCertStr_2nd =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
- "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
- "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
- "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
- "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
- "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
- "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
- "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
- "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
- "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
- "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
- "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
- "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
- "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
- "-----END CERTIFICATE-----";
-
-
- // Certificate information:
- // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce
- // Validity
- // Not Before: May 5 02:40:50 2012 GMT
- // Not After : Apr 15 02:40:50 2033 GMT
- // Subject: C=US, O=Java, OU=SunJSSE Test Serivce
- // X509v3 Subject Key Identifier:
- // DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
- // X509v3 Authority Key Identifier:
- // keyid:DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
- // DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
- // serial:00
- static String trustedCertStr =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
- "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
- "MTIwNTA1MDI0MDUwWhcNMzMwNDE1MDI0MDUwWjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
- "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
- "KoZIhvcNAQEBBQADgY0AMIGJAoGBANtiq0AIJK+iVRwFrqcD7fYXTCbMYC5Qz/k6\n" +
- "AXBy7/1rI8wDhEJLE3m/+NSqiJwZcmdq2dNh/1fJFrwvzuURbc9+paOBWeHbN+Sc\n" +
- "x3huw91oPZme385VpoK3G13rSE114S/rF4DM9mz4EStFhSHXATjtdbskNOAYGLTV\n" +
- "x8uEy9GbAgMBAAGjgaUwgaIwHQYDVR0OBBYEFN1OjSoRwIMD8Kzror/58n3IaR+b\n" +
- "MGMGA1UdIwRcMFqAFN1OjSoRwIMD8Kzror/58n3IaR+boT+kPTA7MQswCQYDVQQG\n" +
- "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
- "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
- "BQADgYEAjjkJesQrkbr36N40egybaIxw7RcqT6iy5fkAGS1JYlBDk8uSCK1o6bCH\n" +
- "ls5EpYcGeEoabSS73WRdkO1lgeyWDduO4ef8cCCSpmpT6/YdZG0QS1PtcREeVig+\n" +
- "Zr25jNemS4ADHX0aaXP4kiV/G80cR7nX5t5XCUm4bYdbwM07NgI=\n" +
- "-----END CERTIFICATE-----";
- static String trustedPrivateKey = // Private key in the format of PKCS#8
- "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANtiq0AIJK+iVRwF\n" +
- "rqcD7fYXTCbMYC5Qz/k6AXBy7/1rI8wDhEJLE3m/+NSqiJwZcmdq2dNh/1fJFrwv\n" +
- "zuURbc9+paOBWeHbN+Scx3huw91oPZme385VpoK3G13rSE114S/rF4DM9mz4EStF\n" +
- "hSHXATjtdbskNOAYGLTVx8uEy9GbAgMBAAECgYEA2VjHkIiA0ABjkX+PqKeb+VLb\n" +
- "fxS7tSca5C8zfdRhLxAWRui0/3ihst0eCJNrBDuxvAOACovsDWyLuaUjtI2v2ysz\n" +
- "vz6SPyGy82PhQOFzyKQuQ814N6EpothpiZzF0yFchfKIGhUsdY89UrGs9nM7m6NT\n" +
- "rztYvgIu4avg2VPR2AECQQD+pFAqipR2BplQRIuuRSZfHRxvoEyDjT1xnHJsC6WP\n" +
- "I5hCLghL91MhQGWbP4EJMKYQOTRVukWlcp2Kycpf+P5hAkEA3I43gmVUAPEdyZdY\n" +
- "fatW7OaLlbbYJb6qEtpCZ1Rwe/BIvm6H6E3qSi/lpz7Ia7WDulpbF6BawHH3pRFq\n" +
- "CUY5ewJBAP3pUDqrRpBN0jB0uSeDslhjSciQ+dqvSpZv3rSYBHUvlBJhnkpJiy37\n" +
- "7ZUZhIxqYxyIPgRBolLwb+FFh7OdL+ECQCtldDic9WVmC+VheRDpCKZ+SlK/8lGi\n" +
- "7VXeShiIvcU1JysJFoa35fSI7hf1O3wt7+hX5PqGG7Un94EsJwACKEcCQQC1TWt6\n" +
- "ArKH6tRxKjOxFtqfs8fgEVYUaOr3j1jF4KBUuX2mtQtddZe3VfJ2wPsuKMMxmhkB\n" +
- "e7xWWZnJsErt2e+E";
-
- // Certificate information:
- // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce
- // Validity
- // Not Before: May 5 02:40:53 2012 GMT
- // Not After : Jan 21 02:40:53 2032 GMT
- // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=casigner
- // X509v3 Subject Key Identifier:
- // 13:07:E0:11:07:DB:EB:33:23:87:31:D0:DB:7E:16:56:BE:11:90:0A
- // X509v3 Authority Key Identifier:
- // keyid:DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
- // DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
- // serial:00
- static String caSignerStr =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICqDCCAhGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
- "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
- "MTIwNTA1MDI0MDUzWhcNMzIwMTIxMDI0MDUzWjBOMQswCQYDVQQGEwJVUzENMAsG\n" +
- "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxETAPBgNV\n" +
- "BAMTCGNhc2lnbmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+x8+o7oM0\n" +
- "ct/LZmZLXBL4CQ8jrULD5P7NtEW0hg/zxBFZfBHf+44Oo2eMPYZj+7xaREOH5BmV\n" +
- "KRYlzRtONAaC5Ng4Mrm5UKNPcMIIUjUOvm7vWM4oSTMSfoEcSX+vp99uUAkw3w7Z\n" +
- "+frYDm1M4At/j0b+lLij71GFN2L8drpgPQIDAQABo4GoMIGlMB0GA1UdDgQWBBQT\n" +
- "B+ARB9vrMyOHMdDbfhZWvhGQCjBjBgNVHSMEXDBagBTdTo0qEcCDA/Cs66K/+fJ9\n" +
- "yGkfm6E/pD0wOzELMAkGA1UEBhMCVVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsT\n" +
- "FFN1bkpTU0UgVGVzdCBTZXJpdmNlggEAMBIGA1UdEwEB/wQIMAYBAf8CAQEwCwYD\n" +
- "VR0PBAQDAgEGMA0GCSqGSIb3DQEBBAUAA4GBAI+LXA/UCPkTANablUkt80JNPWsl\n" +
- "pS4XLNgPxWaN0bkRDs5oI4ooWAz1rwpeJ/nfetOvWlpmrVjSeovBFja5Hl+dUHTf\n" +
- "VfuyzkxXbhuNiJIpo1mVBpNsjwu9YRxuwX6UA2LTUQpgvtVJEE012x3zRvxBCbu2\n" +
- "Y/v1R5fZ4c+hXDfC\n" +
- "-----END CERTIFICATE-----";
- static String caSignerPrivateKey = // Private key in the format of PKCS#8
- "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL7Hz6jugzRy38tm\n" +
- "ZktcEvgJDyOtQsPk/s20RbSGD/PEEVl8Ed/7jg6jZ4w9hmP7vFpEQ4fkGZUpFiXN\n" +
- "G040BoLk2DgyublQo09wwghSNQ6+bu9YzihJMxJ+gRxJf6+n325QCTDfDtn5+tgO\n" +
- "bUzgC3+PRv6UuKPvUYU3Yvx2umA9AgMBAAECgYBYvu30cW8LONyt62Zua9hPFTe7\n" +
- "qt9B7QYyfkdmoG5PQMepTrOp84SzfoOukvgvDm0huFuJnSvhXQl2cCDhkgXskvFj\n" +
- "Hh7KBCFViVXokGdq5YoS0/KYMyQV0TZfJUvILBl51uc4/siQ2tClC/N4sa+1JhgW\n" +
- "a6dFGfRjiUKSSlmMwQJBAPWpIz3Q/c+DYMvoQr5OD8EaYwYIevlTdXb97RnJJh2b\n" +
- "UnhB9jrqesJiHYVzPmP0ukyPOXOwlp2T5Am4Kw0LFOkCQQDGz150NoHOp28Mvyc4\n" +
- "CTqz/zYzUhy2eCJESl196uyP4N65Y01VYQ3JDww4DlsXiU17tVSbgA9TCcfTYOzy\n" +
- "vyw1AkARUky+1hafZCcWGZljK8PmnMKwsTZikCTvL/Zg5BMA8Wu+OQBwpQnk3OAy\n" +
- "Aa87gw0DyvGFG8Vy9POWT9sRP1/JAkBqP0hrMvYMSs6+MSn0eHo2151PsAJIQcuO\n" +
- "U2/Da1khSzu8N6WMi2GiobgV/RYRbf9KrY2ZzMZjykZQYOxAjopBAkEAghCu38cN\n" +
- "aOsW6ueo24uzsWI1FTdE+qWNVEi3RSP120xXBCyhaBjIq4WVSlJK9K2aBaJpit3j\n" +
- "iQ5tl6zrLlxQhg==";
-
- // Certificate information:
- // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=casigner
- // Validity
- // Not Before: May 5 02:40:57 2012 GMT
- // Not After : Jan 21 02:40:57 2032 GMT
- // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer
- // X509v3 Subject Key Identifier:
- // 39:0E:C6:33:B1:50:BC:73:07:31:E5:D8:04:F7:BB:97:55:CF:9B:C8
- // X509v3 Authority Key Identifier:
- // keyid:13:07:E0:11:07:DB:EB:33:23:87:31:D0:DB:7E:16:56:BE:11:90:0A
- // DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
- // serial:02
- static String certIssuerStr =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICvjCCAiegAwIBAgIBAzANBgkqhkiG9w0BAQQFADBOMQswCQYDVQQGEwJVUzEN\n" +
- "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxETAP\n" +
- "BgNVBAMTCGNhc2lnbmVyMB4XDTEyMDUwNTAyNDA1N1oXDTMyMDEyMTAyNDA1N1ow\n" +
- "UDELMAkGA1UEBhMCVVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0Ug\n" +
- "VGVzdCBTZXJpdmNlMRMwEQYDVQQDEwpjZXJ0aXNzdWVyMIGfMA0GCSqGSIb3DQEB\n" +
- "AQUAA4GNADCBiQKBgQCyz55zinU6kNL/LeiTNiBI0QWYmDG0YTotuC4D75liBNqs\n" +
- "7Mmladsh2mTtQUAwmuGaGzaZV25a+cUax0DXZoyBwdbTI09u1bUYsZcaUUKbPoCC\n" +
- "HH26e4jLFL4olW13Sv4ZAd57tIYevMw+Fp5f4fLPFGegCJTFlv2Qjpmic/cuvQID\n" +
- "AQABo4GpMIGmMB0GA1UdDgQWBBQ5DsYzsVC8cwcx5dgE97uXVc+byDBjBgNVHSME\n" +
- "XDBagBQTB+ARB9vrMyOHMdDbfhZWvhGQCqE/pD0wOzELMAkGA1UEBhMCVVMxDTAL\n" +
- "BgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlggECMBMG\n" +
- "A1UdEwEB/wQJMAcBAf8CAgQAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQQFAAOB\n" +
- "gQCQTagenCdClT98C+oTJGJrw/dUBD9K3tE6ZJKPMc/2bUia8G5ei1C0eXj4mWG2\n" +
- "lu9umR6C90/A6qB050QB2h50qtqxSrkpu+ym1yypauZpg7U3nUY9wZWJNI1vqrQZ\n" +
- "pqUMRcXY3iQIVKx+Qj+4/Za1wwFQzpEoGmqRW31V1SdMEw==\n" +
- "-----END CERTIFICATE-----";
- static String certIssuerPrivateKey = // Private key in the format of PKCS#8
- "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBALLPnnOKdTqQ0v8t\n" +
- "6JM2IEjRBZiYMbRhOi24LgPvmWIE2qzsyaVp2yHaZO1BQDCa4ZobNplXblr5xRrH\n" +
- "QNdmjIHB1tMjT27VtRixlxpRQps+gIIcfbp7iMsUviiVbXdK/hkB3nu0hh68zD4W\n" +
- "nl/h8s8UZ6AIlMWW/ZCOmaJz9y69AgMBAAECgYEAjtew2tgm4gxDojqIauF4VPM1\n" +
- "pzsdqd1p3pAdomNLgrQiBLZ8N7oiph6TNb1EjA+OXc+ThFgF/oM9ZDD8qZZwcvjN\n" +
- "qDZlpTkFs2TaGcyEZfUaMB45NHVs6Nn+pSkagSNwwy3xeyAct7sQEzGNTDlEwVv5\n" +
- "7V9LQutQtBd6xT48KzkCQQDpNRfv2OFNG/6GtzJoO68oJhpnpl2MsYNi4ntRkre/\n" +
- "6uXpiCYaDskcrPMRwOOs0m7mxG+Ev+uKnLnSoEMm1GCbAkEAxEmDtiD0Psb8Z9BL\n" +
- "ZRb83Jqho3xe2MCAh3xUfz9b/Mhae9dZ44o4OCgQZuwvW1mczF0NtpgZl93BmYa2\n" +
- "hTwHhwJBAKHrEj6ep/fA6x0gD2idoATRR94VfbiU+7NpqtO9ecVP0+gsdr/66hn1\n" +
- "3yLBeZLh3MxvMTrLgkAQh1i9m0JXjOcCQQClLXAHHegrw+u3uNMZeKTFR+Lp3sk6\n" +
- "AZSnbvr0Me9I45kxSeG81x3ENALJecvIRbrrRws5MvmmkNhQR8rkh8WVAkEAk6b+\n" +
- "aVtmBgUaTS5+FFlHGHJY9HFrfT1a1C/dwyMuqlmbC3YsBmZaMOlKli5TXNybLff8\n" +
- "5KMeGEpXMzgC7AscGA==";
-
- // Certificate information:
- // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer
- // Validity
- // Not Before: May 5 02:41:01 2012 GMT
- // Not After : Jan 21 02:41:01 2032 GMT
- // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=localhost
- // X509v3 Subject Key Identifier:
- // AD:C0:2C:4C:E4:C2:2E:A1:BB:5D:92:BE:66:E0:4E:E0:0D:2F:11:EF
- // X509v3 Authority Key Identifier:
- // keyid:39:0E:C6:33:B1:50:BC:73:07:31:E5:D8:04:F7:BB:97:55:CF:9B:C8
- static String targetCertStr =
- "-----BEGIN CERTIFICATE-----\n" +
- "MIICjTCCAfagAwIBAgIBBDANBgkqhkiG9w0BAQQFADBQMQswCQYDVQQGEwJVUzEN\n" +
- "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEzAR\n" +
- "BgNVBAMTCmNlcnRpc3N1ZXIwHhcNMTIwNTA1MDI0MTAxWhcNMzIwMTIxMDI0MTAx\n" +
- "WjBPMQswCQYDVQQGEwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNT\n" +
- "RSBUZXN0IFNlcml2Y2UxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0B\n" +
- "AQEFAAOBjQAwgYkCgYEAvwaUd7wmBSKqycEstYLWD26vkU08DM39EtaT8wL9HnQ0\n" +
- "fgPblwBFI4zdLa2cuYXRZcFUb04N8nrkcpR0D6kkE+AlFAoRWrrZF80B7JTbtEK4\n" +
- "1PIeurihXvUT+4MpzGLOojIihMfvM4ufelblD56SInso4WFHm7t4qCln88J1gjkC\n" +
- "AwEAAaN4MHYwCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBStwCxM5MIuobtdkr5m4E7g\n" +
- "DS8R7zAfBgNVHSMEGDAWgBQ5DsYzsVC8cwcx5dgE97uXVc+byDAnBgNVHSUEIDAe\n" +
- "BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GB\n" +
- "AGfwcfdvEG/nSCiAn2MGbYHp34mgF3OA1SJLWUW0LvWJhwm2cn4AXlSoyvbwrkaB\n" +
- "IDDCwhJvvc0vUyL2kTx7sqVaFTq3mDs+ktlB/FfH0Pb+i8FE+g+7T42Iw/j0qxHL\n" +
- "YmgbrjBQf5WYN1AvBE/rrPt9aOtS3UsqtVGW574b0shW\n" +
- "-----END CERTIFICATE-----";
- static String targetPrivateKey = // Private key in the format of PKCS#8
- "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBAL8GlHe8JgUiqsnB\n" +
- "LLWC1g9ur5FNPAzN/RLWk/MC/R50NH4D25cARSOM3S2tnLmF0WXBVG9ODfJ65HKU\n" +
- "dA+pJBPgJRQKEVq62RfNAeyU27RCuNTyHrq4oV71E/uDKcxizqIyIoTH7zOLn3pW\n" +
- "5Q+ekiJ7KOFhR5u7eKgpZ/PCdYI5AgMBAAECf3CscOYvFD3zNMnMJ5LomVqA7w3F\n" +
- "gKYM2jlCWAH+wU41PMEXhW6Lujw92jgXL1o+lERwxFzirVdZJWZwKgUSvzP1G0h3\n" +
- "fkucq1/UWnToK+8NSXNM/yS8hXbBgSEoJo5f7LKcIi1Ev6doBVofMxs+njzyWKbM\n" +
- "Nb7rOLHadghoon0CQQDgQzbzzSN8Dc1YmmylhI5v+0sQRHH0DL7D24k4Weh4vInG\n" +
- "EAbt4x8M7ZKEo8/dv0s4hbmNmAnJl93/RRxIyEqLAkEA2g87DiswSQam2pZ8GlrO\n" +
- "+w4Qg9mH8uxx8ou2rl0XlHzH1XiTNbkjfY0EZoL7L31BHFk9n11Fb2P85g6ws+Hy\n" +
- "ywJAM/xgyLNM/nzUlS128geAXUULaYH0SHaL4isJ7B4rXZGW/mrIsGxtzjlkNYsj\n" +
- "rGujrD6TfNc5rZmexIXowJZtcQJBAIww+pCzZ4mrgx5JXWQ8OZHiiu+ZrPOa2+9J\n" +
- "r5sOMpi+WGN/73S8oHqZbNjTINZ5OqEVJq8MchWZPQBTNXuQql0CQHEjUzzkCQa3\n" +
- "j6JTa2KAdqyvLOx0XF9zcc1gA069uNQI2gPUHS8V215z57f/gMGnDNhVfLs/vMKz\n" +
- "sFkVZ3zg7As=";
-
-
- public static void main(String args[]) throws Exception {
-
- // generate certificate from cert string
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
-
- // create a set of trust anchors
- LinkedHashSet<TrustAnchor> trustAnchors = new LinkedHashSet<>();
-
- ByteArrayInputStream is =
- new ByteArrayInputStream(NoiceTrusedCertStr.getBytes());
- Certificate trustedCert = cf.generateCertificate(is);
- is.close();
- TrustAnchor anchor =
- new TrustAnchor((X509Certificate)trustedCert, null);
- trustAnchors.add(anchor);
-
- is = new ByteArrayInputStream(trustedCertStr.getBytes());
- trustedCert = cf.generateCertificate(is);
- is.close();
- anchor = new TrustAnchor((X509Certificate)trustedCert, null);
- trustAnchors.add(anchor);
-
- is = new ByteArrayInputStream(NoiceTrusedCertStr_2nd.getBytes());
- trustedCert = cf.generateCertificate(is);
- is.close();
- anchor = new TrustAnchor((X509Certificate)trustedCert, null);
- trustAnchors.add(anchor);
-
- // create a list of certificates
- List<Certificate> chainList = new ArrayList<>();
-
- is = new ByteArrayInputStream(targetCertStr.getBytes());
- Certificate cert = cf.generateCertificate(is);
- is.close();
- chainList.add(cert);
-
- is = new ByteArrayInputStream(certIssuerStr.getBytes());
- cert = cf.generateCertificate(is);
- is.close();
- chainList.add(cert);
-
- is = new ByteArrayInputStream(caSignerStr.getBytes());
- cert = cf.generateCertificate(is);
- is.close();
- chainList.add(cert);
-
- // create a certificate selector
- X509CertSelector xcs = new X509CertSelector();
- X509Certificate eeCert = (X509Certificate)chainList.get(0);
- xcs.setSubject(eeCert.getSubjectX500Principal());
-
- // reverse build
- SunCertPathBuilderParameters params =
- new SunCertPathBuilderParameters(trustAnchors, xcs);
- params.setBuildForward(false);
- params.setRevocationEnabled(false);
-
- CollectionCertStoreParameters ccsp =
- new CollectionCertStoreParameters(chainList);
- params.addCertStore(CertStore.getInstance("Collection", ccsp));
-
- CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
- CertPathBuilderResult res = cpb.build(params);
- }
-}
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2leadMA b/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2leadMA
deleted file mode 100644
index ed96b64..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2leadMA
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2mgrM b/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2mgrM
deleted file mode 100644
index 1953d3e..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2mgrM
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2prjM b/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2prjM
deleted file mode 100644
index 7f306ed..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrM2prjM
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrMcrl b/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrMcrl
deleted file mode 100644
index 0977ea1..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/mgrMcrl
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2divE b/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2divE
deleted file mode 100644
index f0e5edd..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2divE
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2mgrM b/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2mgrM
deleted file mode 100644
index 4004685..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjM2mgrM
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjMcrl b/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjMcrl
deleted file mode 100644
index 88fb9d8..0000000
--- a/jdk/test/sun/security/provider/certpath/ReverseBuilder/prjMcrl
+++ /dev/null
Binary files differ
diff --git a/jdk/test/sun/util/resources/TimeZone/Bug8139107.java b/jdk/test/sun/util/resources/TimeZone/Bug8139107.java
new file mode 100644
index 0000000..4334d63
--- /dev/null
+++ b/jdk/test/sun/util/resources/TimeZone/Bug8139107.java
@@ -0,0 +1,59 @@
+/*
+ * 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 8139107
+ * @summary Test that date parsing with DateTimeFormatter pattern
+ * that contains timezone field doesn't trigger NPE. All supported
+ * locales are tested.
+ * @run testng/othervm -Djava.locale.providers=JRE,SPI Bug8139107
+ */
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
+import org.testng.annotations.Test;
+
+public class Bug8139107 {
+
+ @Test
+ public void testSupportedLocales() {
+ for (Locale loc:Locale.getAvailableLocales()) {
+ testLocale(loc);
+ }
+ }
+
+ //Test one locale
+ void testLocale(Locale tl) {
+ System.out.println("Locale:" + tl);
+ DateTimeFormatter inputDateTimeFormat = DateTimeFormatter
+ .ofPattern(pattern)
+ .withLocale(tl);
+ System.out.println("Parse result: " + inputDateTimeFormat.parse(inputDate));
+ }
+
+ // Input date time string with short time zone name
+ static final String inputDate = "06-10-2015 18:58:04 MSK";
+ // Pattern with time zone field
+ static final String pattern = "dd-MM-yyyy HH:mm:ss z";
+}
+
diff --git a/langtools/.hgtags b/langtools/.hgtags
index 6202ff1..cb085c2 100644
--- a/langtools/.hgtags
+++ b/langtools/.hgtags
@@ -507,3 +507,12 @@
6462f92dadf2e5b7ac6fc35f7b38a5018108fd4d jdk8u71-b07
ef48693aa6ab6356a46830f3f127d41394b79224 jdk8u71-b08
8089203f9ae281143388d3d6bbe448ef94c32433 jdk8u71-b09
+1c93d260bf996e56d1e1f6d187aceadaa9a38d0c jdk8u72-b00
+aec633bcb3af5382013c6c25b435564aba5bc3d4 jdk8u72-b01
+dfb368f2498e5bfaac7cc7730b5e822999736cd7 jdk8u72-b02
+975709317923c28f0dfcf99d8456048f920d087e jdk8u72-b03
+106fb99e28d20623748c2c3a2120be37fcfac78f jdk8u72-b04
+5bb4ad0363a74265a931b24d0bb0f51b23f09060 jdk8u72-b05
+2e722fd7496556350510c5d3fc02c77377fd8bff jdk8u72-b06
+34d01f3892f5d7408926d5b29da0bcfdc8238f5b jdk8u72-b07
+98179963e9332fd10e8c369e5e50dfe5df280a18 jdk8u72-b08
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
index 017b85d..2544199 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java
@@ -421,6 +421,14 @@
&& (tsym.flags() & COMPOUND) != 0;
}
+ public boolean isIntersection() {
+ return false;
+ }
+
+ public boolean isUnion() {
+ return false;
+ }
+
public boolean isInterface() {
return (tsym.flags() & INTERFACE) != 0;
}
@@ -970,6 +978,11 @@
}
@Override
+ public boolean isUnion() {
+ return true;
+ }
+
+ @Override
public TypeKind getKind() {
return TypeKind.UNION;
}
@@ -1003,6 +1016,11 @@
return interfaces_field.prepend(supertype_field);
}
+ @Override
+ public boolean isIntersection() {
+ return true;
+ }
+
public List<Type> getExplicitComponents() {
return allInterfaces ?
interfaces_field :
diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
index e5683ea..d7110fb 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java
@@ -1539,8 +1539,8 @@
}
}
- if (t.isCompound() || s.isCompound()) {
- return !t.isCompound() ?
+ if (t.isIntersection() || s.isIntersection()) {
+ return !t.isIntersection() ?
visitIntersectionType((IntersectionClassType)s.unannotatedType(), t, true) :
visitIntersectionType((IntersectionClassType)t.unannotatedType(), s, false);
}
@@ -2255,19 +2255,28 @@
}
// </editor-fold>
- // <editor-fold defaultstate="collapsed" desc="makeCompoundType">
+ // <editor-fold defaultstate="collapsed" desc="makeIntersectionType">
/**
- * Make a compound type from non-empty list of types. The list should be
- * ordered according to {@link Symbol#precedes(TypeSymbol,Types)}.
+ * Make an intersection type from non-empty list of types. The list should be ordered according to
+ * {@link TypeSymbol#precedes(TypeSymbol, Types)}. Note that this might cause a symbol completion.
+ * Hence, this version of makeIntersectionType may not be called during a classfile read.
*
- * @param bounds the types from which the compound type is formed
- * @param supertype is objectType if all bounds are interfaces,
- * null otherwise.
+ * @param bounds the types from which the intersection type is formed
*/
- public Type makeCompoundType(List<Type> bounds) {
- return makeCompoundType(bounds, bounds.head.tsym.isInterface());
+ public IntersectionClassType makeIntersectionType(List<Type> bounds) {
+ return makeIntersectionType(bounds, bounds.head.tsym.isInterface());
}
- public Type makeCompoundType(List<Type> bounds, boolean allInterfaces) {
+
+ /**
+ * Make an intersection type from non-empty list of types. The list should be ordered according to
+ * {@link TypeSymbol#precedes(TypeSymbol, Types)}. This does not cause symbol completion as
+ * an extra parameter indicates as to whether all bounds are interfaces - in which case the
+ * supertype is implicitly assumed to be 'Object'.
+ *
+ * @param bounds the types from which the intersection type is formed
+ * @param allInterfaces are all bounds interface types?
+ */
+ public IntersectionClassType makeIntersectionType(List<Type> bounds, boolean allInterfaces) {
Assert.check(bounds.nonEmpty());
Type firstExplicitBound = bounds.head;
if (allInterfaces) {
@@ -2280,23 +2289,24 @@
: names.empty,
null,
syms.noSymbol);
- bc.type = new IntersectionClassType(bounds, bc, allInterfaces);
+ IntersectionClassType intersectionType = new IntersectionClassType(bounds, bc, allInterfaces);
+ bc.type = intersectionType;
bc.erasure_field = (bounds.head.hasTag(TYPEVAR)) ?
syms.objectType : // error condition, recover
erasure(firstExplicitBound);
bc.members_field = new Scope(bc);
- return bc.type;
+ return intersectionType;
}
/**
- * A convenience wrapper for {@link #makeCompoundType(List)}; the
+ * A convenience wrapper for {@link #makeIntersectionType(List)}; the
* arguments are converted to a list and passed to the other
* method. Note that this might cause a symbol completion.
- * Hence, this version of makeCompoundType may not be called
+ * Hence, this version of makeIntersectionType may not be called
* during a classfile read.
*/
- public Type makeCompoundType(Type bound1, Type bound2) {
- return makeCompoundType(List.of(bound1, bound2));
+ public Type makeIntersectionType(Type bound1, Type bound2) {
+ return makeIntersectionType(List.of(bound1, bound2));
}
// </editor-fold>
@@ -2436,7 +2446,7 @@
private final UnaryVisitor<List<Type>> directSupertypes = new UnaryVisitor<List<Type>>() {
public List<Type> visitType(final Type type, final Void ignored) {
- if (!type.isCompound()) {
+ if (!type.isIntersection()) {
final Type sup = supertype(type);
return (sup == Type.noType || sup == type || sup == null)
? interfaces(type)
@@ -2490,30 +2500,32 @@
// <editor-fold defaultstate="collapsed" desc="setBounds">
/**
- * Set the bounds field of the given type variable to reflect a
- * (possibly multiple) list of bounds.
- * @param t a type variable
- * @param bounds the bounds, must be nonempty
- * @param supertype is objectType if all bounds are interfaces,
- * null otherwise.
+ * Same as {@link Types#setBounds(TypeVar, List, boolean)}, except that third parameter is computed directly,
+ * as follows: if all all bounds are interface types, the computed supertype is Object,otherwise
+ * the supertype is simply left null (in this case, the supertype is assumed to be the head of
+ * the bound list passed as second argument). Note that this check might cause a symbol completion.
+ * Hence, this version of setBounds may not be called during a classfile read.
+ *
+ * @param t a type variable
+ * @param bounds the bounds, must be nonempty
*/
public void setBounds(TypeVar t, List<Type> bounds) {
setBounds(t, bounds, bounds.head.tsym.isInterface());
}
/**
- * Same as {@link #setBounds(Type.TypeVar,List,Type)}, except that
- * third parameter is computed directly, as follows: if all
- * all bounds are interface types, the computed supertype is Object,
- * otherwise the supertype is simply left null (in this case, the supertype
- * is assumed to be the head of the bound list passed as second argument).
- * Note that this check might cause a symbol completion. Hence, this version of
- * setBounds may not be called during a classfile read.
+ * Set the bounds field of the given type variable to reflect a (possibly multiple) list of bounds.
+ * This does not cause symbol completion as an extra parameter indicates as to whether all bounds
+ * are interfaces - in which case the supertype is implicitly assumed to be 'Object'.
+ *
+ * @param t a type variable
+ * @param bounds the bounds, must be nonempty
+ * @param allInterfaces are all bounds interface types?
*/
public void setBounds(TypeVar t, List<Type> bounds, boolean allInterfaces) {
t.bound = bounds.tail.isEmpty() ?
bounds.head :
- makeCompoundType(bounds, allInterfaces);
+ makeIntersectionType(bounds, allInterfaces);
t.rank_field = -1;
}
// </editor-fold>
@@ -3063,7 +3075,7 @@
if (st == supertype(t) && is == interfaces(t))
return t;
else
- return makeCompoundType(is.prepend(st));
+ return makeIntersectionType(is.prepend(st));
}
}
@@ -3566,7 +3578,7 @@
else if (compound.tail.isEmpty())
return compound.head;
else
- return makeCompoundType(compound);
+ return makeIntersectionType(compound);
}
/**
@@ -3744,8 +3756,8 @@
synchronized (this) {
if (arraySuperType == null) {
// JLS 10.8: all arrays implement Cloneable and Serializable.
- arraySuperType = makeCompoundType(List.of(syms.serializableType,
- syms.cloneableType), true);
+ arraySuperType = makeIntersectionType(List.of(syms.serializableType,
+ syms.cloneableType), true);
}
}
}
@@ -3811,7 +3823,7 @@
return glbFlattened(union(bounds, lowers), errT);
}
}
- return makeCompoundType(bounds);
+ return makeIntersectionType(bounds);
}
// </editor-fold>
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
index 16079b0..f1bbf15 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -2434,7 +2434,7 @@
@Override
public Type visitClassType(ClassType t, DiagnosticPosition pos) {
- return t.isCompound() ?
+ return t.isIntersection() ?
visitIntersectionClassType((IntersectionClassType)t, pos) : t;
}
@@ -2465,8 +2465,7 @@
}
supertypes.append(i.tsym.type);
}
- IntersectionClassType notionalIntf =
- (IntersectionClassType)types.makeCompoundType(supertypes.toList());
+ IntersectionClassType notionalIntf = types.makeIntersectionType(supertypes.toList());
notionalIntf.allparams_field = targs.toList();
notionalIntf.tsym.flags_field |= INTERFACE;
return notionalIntf.tsym;
@@ -4032,7 +4031,7 @@
} else if (bounds.length() == 1) {
return bounds.head.type;
} else {
- Type owntype = types.makeCompoundType(TreeInfo.types(bounds));
+ Type owntype = types.makeIntersectionType(TreeInfo.types(bounds));
// ... the variable's bound is a class type flagged COMPOUND
// (see comment for TypeVar.bound).
// In this case, generate a class tree that represents the
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
index 4e6d0d3..d5e9c47 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
@@ -1813,7 +1813,7 @@
Type t1,
Type t2) {
return checkCompatibleAbstracts(pos, t1, t2,
- types.makeCompoundType(t1, t2));
+ types.makeIntersectionType(t1, t2));
}
public boolean checkCompatibleAbstracts(DiagnosticPosition pos,
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
index 3a1c872..c88386e 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java
@@ -373,7 +373,7 @@
List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
if (Type.containsAny(upperBounds, vars)) {
TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
- fresh_tvar.type = new TypeVar(fresh_tvar, types.makeCompoundType(uv.getBounds(InferenceBound.UPPER)), null);
+ fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
todo.append(uv);
uv.inst = fresh_tvar.type;
} else if (upperBounds.nonEmpty()) {
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
index 18cc85d..1253f87 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -1179,12 +1179,14 @@
@Override
public void visitClassDef(JCClassDecl tree) {
List<Frame> prevStack = frameStack;
+ int prevLambdaCount = lambdaCount;
SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
syntheticMethodNameCounts;
Map<ClassSymbol, Symbol> prevClinits = clinits;
DiagnosticSource prevSource = log.currentSource();
try {
log.useSource(tree.sym.sourcefile);
+ lambdaCount = 0;
syntheticMethodNameCounts = new SyntheticMethodNameCounter();
prevClinits = new HashMap<ClassSymbol, Symbol>();
if (tree.sym.owner.kind == MTH) {
@@ -1211,6 +1213,7 @@
finally {
log.useSource(prevSource.getFile());
frameStack = prevStack;
+ lambdaCount = prevLambdaCount;
syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
clinits = prevClinits;
}
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
index b7f0537..ad00b78 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/TransTypes.java
@@ -750,7 +750,7 @@
Type originalTarget = tree.type;
tree.type = erasure(tree.type);
tree.expr = translate(tree.expr, tree.type);
- if (originalTarget.isCompound()) {
+ if (originalTarget.isIntersection()) {
Type.IntersectionClassType ict = (Type.IntersectionClassType)originalTarget;
for (Type c : ict.getExplicitComponents()) {
Type ec = erasure(c);
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
index ef9f0cd..f407915 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties
@@ -232,9 +232,9 @@
javac.msg.bug=\
An exception has occurred in the compiler ({0}). \
-Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
-after checking the database for duplicates. \
-Include your program and the following diagnostic in your report. Thank you.
+Please file a bug against the Java compiler via the Java bug reporting page (http://bugreport.java.com) \
+after checking the Bug Database (http://bugs.java.com) for duplicates. \
+Include your program and the following diagnostic in your report. Thank you.
javac.msg.io=\
\n\nAn input/output error occurred.\n\
diff --git a/langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java b/langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java
new file mode 100644
index 0000000..cda7c9d
--- /dev/null
+++ b/langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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 8067422
+ * @summary Check that the lambda names are not unnecessarily unstable
+ * @run main TestNonSerializableLambdaNameStability
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.ToolProvider;
+
+public class TestNonSerializableLambdaNameStability {
+
+ public static void main(String... args) throws Exception {
+ new TestNonSerializableLambdaNameStability().run();
+ }
+
+ String lambdaSource = "public class L%d {\n" +
+ " public static class A {\n" +
+ " private Runnable r = () -> { };\n" +
+ " }\n" +
+ " public static class B {\n" +
+ " private Runnable r = () -> { };\n" +
+ " }\n" +
+ " private Runnable r = () -> { };\n" +
+ "}\n";
+
+ String expectedLambdaMethodName = "lambda$new$0";
+
+ void run() throws Exception {
+ List<JavaFileObject> sources = new ArrayList<>();
+
+ for (int i = 0; i < 3; i++) {
+ sources.add(new SourceJavaFileObject("L" + i, String.format(lambdaSource, i)));
+ }
+
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+ try (MemoryFileManager fm = new MemoryFileManager(compiler.getStandardFileManager(null, null, null))) {
+ if (!compiler.getTask(null, fm, null, null, null, sources).call()) {
+ throw new AssertionError("Compilation failed!");
+ }
+
+ for (String file : fm.name2Content.keySet()) {
+ byte[] fileBytes = fm.name2Content.get(file);
+ try (InputStream in = new ByteArrayInputStream(fileBytes)) {
+ boolean foundLambdaMethod = false;
+ ClassFile cf = ClassFile.read(in);
+ StringBuilder seenMethods = new StringBuilder();
+ String sep = "";
+ for (Method m : cf.methods) {
+ String methodName = m.getName(cf.constant_pool);
+ if (expectedLambdaMethodName.equals(methodName)) {
+ foundLambdaMethod = true;
+ break;
+ }
+ seenMethods.append(sep);
+ seenMethods.append(methodName);
+ sep = ", ";
+ }
+
+ if (!foundLambdaMethod) {
+ throw new AbstractMethodError("Did not find the lambda method, " +
+ "found methods: " + seenMethods.toString());
+ }
+ }
+ }
+ }
+ }
+
+ class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+
+ final Map<String, byte[]> name2Content = new HashMap<>();
+
+ public MemoryFileManager(JavaFileManager fileManager) {
+ super(fileManager);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+ try {
+ return new SimpleJavaFileObject(new URI("mem://" + className.replace('.', '/') + kind.extension), kind) {
+ @Override public OutputStream openOutputStream() throws IOException {
+ return new ByteArrayOutputStream() {
+ @Override public void close() throws IOException {
+ super.close();
+ name2Content.put(className, toByteArray());
+ }
+ };
+ }
+ };
+ } catch (URISyntaxException ex) {
+ throw new AssertionError(ex);
+ }
+ }
+
+ }
+
+ class SourceJavaFileObject extends SimpleJavaFileObject {
+
+ private final String code;
+
+ public SourceJavaFileObject(String name, String code) throws URISyntaxException {
+ super(new URI("mem:///" + name + ".java"), Kind.SOURCE);
+ this.code = code;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+ return code;
+ }
+
+ }
+}
diff --git a/langtools/test/tools/javac/multicatch/8071291/T8071291.java b/langtools/test/tools/javac/multicatch/8071291/T8071291.java
new file mode 100644
index 0000000..dd0e580
--- /dev/null
+++ b/langtools/test/tools/javac/multicatch/8071291/T8071291.java
@@ -0,0 +1,49 @@
+/*
+ * 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 8071291
+ * @summary Compiler crashes trying to cast UnionType to IntersectionClassType
+ * @compile T8071291.java
+ */
+
+class T8071291 {
+
+ interface A { }
+ class Exception1 extends Exception implements A { }
+ class Exception2 extends Exception implements A { }
+
+ void test(boolean cond) {
+ try {
+ if (cond) {
+ throw new Exception1();
+ } else {
+ throw new Exception2();
+ }
+ }
+ catch (Exception1|Exception2 x) {
+ if (x instanceof Exception1) { }
+ }
+ }
+}
diff --git a/nashorn/.hgtags b/nashorn/.hgtags
index 07062ea..613d7c1 100644
--- a/nashorn/.hgtags
+++ b/nashorn/.hgtags
@@ -491,3 +491,12 @@
c3c1c032ff27f5967edcd595eeca23a005c8a7fe jdk8u71-b07
0eb2b5f656d5d738957259d5f3f7982dc5b2a864 jdk8u71-b08
79a56b0e79aa18f18c930236157458d7893537db jdk8u71-b09
+667e020da337e453eac8ecb9285c9b34a47e25fd jdk8u72-b00
+a105e7b0eff93895b82e3d372a63df4311d79821 jdk8u72-b01
+f7c3d65076a0c0bf1bb4ea633b4ea0af9ffb12fe jdk8u72-b02
+c47a6341ae31e394f6748acbeebf68de3ae285ff jdk8u72-b03
+4592976d8655d9ec0ad364901ae07c79813c8cd4 jdk8u72-b04
+0c87ce7cc7d01462476bce07945dc1646b4f08d1 jdk8u72-b05
+a2591c7bcb92f5bb2bd53b46d5a2c97be367f7fe jdk8u72-b06
+619a1ac46fc46394f524f7aa587f6c70d3d7ab52 jdk8u72-b07
+bcc30e9810fe0b3f19556dcfce0cdd801dbfe463 jdk8u72-b08
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
index 7587431..df740ef 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java
@@ -54,10 +54,9 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_NEWMAP_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROPERTYMAP_TYPE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_DESC;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_TYPE;
@@ -282,9 +281,9 @@
assert specs != null;
if (!specs.isEmpty()) {
mi.memberInfoArray(className, specs);
- mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC);
+ mi.invokeStatic(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_CREATEBUILTIN, SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC);
} else {
- mi.invokeStatic(SCRIPTFUNCTIONIMPL_TYPE, SCRIPTFUNCTIONIMPL_MAKEFUNCTION, SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC);
+ mi.invokeStatic(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_CREATEBUILTIN, SCRIPTFUNCTION_CREATEBUILTIN_DESC);
}
if (arityFound) {
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
index 97a4e0d..b47877d 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ConstructorGenerator.java
@@ -38,9 +38,8 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_SETCONSTRUCTOR_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.PROTOTYPEOBJECT_TYPE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC3;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_INIT_DESC4;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTIONIMPL_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC3;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_INIT_DESC4;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETARITY_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTFUNCTION_SETPROTOTYPE;
@@ -55,7 +54,7 @@
import jdk.internal.org.objectweb.asm.Handle;
/**
- * This class generates constructor class for a @ClassInfo annotated class.
+ * This class generates constructor class for a @ScriptClass annotated class.
*
*/
public class ConstructorGenerator extends ClassGenerator {
@@ -75,8 +74,8 @@
}
byte[] getClassBytes() {
- // new class extensing from ScriptObject
- final String superClass = (constructor != null)? SCRIPTFUNCTIONIMPL_TYPE : SCRIPTOBJECT_TYPE;
+ // new class extending from ScriptObject
+ final String superClass = (constructor != null)? SCRIPTFUNCTION_TYPE : SCRIPTOBJECT_TYPE;
cw.visit(V1_7, ACC_FINAL, className, null, superClass, null);
if (memberCount > 0) {
// add fields
@@ -182,8 +181,8 @@
loadMap(mi);
} else {
// call Function.<init>
- superClass = SCRIPTFUNCTIONIMPL_TYPE;
- superDesc = (memberCount > 0) ? SCRIPTFUNCTIONIMPL_INIT_DESC4 : SCRIPTFUNCTIONIMPL_INIT_DESC3;
+ superClass = SCRIPTFUNCTION_TYPE;
+ superDesc = (memberCount > 0) ? SCRIPTFUNCTION_INIT_DESC4 : SCRIPTFUNCTION_INIT_DESC3;
mi.loadLiteral(constructor.getName());
mi.visitLdcInsn(new Handle(H_INVOKESTATIC, scriptClassInfo.getJavaName(), constructor.getJavaName(), constructor.getJavaDesc()));
loadMap(mi);
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
index cc3524d..a868ada 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java
@@ -161,7 +161,7 @@
}
/**
- * Tag something as optimitic builtin or not
+ * Tag something as optimistic builtin or not
* @param isOptimistic boolean, true if builtin constructor
*/
public void setIsOptimistic(final boolean isOptimistic) {
@@ -178,7 +178,7 @@
}
/**
- * Set thre SpecializedFunction link logic class for specializations, i.e. optimistic
+ * Set the SpecializedFunction link logic class for specializations, i.e. optimistic
* builtins
* @param linkLogicClass link logic class
*/
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
index 115e4b1..80308ac 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/PrototypeGenerator.java
@@ -42,7 +42,7 @@
import java.io.IOException;
/**
- * This class generates prototype class for a @ClassInfo annotated class.
+ * This class generates prototype class for a @ScriptClass annotated class.
*
*/
public class PrototypeGenerator extends ClassGenerator {
@@ -57,7 +57,7 @@
}
byte[] getClassBytes() {
- // new class extensing from ScriptObject
+ // new class extending from ScriptObject
cw.visit(V1_7, ACC_FINAL | ACC_SUPER, className, null, PROTOTYPEOBJECT_TYPE, null);
if (memberCount > 0) {
// add fields
@@ -155,7 +155,7 @@
*/
public static void main(final String[] args) throws IOException {
if (args.length != 1) {
- System.err.println("Usage: " + ConstructorGenerator.class.getName() + " <class>");
+ System.err.println("Usage: " + PrototypeGenerator.class.getName() + " <class>");
System.exit(1);
}
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java
index c91d758..ca9a325 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java
@@ -48,7 +48,7 @@
*
*/
public final class ScriptClassInfo {
- // descriptots for various annotations
+ // descriptors for various annotations
static final String SCRIPT_CLASS_ANNO_DESC = Type.getDescriptor(ScriptClass.class);
static final String CONSTRUCTOR_ANNO_DESC = Type.getDescriptor(Constructor.class);
static final String FUNCTION_ANNO_DESC = Type.getDescriptor(Function.class);
@@ -140,7 +140,7 @@
}
boolean isPrototypeNeeded() {
- // Prototype class generation is needed if we have atleast one
+ // Prototype class generation is needed if we have at least one
// prototype property or @Constructor defined in the class.
for (final MemberInfo memInfo : members) {
if (memInfo.getWhere() == Where.PROTOTYPE || memInfo.isConstructor()) {
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
index ae58aad..62fa339 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java
@@ -118,7 +118,7 @@
addScriptMember(memInfo);
return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
- // These could be "null" if values are not suppiled,
+ // These could be "null" if values are not supplied,
// in which case we have to use the default values.
private String name;
private Integer attributes;
@@ -194,7 +194,7 @@
final MemberInfo memInfo = new MemberInfo();
- //annokind == e.g. GETTER or SPECIALIZED_FUNCTION
+ // annoKind == GETTER or SPECIALIZED_FUNCTION
memInfo.setKind(annoKind);
memInfo.setJavaName(methodName);
memInfo.setJavaDesc(methodDesc);
@@ -203,7 +203,7 @@
addScriptMember(memInfo);
return new AnnotationVisitor(Opcodes.ASM4, delegateAV) {
- // These could be "null" if values are not suppiled,
+ // These could be "null" if values are not supplied,
// in which case we have to use the default values.
private String name;
private Integer attributes;
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
index 0d6a9e3..354289c 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java
@@ -65,7 +65,6 @@
* 2) add "Map" type static field named "$map".
* 3) add static initializer block to initialize map.
*/
-
public class ScriptClassInstrumentor extends ClassVisitor {
private final ScriptClassInfo scriptClassInfo;
private final int memberCount;
@@ -267,7 +266,7 @@
*/
public static void main(final String[] args) throws IOException {
if (args.length != 1) {
- System.err.println("Usage: " + ScriptClassInfoCollector.class.getName() + " <class>");
+ System.err.println("Usage: " + ScriptClassInstrumentor.class.getName() + " <class>");
System.exit(1);
}
diff --git a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
index 8656a42..6669514 100644
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java
@@ -31,10 +31,9 @@
import java.util.Collections;
import java.util.List;
import jdk.internal.org.objectweb.asm.Type;
-import jdk.nashorn.internal.objects.PrototypeObject;
-import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.PrototypeObject;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Specialization;
@@ -88,7 +87,6 @@
static final Type TYPE_PROPERTYMAP = Type.getType(PropertyMap.class);
static final Type TYPE_PROTOTYPEOBJECT = Type.getType(PrototypeObject.class);
static final Type TYPE_SCRIPTFUNCTION = Type.getType(ScriptFunction.class);
- static final Type TYPE_SCRIPTFUNCTIONIMPL = Type.getType(ScriptFunctionImpl.class);
static final Type TYPE_SCRIPTOBJECT = Type.getType(ScriptObject.class);
static final String PROTOTYPE_SUFFIX = "$Prototype";
@@ -122,17 +120,14 @@
static final String SCRIPTFUNCTION_SETARITY_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE);
static final String SCRIPTFUNCTION_SETPROTOTYPE = "setPrototype";
static final String SCRIPTFUNCTION_SETPROTOTYPE_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_OBJECT);
-
- // ScriptFunctionImpl
- static final String SCRIPTFUNCTIONIMPL_TYPE = TYPE_SCRIPTFUNCTIONIMPL.getInternalName();
- static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION = "makeFunction";
- static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
+ static final String SCRIPTFUNCTION_CREATEBUILTIN = "createBuiltin";
+ static final String SCRIPTFUNCTION_CREATEBUILTIN_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
- static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
+ static final String SCRIPTFUNCTION_CREATEBUILTIN_SPECS_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
- static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
+ static final String SCRIPTFUNCTION_INIT_DESC3 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
- static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
+ static final String SCRIPTFUNCTION_INIT_DESC4 =
Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_SPECIALIZATION_ARRAY);
// ScriptObject
diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml
index 555c345..630dcea 100644
--- a/nashorn/make/build.xml
+++ b/nashorn/make/build.xml
@@ -209,10 +209,11 @@
</jar>
</target>
+ <!-- generate javadoc for all Nashorn and ASM classes -->
<target name="javadoc" depends="jar">
<javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${src.dir}/overview.html"
extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
- additionalparam="-quiet" failonerror="true">
+ additionalparam="-quiet" failonerror="true" useexternalfile="true">
<classpath>
<pathelement location="${build.classes.dir}"/>
</classpath>
@@ -226,10 +227,23 @@
</javadoc>
</target>
+ <!-- generate javadoc for Nashorn classes -->
+ <target name="javadocnh" depends="jar">
+ <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${src.dir}/overview.html"
+ extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
+ additionalparam="-quiet" failonerror="true" useexternalfile="true">
+ <classpath>
+ <pathelement location="${build.classes.dir}"/>
+ </classpath>
+ <fileset dir="${src.dir}" includes="**/*.java"/>
+ <link href="http://docs.oracle.com/javase/8/docs/api/"/>
+ </javadoc>
+ </target>
+
<!-- generate javadoc only for nashorn extension api classes -->
<target name="javadocapi" depends="jar">
<javadoc destdir="${dist.javadoc.dir}" use="yes" extdirs="${nashorn.ext.path}"
- windowtitle="${nashorn.product.name}" additionalparam="-quiet" failonerror="true">
+ windowtitle="${nashorn.product.name}" additionalparam="-quiet" failonerror="true" useexternalfile="true">
<classpath>
<pathelement location="${build.classes.dir}"/>
</classpath>
@@ -238,7 +252,6 @@
</javadoc>
</target>
-
<!-- generate shell.html for shell tool documentation -->
<target name="shelldoc" depends="jar">
<java classname="${nashorn.shell.tool}" dir="${basedir}" output="${dist.dir}/shell.html" failonerror="true" fork="true">
@@ -267,8 +280,8 @@
<javac srcdir="${test.src.dir}"
destdir="${build.test.classes.dir}"
classpath="${javac.test.classpath}"
- source="${javac.source}"
- target="${javac.target}"
+ source="${test.javac.source}"
+ target="${test.javac.target}"
debug="${javac.debug}"
encoding="${javac.encoding}"
includeantruntime="false" fork="true">
@@ -460,7 +473,7 @@
</testng>
</target>
- <target name="test" depends="get-testng, javadoc, test-pessimistic, test-optimistic"/>
+ <target name="test" depends="get-testng, javadocnh, test-pessimistic, test-optimistic"/>
<target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
<echo message="Running test suite in OPTIMISTIC mode..."/>
diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties
index d826427..1632f2c 100644
--- a/nashorn/make/project.properties
+++ b/nashorn/make/project.properties
@@ -30,6 +30,8 @@
build.compiler=modern
javac.source=1.7
javac.target=1.7
+test.javac.source=1.8
+test.javac.target=1.8
# nashorn version information
nashorn.version=0.1
diff --git a/nashorn/samples/EvalWithArbitraryThis.java b/nashorn/samples/EvalWithArbitraryThis.java
new file mode 100644
index 0000000..4b9c0c7
--- /dev/null
+++ b/nashorn/samples/EvalWithArbitraryThis.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javax.script.*;
+import jdk.nashorn.api.scripting.*;
+
+// Simple nashorn demo that evals a script with arbitrary script
+// object bound as "this" for the evaluated script.
+
+public class EvalWithArbitraryThis {
+ public static void main(String[] args) throws Exception {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+ Object sobj = e.eval("( { foo: 343, bar: 'hello' } )");
+
+ // "this" bound to sobj in this eval.
+ // so it prints sobj.foo and sobj.bar.
+ ((ScriptObjectMirror)sobj).eval("print(this.foo); print(this.bar)");
+ }
+}
diff --git a/nashorn/samples/LambdaAsFunc.java b/nashorn/samples/LambdaAsFunc.java
new file mode 100644
index 0000000..1ed5380
--- /dev/null
+++ b/nashorn/samples/LambdaAsFunc.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javax.script.*;
+import java.util.function.*;
+
+// example demonstrating that arbitrary Lambda can be called as function from script
+
+public class LambdaAsFunc {
+ public static void main(String[] args) throws Exception {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+
+ // expose a lambda as top-level script function
+ e.put("upper", (Function<String, String>) String::toUpperCase);
+
+ // call lambda as though it is a normal script function
+ System.out.println(e.eval("upper('hello')"));
+ }
+}
diff --git a/nashorn/samples/Main.asm b/nashorn/samples/Main.asm
new file mode 100644
index 0000000..3c4fd5e
--- /dev/null
+++ b/nashorn/samples/Main.asm
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Simple sample to demonstrate openjdk asmtools assembler with
+// nashorn dynalink linker in a invokedynamic instruction.
+//
+// To assemble this file, use the following command:
+//
+// java -cp <asmtools.jar> org.openjdk.asmtools.Main jasm Main.asm
+//
+// See also: https://wiki.openjdk.java.net/display/CodeTools/asmtools
+//
+// NOTE: Uses nashorn internals and so *may* break with later nashorn!
+
+super public class Main
+ version 52:0
+{
+
+
+public Method "<init>":"()V"
+ stack 1 locals 1
+{
+ aload_0;
+ invokespecial Method java/lang/Object."<init>":"()V";
+ return;
+}
+
+public static Method main:"([Ljava/lang/String;)V"
+ stack 2 locals 2
+{
+ // List l = new ArrayList();
+ new class java/util/ArrayList;
+ dup;
+ invokespecial Method java/util/ArrayList."<init>":"()V";
+ astore_1;
+ aload_1;
+
+ // l.add("hello");
+ ldc String "hello";
+ invokeinterface InterfaceMethod java/util/List.add:"(Ljava/lang/Object;)Z", 2;
+ pop;
+
+ // l.add("world");
+ aload_1;
+ ldc String "world";
+ invokeinterface InterfaceMethod java/util/List.add:"(Ljava/lang/Object;)Z", 2;
+ pop;
+
+ // printLength(l);
+ aload_1;
+ invokestatic Method printLength:"(Ljava/lang/Object;)V";
+
+ // printLength(args); // args is argument of main method
+ aload_0;
+ invokestatic Method printLength:"(Ljava/lang/Object;)V";
+ return;
+}
+
+private static Method printLength:"(Ljava/lang/Object;)V"
+ stack 2 locals 1
+{
+ getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
+ aload_0;
+
+ // Using nashorn embedded dynalink linker with the following invokedynamic
+ // 'length' property on a bean - arrays, lists supported
+
+ invokedynamic InvokeDynamic REF_invokeStatic:jdk/nashorn/internal/runtime/linker/Bootstrap.bootstrap:"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;I)Ljava/lang/invoke/CallSite;":"dyn:getProp|getElem|getMethod:length":"(Ljava/lang/Object;)Ljava/lang/Object;" int 0;
+
+ // print 'length' value
+ invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/Object;)V";
+ return;
+}
+
+} // end Class Main
diff --git a/nashorn/samples/PrintToString.java b/nashorn/samples/PrintToString.java
new file mode 100644
index 0000000..21f1f9e
--- /dev/null
+++ b/nashorn/samples/PrintToString.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import javax.script.*;
+import java.io.StringWriter;
+
+// simple example demonstrating capturing of "print" output
+// from script execution as a String via script engine API.
+
+public class PrintToString {
+ public static void main(String[] args) throws ScriptException {
+ ScriptEngineManager m = new ScriptEngineManager();
+ ScriptEngine e = m.getEngineByName("nashorn");
+ StringWriter sw = new StringWriter();
+ e.getContext().setWriter(sw);
+ e.eval("print('hello world')");
+ System.out.println(sw.toString());
+ }
+}
diff --git a/nashorn/samples/array_removeif.js b/nashorn/samples/array_removeif.js
new file mode 100644
index 0000000..68cc873
--- /dev/null
+++ b/nashorn/samples/array_removeif.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Sample for Collection.removeIf and Java.to
+// See http://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-
+
+var langs = [
+ "java", "javascript",
+ "C", "C#", "C++",
+ "Erlang", "Haskell"
+];
+
+// convert script array to a Java List
+function asList(array) {
+ return Java.to(array, java.util.List);
+}
+
+// remove elements that satisfy a predicate
+// using Collection.removeIf(Predicate)
+asList(langs).removeIf(
+ function(s) s.startsWith("C"));
+
+// print modified array
+print(langs);
diff --git a/nashorn/samples/bind_on_java.js b/nashorn/samples/bind_on_java.js
new file mode 100644
index 0000000..e905a39
--- /dev/null
+++ b/nashorn/samples/bind_on_java.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// sample to demonstrate calling Function.prototype.bind on Java methods.
+
+var DoubleStream = java.util.stream.DoubleStream;
+var r = new java.util.Random();
+
+// bind "this" for nextGaussian method of Random class
+var next = Function.bind.call(r.nextGaussian, r);
+
+// next is used as no argument "function"
+DoubleStream
+ .generate(function() next())
+ .limit(100)
+ .forEach(print);
diff --git a/nashorn/samples/call_bind_java.js b/nashorn/samples/call_bind_java.js
new file mode 100644
index 0000000..d67d5da
--- /dev/null
+++ b/nashorn/samples/call_bind_java.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Sample demonstrating calling Java methods like normal
+// functions. Bound instance methods, static methods can be
+// called like normal script functions.
+
+// Java types used
+var Files = Java.type("java.nio.file.Files");
+var FileSystems = Java.type("java.nio.file.FileSystems");
+var System = Java.type("java.lang.System");
+
+var fs = FileSystems.default;
+var bind = Function.prototype.bind;
+
+// Java methods as "functions"
+
+// Java method with bound "this"
+var Path = bind.call(fs.getPath, fs);
+// Java static method
+var Property = System.getProperty;
+
+// call Java static methods and bound instance methods
+// like normal script functions.
+
+var root = Path("/");
+// print URI for root dir
+print(root.toUri());
+var home = Path(Property("user.home"));
+// list home directory
+Files.walk(home).forEach(print);
diff --git a/nashorn/samples/check_nashorn.js b/nashorn/samples/check_nashorn.js
new file mode 100644
index 0000000..feeb30b
--- /dev/null
+++ b/nashorn/samples/check_nashorn.js
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// check if script is being run using nashorn script engine
+function isNashorn() {
+ try {
+ // "engine" variable is of type javax.script.ScriptEngine is defined
+ // by nashorn jsr-223 engine. Check the name of the engine from
+ // javax.script.ScriptEngineFactory associated
+
+ return engine.factory.engineName.contains("Nashorn");
+ } catch (e) {
+ // if engine or any of the properties are undefined
+ // then script is not being run using nashorn.
+ return false;
+ }
+}
diff --git a/nashorn/samples/datetime.js b/nashorn/samples/datetime.js
new file mode 100644
index 0000000..3d5f109
--- /dev/null
+++ b/nashorn/samples/datetime.js
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// converting b/w JavaScript Date and Java LocalDateTime
+
+// JavaScript Date with current time
+var d = new Date();
+print(d);
+
+// Java 8 java.time classes used
+var Instant = java.time.Instant;
+var LocalDateTime = java.time.LocalDateTime;
+var ZoneId = java.time.ZoneId;
+
+// Date.prototype.getTime
+
+// getTime() method returns the numeric value corresponding to the time
+// for the specified date according to universal time. The value returned
+// by the getTime() method is the number of milliseconds since 1 January 1970 00:00:00 UTC.
+// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime
+
+// Java Instant.ofEpochMilli to convert time in milliseconds to Instant object
+// https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#ofEpochMilli-long-
+
+var instant = Instant.ofEpochMilli(d.getTime());
+
+// Instant to LocalDateTime using LocalDateTime.ofInstant
+// https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#ofInstant-java.time.Instant-java.time.ZoneId-
+
+var ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+print(ldt);
+
+// converting a LocalDateTime to JavaScript Date
+// convert LocalDateTime to Instant first
+// https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#atZone-java.time.ZoneId-
+
+var instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
+
+// instant to to epoch milliseconds
+// https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html#toEpochMilli--
+// and then to JavaScript Date from time in milliseconds
+// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date
+
+var d1 = new Date(instant.toEpochMilli());
+print(d1);
diff --git a/nashorn/samples/defaults.js b/nashorn/samples/defaults.js
new file mode 100644
index 0000000..9347998
--- /dev/null
+++ b/nashorn/samples/defaults.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// print default methods of a Java class
+
+if (arguments.length == 0) {
+ print("Usage: jjs defaults.js -- <java class name>");
+ exit(1);
+}
+
+var jclass = Java.type(arguments[0]).class;
+for each (m in jclass.methods) {
+ // http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#isDefault--
+ if (m.default) print(m);
+}
diff --git a/nashorn/samples/exceptionswallow.js b/nashorn/samples/exceptionswallow.js
new file mode 100644
index 0000000..82f4e2d
--- /dev/null
+++ b/nashorn/samples/exceptionswallow.js
@@ -0,0 +1,136 @@
+#// Usage: jjs exceptionswallow.js -- <directory>
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This example demonstrates Java subclassing by Java.extend
+// and javac Compiler and Tree API. This example looks for
+// empty catch blocks ("exception swallow") and reports those.
+
+if (arguments.length == 0) {
+ print("Usage: jjs exceptionswallow.js -- <directory>");
+ exit(1);
+}
+
+// Java types used
+var File = Java.type("java.io.File");
+var Files = Java.type("java.nio.file.Files");
+var StringArray = Java.type("java.lang.String[]");
+var ToolProvider = Java.type("javax.tools.ToolProvider");
+var Tree = Java.type("com.sun.source.tree.Tree");
+var EmptyStatementTree = Java.type("com.sun.source.tree.EmptyStatementTree");
+var Trees = Java.type("com.sun.source.util.Trees");
+var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
+
+// printEmptyCatch
+
+function printEmptyCatch() {
+ // get the system compiler tool
+ var compiler = ToolProvider.systemJavaCompiler;
+ // get standard file manager
+ var fileMgr = compiler.getStandardFileManager(null, null, null);
+ // Using Java.to convert script array (arguments) to a Java String[]
+ var compUnits = fileMgr.getJavaFileObjects(
+ Java.to(arguments, StringArray));
+ // create a new compilation task
+ var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
+
+ // SourcePositions object to get positions of AST nodes
+ var sourcePositions = Trees.instance(task).sourcePositions;
+
+ // subclass SimpleTreeVisitor - to print empty catch
+ var EmptyCatchFinder = Java.extend(TreeScanner);
+
+ function hasOnlyEmptyStats(stats) {
+ var itr = stats.iterator();
+ while (itr.hasNext()) {
+ if (! (itr.next() instanceof EmptyStatementTree)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ var visitor = new EmptyCatchFinder() {
+ // current CompilationUnitTree
+ compUnit: null,
+ // current LineMap (pos -> line, column)
+ lineMap: null,
+ // current compilation unit's file name
+ fileName: null,
+
+ // overrides of TreeScanner methods
+
+ visitCompilationUnit: function(node, p) {
+ // capture info about current Compilation unit
+ this.compUnit = node;
+ this.lineMap = node.lineMap;
+ this.fileName = node.sourceFile.name;
+
+ // Using Java.super API to call super class method here
+ return Java.super(visitor).visitCompilationUnit(node, p);
+ },
+
+ visitCatch: function (node, p) {
+ var stats = node.block.statements;
+ if (stats.empty || hasOnlyEmptyStats(stats)) {
+ // print information on this empty catch
+ var pos = sourcePositions.getStartPosition(this.compUnit, node);
+ var line = this.lineMap.getLineNumber(pos);
+ var col = this.lineMap.getColumnNumber(pos);
+ print("Exception swallow" + " @ " + this.fileName + ":" + line + ":" + col);
+ // print(node);
+ }
+ }
+ }
+
+ for each (var cu in task.parse()) {
+ cu.accept(visitor, null);
+ }
+}
+
+// for each ".java" file in directory (recursively) and check it!
+function main(dir) {
+ Files.walk(dir.toPath()).
+ forEach(function(p) {
+ var name = p.toFile().absolutePath;
+ if (name.endsWith(".java")) {
+ try {
+ printEmptyCatch(p.toFile().getAbsolutePath());
+ } catch (e) {
+ print(e);
+ }
+ }
+ });
+}
+
+main(new File(arguments[0]));
diff --git a/nashorn/samples/find_max_lines.js b/nashorn/samples/find_max_lines.js
new file mode 100644
index 0000000..a49d6bd
--- /dev/null
+++ b/nashorn/samples/find_max_lines.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Find the file with maximum number of lines
+
+var Files = Java.type("java.nio.file.Files");
+var Integer = Java.type("java.lang.Integer");
+var Paths = Java.type("java.nio.file.Paths");
+
+var file = arguments.length == 0? "." : arguments[0];
+var ext = arguments.length > 1? arguments[1] : ".java";
+var path = Paths.get(file);
+
+// return number of lines in given Path (that represents a file)
+function lines(p) {
+ var strm = Files.lines(p);
+ try {
+ return strm.count();
+ } finally {
+ strm.close();
+ }
+}
+
+// walk files, map to file and lines, find the max
+var obj = Files.find(path, Integer.MAX_VALUE,
+ function(p, a) !p.toFile().isDirectory() && p.toString().endsWith(ext)).
+map(function(p) ({ path : p, lines: lines(p) })).
+max(function(x, y) x.lines - y.lines).get();
+
+// print path and lines of the max line file
+print(obj.path, obj.lines);
diff --git a/nashorn/samples/find_nonfinals2.js b/nashorn/samples/find_nonfinals2.js
index 75fde62..cd00303 100644
--- a/nashorn/samples/find_nonfinals2.js
+++ b/nashorn/samples/find_nonfinals2.js
@@ -43,7 +43,6 @@
// Java types used
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
var StringArray = Java.type("java.lang.String[]");
var ToolProvider = Java.type("javax.tools.ToolProvider");
var Tree = Java.type("com.sun.source.tree.Tree");
@@ -106,7 +105,7 @@
// for each ".java" file in directory (recursively).
function main(dir) {
var totalCount = 0;
- Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
+ Files.walk(dir.toPath()).
forEach(function(p) {
var name = p.toFile().absolutePath;
if (name.endsWith(".java")) {
diff --git a/nashorn/samples/fixed_point.js b/nashorn/samples/fixed_point.js
new file mode 100644
index 0000000..249384f
--- /dev/null
+++ b/nashorn/samples/fixed_point.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Simple sample demonstrating "fixed point" computation with Streams
+
+// See also https://mitpress.mit.edu/sicp/chapter1/node21.html#secprocgeneralmethods
+var Stream = Java.type("java.util.stream.Stream");
+
+// generic fixed point procedure
+function fixed_point(f, init_guess) {
+ var tolerance = 0.00001;
+ function close_enough(v1, v2) Math.abs(v1 - v2) < tolerance;
+
+ var prev;
+ return Stream.iterate(init_guess, f)
+ .filter(function(x) {
+ try {
+ return prev == undefined? false : close_enough(prev, x);
+ } finally {
+ prev = x;
+ }
+ })
+ .findFirst()
+ .get();
+}
+
+// solution to x = cos(x)
+print(fixed_point(Math.cos, 1.0))
+
+// solution to x = sin(x) + cos(x)
+print(fixed_point(function(x) Math.sin(x) + Math.cos(x), 1.0));
+
+// square root by Newton's method
+// http://en.wikipedia.org/wiki/Newton's_method
+function sqrt(n)
+ fixed_point(function(x) (x + n/x) / 2, 2.0);
+
+print(sqrt(2))
+print(sqrt(3))
+
+
diff --git a/nashorn/samples/importstatic.js b/nashorn/samples/importstatic.js
new file mode 100644
index 0000000..39d9f3c
--- /dev/null
+++ b/nashorn/samples/importstatic.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Java like "import static class_name.*" for nashorn
+
+function importStatic(clazz) {
+ // make sure the argument is a Java type
+ if (! Java.isType(clazz)) {
+ throw new TypeError(clazz + " is not a Java type");
+ }
+
+ // bind properties of clazz to an object
+ var obj = Object.bindProperties({}, clazz);
+
+ // copy properties to global to "import" those
+ for (var i in obj) {
+ this[i] = obj[i];
+ }
+}
+
+importStatic(java.time.Instant);
+print(now());
+print(ofEpochSecond(1));
+print(parse("2007-12-03T10:15:30.00Z"));
diff --git a/nashorn/samples/javabind.js b/nashorn/samples/javabind.js
new file mode 100644
index 0000000..e594efa
--- /dev/null
+++ b/nashorn/samples/javabind.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// bind on a Java method
+
+// #javascript "bind" function
+var bind = Function.prototype.bind;
+
+// Java console object
+var console = java.lang.System.console();
+
+// arguments "this" and prompt string of Console.readLine method are bound
+var readName = bind.call(console.readLine, console, "Your name: ");
+
+// Now call it like a function that takes no arguments!
+print("Hello,", readName());
diff --git a/nashorn/samples/javaconstructorbind.js b/nashorn/samples/javaconstructorbind.js
new file mode 100644
index 0000000..68c13f3
--- /dev/null
+++ b/nashorn/samples/javaconstructorbind.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// bind on a Java constructor
+
+// See Function.prototype.bind:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
+var bind = Function.prototype.bind;
+
+var URL = Java.type("java.net.URL");
+
+// get the constructor that accepts URL, String parameters.
+// constructor signatures are properties of type object.
+var newURL = URL["(URL, String)"];
+
+// bind "context" URL parameter.
+var TwitterURL = bind.call(newURL, null, new URL('https://www.twitter.com'));
+
+// now you can create context relative URLs using the bound constructor
+print(new TwitterURL("sundararajan_a"));
+
+// read the URL content and print (optional part)
+
+var BufferedReader = Java.type("java.io.BufferedReader");
+var InputStreamReader = Java.type("java.io.InputStreamReader");
+
+// function to retrieve text content of the given URL
+function readTextFromURL(url) {
+ var str = '';
+ var u = new URL(url);
+ var reader = new BufferedReader(
+ new InputStreamReader(u.openStream()));
+ try {
+ reader.lines().forEach(function(x) str += x);
+ return str;
+ } finally {
+ reader.close();
+ }
+}
+
+print(readTextFromURL(new TwitterURL("sundararajan_a")));
diff --git a/nashorn/samples/javafoovars.js b/nashorn/samples/javafoovars.js
index 037c2bf..31fc5ba 100644
--- a/nashorn/samples/javafoovars.js
+++ b/nashorn/samples/javafoovars.js
@@ -42,7 +42,6 @@
// Java types used
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
var StringArray = Java.type("java.lang.String[]");
var ToolProvider = Java.type("javax.tools.ToolProvider");
var Tree = Java.type("com.sun.source.tree.Tree");
@@ -81,7 +80,7 @@
// for each ".java" file in directory (recursively) count "foo".
function main(dir) {
var totalCount = 0;
- Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
+ Files.walk(dir.toPath()).
forEach(function(p) {
var name = p.toFile().absolutePath;
if (name.endsWith(".java")) {
diff --git a/nashorn/samples/mapwith.js b/nashorn/samples/mapwith.js
new file mode 100644
index 0000000..70672d4
--- /dev/null
+++ b/nashorn/samples/mapwith.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Using a Java map with Javascript "with" statement
+
+var map = new java.util.HashMap();
+map.put("foo", 34);
+map.put("bar", "hello");
+
+var obj = {
+ __noSuchProperty__: function(name) {
+ return map.get(name);
+ }
+};
+
+with(obj) {
+ print(foo);
+ print(bar);
+}
diff --git a/nashorn/samples/mothers_day.js b/nashorn/samples/mothers_day.js
new file mode 100644
index 0000000..e232633
--- /dev/null
+++ b/nashorn/samples/mothers_day.js
@@ -0,0 +1,56 @@
+# compute Mothers day of the given the year
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// print "Mother's day" of the given year using Java Time API
+
+if (arguments.length == 0) {
+ print("Usage: jjs mothers_day.js -- year");
+ exit(1);
+}
+
+// java classes used
+var DayOfWeek = java.time.DayOfWeek;
+var LocalDate = java.time.LocalDate;
+var TemporalAdjusters = java.time.temporal.TemporalAdjusters;
+
+var year = parseInt(arguments[0]);
+
+// See: https://en.wikipedia.org/?title=Mother%27s_Day
+// We need second Sunday of May. Make April 30 of the given
+// year adjust and adjust to next Sunday from there twice. To adjust a Date
+// we use a common TemporalAdjuster provided in JDK8.
+// https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html
+
+print(LocalDate.of(year, 4, 30).
+ with(TemporalAdjusters.next(DayOfWeek.SUNDAY)).
+ with(TemporalAdjusters.next(DayOfWeek.SUNDAY)));
diff --git a/nashorn/samples/passwordgen.js b/nashorn/samples/passwordgen.js
new file mode 100644
index 0000000..82c4055
--- /dev/null
+++ b/nashorn/samples/passwordgen.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Simple password generator using SecureRandom + stream API
+
+// accept optional password length from command line
+var len = arguments.length? parseInt(arguments[0]) : 8;
+
+// Java types used
+var Collectors = Java.type("java.util.stream.Collectors");
+var SecureRandom = Java.type("java.security.SecureRandom");
+
+// allowed password chars
+var chars =
+ "!@#$%ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+// generated and print password
+print(new SecureRandom().
+ ints(len, 0, chars.length).
+ mapToObj(function(i) chars[i]).
+ collect(Collectors.joining("")));
diff --git a/nashorn/samples/print_symlinks.js b/nashorn/samples/print_symlinks.js
new file mode 100644
index 0000000..410b843
--- /dev/null
+++ b/nashorn/samples/print_symlinks.js
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Print all symbolic links in user's home directory
+
+// JavaImporter and "with" to simulate "import" statements in Java.
+// See https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions
+
+with (new JavaImporter(java.nio.file, java.lang)) {
+
+ var userDir = System.getProperty("user.dir")
+ var home = FileSystems.default.getPath(userDir);
+
+ // JS functions can be passed where Java lambdas are required.
+ // Also, using "Expression closure" extension here.
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Expression_Closures
+
+ Files.walk(home).
+ filter(function(p) Files.isSymbolicLink(p)).
+ forEach(function(p)
+ print(p, '->', Files.readSymbolicLink(p)));
+}
diff --git a/nashorn/samples/resourcetrysuggester.js b/nashorn/samples/resourcetrysuggester.js
new file mode 100644
index 0000000..d21276c
--- /dev/null
+++ b/nashorn/samples/resourcetrysuggester.js
@@ -0,0 +1,156 @@
+#// Usage: jjs resourcetrysuggester.js -- <directory>
+
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This example demonstrates Java subclassing by Java.extend
+// and javac Compiler and Tree API. This example looks for
+// finally clauses with "close" call and suggests "resource try"!
+
+if (arguments.length == 0) {
+ print("Usage: jjs resourcetrysuggester.js -- <directory>");
+ exit(1);
+}
+
+// Java types used
+var ExpressionStatementTree = Java.type("com.sun.source.tree.ExpressionStatementTree");
+var File = Java.type("java.io.File");
+var Files = Java.type("java.nio.file.Files");
+var MemberSelectTree = Java.type("com.sun.source.tree.MemberSelectTree");
+var MethodInvocationTree = Java.type("com.sun.source.tree.MethodInvocationTree");
+var StringArray = Java.type("java.lang.String[]");
+var ToolProvider = Java.type("javax.tools.ToolProvider");
+var Tree = Java.type("com.sun.source.tree.Tree");
+var Trees = Java.type("com.sun.source.util.Trees");
+var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
+
+// resourceTrySuggestions
+
+function resourceTrySuggestions() {
+ // get the system compiler tool
+ var compiler = ToolProvider.systemJavaCompiler;
+ // get standard file manager
+ var fileMgr = compiler.getStandardFileManager(null, null, null);
+ // Using Java.to convert script array (arguments) to a Java String[]
+ var compUnits = fileMgr.getJavaFileObjects(
+ Java.to(arguments, StringArray));
+ // create a new compilation task
+ var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
+
+ // SourcePositions object to get positions of AST nodes
+ var sourcePositions = Trees.instance(task).sourcePositions;
+
+ // subclass SimpleTreeVisitor - to print resource try suggestions
+ var ResourceTrySuggester = Java.extend(TreeScanner);
+
+ function hasOnlyEmptyStats(stats) {
+ var itr = stats.iterator();
+ while (itr.hasNext()) {
+ if (! (itr.next() instanceof EmptyStatementTree)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // does the given statement list has an expression statement which
+ // calls "close" method (don't worry about types - just crude one will do)
+ function hasCloseCall(stats) {
+ var itr = stats.iterator();
+ while (itr.hasNext()) {
+ var stat = itr.next();
+ if (stat instanceof ExpressionStatementTree) {
+ var expr = stat.expression;
+ if (expr instanceof MethodInvocationTree) {
+ var method = expr.methodSelect;
+ if (method instanceof MemberSelectTree) {
+ return method.identifier.toString().equals("close");
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ var visitor = new ResourceTrySuggester() {
+ // current CompilationUnitTree
+ compUnit: null,
+ // current LineMap (pos -> line, column)
+ lineMap: null,
+ // current compilation unit's file name
+ fileName: null,
+
+ // overrides of TreeScanner methods
+
+ visitCompilationUnit: function(node, p) {
+ // capture info about current Compilation unit
+ this.compUnit = node;
+ this.lineMap = node.lineMap;
+ this.fileName = node.sourceFile.name;
+
+ // Using Java.super API to call super class method here
+ return Java.super(visitor).visitCompilationUnit(node, p);
+ },
+
+ visitTry: function (node, p) {
+ var finallyBlk = node.finallyBlock;
+ if (finallyBlk != null && hasCloseCall(finallyBlk.statements)) {
+ var pos = sourcePositions.getStartPosition(this.compUnit, node);
+ var line = this.lineMap.getLineNumber(pos);
+ var col = this.lineMap.getColumnNumber(pos);
+ print("Consider resource try statement " + " @ " + this.fileName + ":" + line + ":" + col);
+ // print(node);
+ }
+ }
+ }
+
+ for each (var cu in task.parse()) {
+ cu.accept(visitor, null);
+ }
+}
+
+// for each ".java" file in directory (recursively) and check it!
+function main(dir) {
+ Files.walk(dir.toPath()).
+ forEach(function(p) {
+ var name = p.toFile().absolutePath;
+ if (name.endsWith(".java")) {
+ try {
+ resourceTrySuggestions(p.toFile().getAbsolutePath());
+ } catch (e) {
+ print(e);
+ }
+ }
+ });
+}
+
+main(new File(arguments[0]));
diff --git a/nashorn/samples/sort_by_java8.js b/nashorn/samples/sort_by_java8.js
new file mode 100644
index 0000000..21eba69
--- /dev/null
+++ b/nashorn/samples/sort_by_java8.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Simple sorting with Java8 APIs
+
+// Separation key-extraction from key ordering
+
+// Simple demo for Comparator.comparing
+// http://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html#comparing-java.util.function.Function-
+
+// data to be sorted
+var cards = [
+ { name: "hello", email: "foo@hello.com" },
+ { name: "world", email: "bar@world.com" },
+ { name: "see", email: "see@dontsee.com" },
+];
+
+var Collections = java.util.Collections;
+var Comparator = java.util.Comparator;
+
+// sort records name in reverse order of names
+Collections.sort(cards,
+ Comparator.comparing(function(a) a.name).reversed());
+
+print(JSON.stringify(cards))
+
+// sort records by email
+Collections.sort(cards,
+ Comparator.comparing(function(a) a.email));
+
+print(JSON.stringify(cards))
diff --git a/nashorn/samples/this_for_eval.js b/nashorn/samples/this_for_eval.js
new file mode 100644
index 0000000..58f584a
--- /dev/null
+++ b/nashorn/samples/this_for_eval.js
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// how to pass arbitrary "this" object for eval'ed script?
+
+var obj = { foo: 44 };
+
+// the following won't work. eval.apply is indirect eval call
+// and so 'this' will be global object always! So, this
+// line will print 'undefined'
+eval.apply(obj, [ " print(this.foo)" ]);
+
+obj.myEval = eval;
+
+// still won't work - still indirect 'eval' call!
+// still undefined is printed!
+obj.myEval("print(this.foo)");
+
+function func(code) {
+ eval(code);
+}
+
+// eval called inside func and so get's func's "this" as it's "this"!
+// So, 44 is printed
+
+func.apply(obj, [ "print(this.foo)" ]);
diff --git a/nashorn/samples/zipfs.js b/nashorn/samples/zipfs.js
index ecb6f61..fba5f15 100644
--- a/nashorn/samples/zipfs.js
+++ b/nashorn/samples/zipfs.js
@@ -36,13 +36,12 @@
var Files = Java.type("java.nio.file.Files")
var FileSystems = Java.type("java.nio.file.FileSystems")
-var FileVisitOption = Java.type("java.nio.file.FileVisitOption")
var Paths = Java.type("java.nio.file.Paths")
var zipfile = Paths.get(arguments[0])
var fs = FileSystems.newFileSystem(zipfile, null)
var root = fs.rootDirectories[0]
-Files.walk(root, FileVisitOption.FOLLOW_LINKS).forEach(
+Files.walk(root).forEach(
function(p) (print(p), print(Files.readAttributes(p, "zip:*")))
)
fs.close()
diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java
index 26c76a1..7839467 100644
--- a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java
+++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java
@@ -117,7 +117,7 @@
* return factory.createLinker();
* }
*
- * public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType type) {
+ * public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
* return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));
* }
* }
diff --git a/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
index 2896732..d65db5b 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
@@ -107,7 +107,7 @@
private final AccessibleObject target;
private final MethodType type;
- public CallerSensitiveDynamicMethod(final AccessibleObject target) {
+ CallerSensitiveDynamicMethod(final AccessibleObject target) {
super(getName(target));
this.target = target;
this.type = getMethodType(target);
@@ -115,8 +115,9 @@
private static String getName(final AccessibleObject target) {
final Member m = (Member)target;
- return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
- m.getName()));
+ final boolean constructor = m instanceof Constructor;
+ return getMethodNameWithSignature(getMethodType(target), constructor ? m.getName() :
+ getClassAndMethodName(m.getDeclaringClass(), m.getName()), !constructor);
}
@Override
diff --git a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java
index 29c98d0..06a9632 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java
@@ -152,7 +152,7 @@
boolean isAccessible(final Member m) {
final Class<?> declaring = m.getDeclaringClass();
// (declaring == clazz) is just an optimization - we're calling this only from code that operates on a
- // non-restriced class, so if the declaring class is identical to the class being inspected, then forego
+ // non-restricted class, so if the declaring class is identical to the class being inspected, then forego
// a potentially expensive restricted-package check.
return declaring == clazz || !CheckRestrictedPackage.isRestrictedClass(declaring);
}
diff --git a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
index 83156e3..a856f00 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
@@ -86,7 +86,9 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.text.Collator;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -242,6 +244,35 @@
return methods.getFirst().isConstructor();
}
+ @Override
+ public String toString() {
+ // First gather the names and sort them. This makes it consistent and easier to read.
+ final List<String> names = new ArrayList<>(methods.size());
+ int len = 0;
+ for (final SingleDynamicMethod m: methods) {
+ final String name = m.getName();
+ len += name.length();
+ names.add(name);
+ }
+ // Case insensitive sorting, so e.g. "Object" doesn't come before "boolean".
+ final Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.SECONDARY);
+ Collections.sort(names, collator);
+
+ final String className = getClass().getName();
+ // Class name length + length of signatures + 2 chars/per signature for indentation and newline +
+ // 3 for brackets and initial newline
+ final int totalLength = className.length() + len + 2 * names.size() + 3;
+ final StringBuilder b = new StringBuilder(totalLength);
+ b.append('[').append(className).append('\n');
+ for(final String name: names) {
+ b.append(' ').append(name).append('\n');
+ }
+ b.append(']');
+ assert b.length() == totalLength;
+ return b.toString();
+ };
+
ClassLoader getClassLoader() {
return classLoader;
}
diff --git a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
index f4a8b0a..3e57337 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
@@ -122,13 +122,13 @@
* @param constructor does this represent a constructor?
*/
SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
- super(getName(target, clazz, name));
+ super(getName(target, clazz, name, constructor));
this.target = target;
this.constructor = constructor;
}
- private static String getName(final MethodHandle target, final Class<?> clazz, final String name) {
- return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
+ private static String getName(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
+ return getMethodNameWithSignature(target.type(), constructor ? name : getClassAndMethodName(clazz, name), !constructor);
}
@Override
diff --git a/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java b/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
index 9e0758c..bf40d60 100644
--- a/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
+++ b/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
@@ -98,7 +98,6 @@
* target method to a call site type (including mapping variable arity methods to a call site signature with different
* arity).
* @author Attila Szegedi
- * @version $Id: $
*/
abstract class SingleDynamicMethod extends DynamicMethod {
@@ -143,14 +142,18 @@
return getMethodType().parameterList().equals(method.getMethodType().parameterList());
}
- static String getMethodNameWithSignature(final MethodType type, final String methodName) {
+ static String getMethodNameWithSignature(final MethodType type, final String methodName, final boolean withReturnType) {
final String typeStr = type.toString();
final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
int secondParamIndex = typeStr.indexOf(',') + 1;
if(secondParamIndex == 0) {
secondParamIndex = retTypeIndex - 1;
}
- return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
+ final StringBuilder b = new StringBuilder();
+ if (withReturnType) {
+ b.append(typeStr, retTypeIndex, typeStr.length()).append(' ');
+ }
+ return b.append(methodName).append('(').append(typeStr, secondParamIndex, retTypeIndex).toString();
}
/**
diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java
index c5357ac..adf34a0 100644
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java
@@ -353,7 +353,7 @@
/**
* Applies argument filters to both the invocation and the guard (if there is one).
- * @param pos the position of the first argumen being filtered
+ * @param pos the position of the first argument being filtered
* @param filters the argument filters
* @return a filtered invocation
*/
diff --git a/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java b/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java
index 88357ff..b070ed6 100644
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java
@@ -110,7 +110,7 @@
/**
* Check if invocation is cacheable
- * @return true if cachable, false otherwise
+ * @return true if cacheable, false otherwise
*/
public boolean isCacheable() {
return cacheable;
diff --git a/nashorn/src/jdk/nashorn/api/scripting/AbstractJSObject.java b/nashorn/src/jdk/nashorn/api/scripting/AbstractJSObject.java
index 9a2a39c..680198d 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/AbstractJSObject.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/AbstractJSObject.java
@@ -182,7 +182,7 @@
/**
* Checking whether the given object is an instance of 'this' object.
*
- * @param instance instace to check
+ * @param instance instance to check
* @return true if the given 'instance' is an instance of this 'function' object
*/
@Override
diff --git a/nashorn/src/jdk/nashorn/api/scripting/JSObject.java b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java
index f1659b3..3c4484a 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/JSObject.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/JSObject.java
@@ -141,7 +141,7 @@
/**
* Checking whether the given object is an instance of 'this' object.
*
- * @param instance instace to check
+ * @param instance instance to check
* @return true if the given 'instance' is an instance of this 'function' object
*/
public boolean isInstance(final Object instance);
diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java
index 004c1c0..1509a7d 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornException.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornException.java
@@ -51,6 +51,8 @@
private String fileName;
// script line number
private int line;
+ // are the line and fileName unknown?
+ private boolean lineAndFileNameUnknown;
// script column number
private int column;
// underlying ECMA error object - lazily initialized
@@ -92,27 +94,10 @@
*/
protected NashornException(final String msg, final Throwable cause) {
super(msg, cause == null ? null : cause);
- // This is not so pretty - but it gets the job done. Note that the stack
- // trace has been already filled by "fillInStackTrace" call from
- // Throwable
- // constructor and so we don't pay additional cost for it.
-
// Hard luck - no column number info
this.column = -1;
-
- // Find the first JavaScript frame by walking and set file, line from it
- // Usually, we should be able to find it in just few frames depth.
- for (final StackTraceElement ste : getStackTrace()) {
- if (ECMAErrors.isScriptFrame(ste)) {
- // Whatever here is compiled from JavaScript code
- this.fileName = ste.getFileName();
- this.line = ste.getLineNumber();
- return;
- }
- }
-
- this.fileName = null;
- this.line = 0;
+ // We can retrieve the line number and file name from the stack trace if needed
+ this.lineAndFileNameUnknown = true;
}
/**
@@ -121,6 +106,7 @@
* @return the file name
*/
public final String getFileName() {
+ ensureLineAndFileName();
return fileName;
}
@@ -131,6 +117,7 @@
*/
public final void setFileName(final String fileName) {
this.fileName = fileName;
+ lineAndFileNameUnknown = false;
}
/**
@@ -139,6 +126,7 @@
* @return the line number
*/
public final int getLineNumber() {
+ ensureLineAndFileName();
return line;
}
@@ -148,6 +136,7 @@
* @param line the line number
*/
public final void setLineNumber(final int line) {
+ lineAndFileNameUnknown = false;
this.line = line;
}
@@ -274,4 +263,19 @@
public void setEcmaError(final Object ecmaError) {
this.ecmaError = ecmaError;
}
+
+ private void ensureLineAndFileName() {
+ if (lineAndFileNameUnknown) {
+ for (final StackTraceElement ste : getStackTrace()) {
+ if (ECMAErrors.isScriptFrame(ste)) {
+ // Whatever here is compiled from JavaScript code
+ fileName = ste.getFileName();
+ line = ste.getLineNumber();
+ return;
+ }
+ }
+
+ lineAndFileNameUnknown = false;
+ }
+ }
}
diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
index 1d47dac..0f2f3d7 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java
@@ -140,7 +140,7 @@
this._global_per_engine = nashornContext.getEnv()._global_per_engine;
// create new global object
- this.global = createNashornGlobal(context);
+ this.global = createNashornGlobal();
// set the default ENGINE_SCOPE object for the default context
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
}
@@ -167,7 +167,7 @@
// We use same 'global' for all Bindings.
return new SimpleBindings();
}
- return createGlobalMirror(null);
+ return createGlobalMirror();
}
// Compilable methods
@@ -317,7 +317,7 @@
// We didn't find associated nashorn global mirror in the Bindings given!
// Create new global instance mirror and associate with the Bindings.
- final ScriptObjectMirror mirror = createGlobalMirror(ctxt);
+ final ScriptObjectMirror mirror = createGlobalMirror();
bindings.put(NASHORN_GLOBAL, mirror);
return mirror.getHomeGlobal();
}
@@ -333,13 +333,13 @@
}
// Create a new ScriptObjectMirror wrapping a newly created Nashorn Global object
- private ScriptObjectMirror createGlobalMirror(final ScriptContext ctxt) {
- final Global newGlobal = createNashornGlobal(ctxt);
+ private ScriptObjectMirror createGlobalMirror() {
+ final Global newGlobal = createNashornGlobal();
return new ScriptObjectMirror(newGlobal, newGlobal);
}
// Create a new Nashorn Global object
- private Global createNashornGlobal(final ScriptContext ctxt) {
+ private Global createNashornGlobal() {
final Global newGlobal = AccessController.doPrivileged(new PrivilegedAction<Global>() {
@Override
public Global run() {
@@ -354,7 +354,7 @@
}
}, CREATE_GLOBAL_ACC_CTXT);
- nashornContext.initGlobal(newGlobal, this, ctxt);
+ nashornContext.initGlobal(newGlobal, this);
return newGlobal;
}
diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptUtils.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptUtils.java
index ab7a20b..0d5d676 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/ScriptUtils.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptUtils.java
@@ -79,7 +79,7 @@
* @return a synchronizing wrapper function
*/
public static Object makeSynchronizedFunction(final ScriptFunction func, final Object sync) {
- return func.makeSynchronizedFunction(unwrap(sync));
+ return func.createSynchronized(unwrap(sync));
}
/**
diff --git a/nashorn/src/jdk/nashorn/api/scripting/URLReader.java b/nashorn/src/jdk/nashorn/api/scripting/URLReader.java
index 4e42753a..85a585c 100644
--- a/nashorn/src/jdk/nashorn/api/scripting/URLReader.java
+++ b/nashorn/src/jdk/nashorn/api/scripting/URLReader.java
@@ -103,7 +103,7 @@
/**
* Charset used by this reader
*
- * @return the Chartset used to convert bytes to chars
+ * @return the Charset used to convert bytes to chars
*/
public Charset getCharset() {
return cs;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java b/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java
index 62e58f4..51abacd 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ApplySpecialization.java
@@ -40,11 +40,9 @@
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -82,7 +80,7 @@
*/
@Logger(name="apply2call")
-public final class ApplySpecialization extends NodeVisitor<LexicalContext> implements Loggable {
+public final class ApplySpecialization extends SimpleNodeVisitor implements Loggable {
private static final boolean USE_APPLY2CALL = Options.getBooleanProperty("nashorn.apply2call", true);
@@ -106,7 +104,6 @@
* @param compiler compiler
*/
public ApplySpecialization(final Compiler compiler) {
- super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
}
@@ -139,7 +136,7 @@
private boolean hasApplies(final FunctionNode functionNode) {
try {
- functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ functionNode.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode fn) {
return fn == functionNode;
@@ -173,7 +170,7 @@
final Deque<Set<Expression>> stack = new ArrayDeque<>();
//ensure that arguments is only passed as arg to apply
- functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ functionNode.accept(new SimpleNodeVisitor() {
private boolean isCurrentArg(final Expression expr) {
return !stack.isEmpty() && stack.peek().contains(expr); //args to current apply call
@@ -283,17 +280,13 @@
start++;
}
- start++; //we always uses this
+ start++; // we always use this
- final List<IdentNode> params = functionNode.getParameters();
+ assert functionNode.getNumOfParams() == 0 : "apply2call on function with named paramaters!";
final List<IdentNode> newParams = new ArrayList<>();
- final long to = Math.max(params.size(), actualCallSiteType.parameterCount() - start);
+ final long to = actualCallSiteType.parameterCount() - start;
for (int i = 0; i < to; i++) {
- if (i >= params.size()) {
- newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
- } else {
- newParams.add(params.get(i));
- }
+ newParams.add(new IdentNode(functionNode.getToken(), functionNode.getFinish(), EXPLODED_ARGUMENT_PREFIX.symbolName() + (i)));
}
callSiteTypes.push(actualCallSiteType);
@@ -302,7 +295,28 @@
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
- if (!USE_APPLY2CALL) {
+ // Cheap tests first
+ if (!(
+ // is the transform globally enabled?
+ USE_APPLY2CALL
+
+ // Are we compiling lazily? We can't known the number and types of the actual parameters at
+ // the caller when compiling eagerly, so this only works with on-demand compilation.
+ && compiler.isOnDemandCompilation()
+
+ // Does the function even reference the "arguments" identifier (without redefining it)? If not,
+ // it trivially can't have an expression of form "f.apply(self, arguments)" that this transform
+ // is targeting.
+ && functionNode.needsArguments()
+
+ // Does the function have eval? If so, it can arbitrarily modify arguments so we can't touch it.
+ && !functionNode.hasEval()
+
+ // Finally, does the function declare any parameters explicitly? We don't support that. It could
+ // be done, but has some complications. Therefore only a function with no explicit parameters
+ // is considered.
+ && functionNode.getNumOfParams() == 0))
+ {
return false;
}
@@ -312,14 +326,6 @@
return false;
}
- if (!compiler.isOnDemandCompilation()) {
- return false;
- }
-
- if (functionNode.hasEval()) {
- return false;
- }
-
if (!hasApplies(functionNode)) {
return false;
}
@@ -375,7 +381,7 @@
callSiteTypes.pop();
explodedArguments.pop();
- return newFunctionNode.setState(lc, CompilationState.BUILTINS_TRANSFORMED);
+ return newFunctionNode;
}
private static boolean isApply(final CallNode callNode) {
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java b/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
index ebdf3b7..73ded48 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -65,17 +65,14 @@
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
@@ -83,7 +80,7 @@
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ECMAErrors;
@@ -104,7 +101,7 @@
* visitor.
*/
@Logger(name="symbols")
-final class AssignSymbols extends NodeVisitor<LexicalContext> implements Loggable {
+final class AssignSymbols extends SimpleNodeVisitor implements Loggable {
private final DebugLogger log;
private final boolean debug;
@@ -149,12 +146,13 @@
private final Deque<Set<String>> thisProperties = new ArrayDeque<>();
private final Map<String, Symbol> globalSymbols = new HashMap<>(); //reuse the same global symbol
private final Compiler compiler;
+ private final boolean isOnDemand;
public AssignSymbols(final Compiler compiler) {
- super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
this.debug = log.isEnabled();
+ this.isOnDemand = compiler.isOnDemandCompilation();
}
@Override
@@ -187,7 +185,7 @@
*/
private void acceptDeclarations(final FunctionNode functionNode, final Block body) {
// This visitor will assign symbol to all declared variables.
- body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ body.accept(new SimpleNodeVisitor() {
@Override
protected boolean enterDefault(final Node node) {
// Don't bother visiting expressions; var is a statement, it can't be inside an expression.
@@ -242,7 +240,7 @@
/**
* Creates a synthetic initializer for a variable (a var statement that doesn't occur in the source code). Typically
- * used to create assignmnent of {@code :callee} to the function name symbol in self-referential function
+ * used to create assignment of {@code :callee} to the function name symbol in self-referential function
* expressions as well as for assignment of {@code :arguments} to {@code arguments}.
*
* @param name the ident node identifying the variable to initialize
@@ -390,7 +388,7 @@
// Create and add to appropriate block.
symbol = createSymbol(name, flags);
- symbolBlock.putSymbol(lc, symbol);
+ symbolBlock.putSymbol(symbol);
if ((flags & IS_SCOPE) == 0) {
// Initial assumption; symbol can lose its slot later
@@ -440,7 +438,7 @@
start(block);
if (lc.isFunctionBody()) {
- block.clearSymbols();
+ assert !block.hasSymbols();
final FunctionNode fn = lc.getCurrentFunction();
if (isUnparsedFunction(fn)) {
// It's a skipped nested function. Just mark the symbols being used by it as being in use.
@@ -459,7 +457,7 @@
}
private boolean isUnparsedFunction(final FunctionNode fn) {
- return compiler.isOnDemandCompilation() && fn != lc.getOutermostFunction();
+ return isOnDemand && fn != lc.getOutermostFunction();
}
@Override
@@ -551,9 +549,7 @@
private void defineVarIdent(final VarNode varNode) {
final IdentNode ident = varNode.getName();
final int flags;
- if (varNode.isAnonymousFunctionDeclaration()) {
- flags = IS_INTERNAL;
- } else if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
+ if (!varNode.isBlockScoped() && lc.getCurrentFunction().isProgram()) {
flags = IS_SCOPE;
} else {
flags = 0;
@@ -749,28 +745,6 @@
}
}
- @Override
- public Node leaveBlock(final Block block) {
- // It's not necessary to guard the marking of symbols as locals with this "if" condition for
- // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
- // is not an on-demand optimistic compilation, so we can skip locals marking then.
- if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
- // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
- // compilation, and we're skipping parsing the function bodies for nested functions, this
- // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
- // symbol in the outer function named the same as one of the parameters, though.
- if (lc.getFunction(block) == lc.getOutermostFunction()) {
- for (final Symbol symbol: block.getSymbols()) {
- if (!symbol.isScope()) {
- assert symbol.isVar() || symbol.isParam();
- compiler.declareLocalSymbol(symbol.getName());
- }
- }
- }
- }
- return block;
- }
-
private Node leaveDELETE(final UnaryNode unaryNode) {
final FunctionNode currentFunctionNode = lc.getCurrentFunction();
final boolean strictMode = currentFunctionNode.isStrict();
@@ -785,12 +759,13 @@
// If this is a declared variable or a function parameter, delete always fails (except for globals).
final String name = ident.getName();
final Symbol symbol = ident.getSymbol();
- final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
- if (failDelete && symbol.isThis()) {
- return LiteralNode.newInstance(unaryNode, true).accept(this);
+ if (symbol.isThis()) {
+ // Can't delete "this", ignore and return true
+ return LiteralNode.newInstance(unaryNode, true);
}
- final Expression literalNode = (Expression)LiteralNode.newInstance(unaryNode, name).accept(this);
+ final Expression literalNode = LiteralNode.newInstance(unaryNode, name);
+ final boolean failDelete = strictMode || (!symbol.isScope() && (symbol.isParam() || (symbol.isVar() && !symbol.isProgramLevel())));
if (!failDelete) {
args.add(compilerConstantIdentifier(SCOPE));
@@ -800,13 +775,15 @@
if (failDelete) {
request = Request.FAIL_DELETE;
+ } else if ((symbol.isGlobal() && !symbol.isFunctionDeclaration()) || symbol.isProgramLevel()) {
+ request = Request.SLOW_DELETE;
}
} else if (rhs instanceof AccessNode) {
final Expression base = ((AccessNode)rhs).getBase();
final String property = ((AccessNode)rhs).getProperty();
args.add(base);
- args.add((Expression)LiteralNode.newInstance(unaryNode, property).accept(this));
+ args.add(LiteralNode.newInstance(unaryNode, property));
args.add(strictFlagNode);
} else if (rhs instanceof IndexNode) {
@@ -819,15 +796,15 @@
args.add(strictFlagNode);
} else {
- return LiteralNode.newInstance(unaryNode, true).accept(this);
+ return LiteralNode.newInstance(unaryNode, true);
}
- return new RuntimeNode(unaryNode, request, args).accept(this);
+ return new RuntimeNode(unaryNode, request, args);
}
@Override
public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
- forNode.setIterator(newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
+ return forNode.setIterator(lc, newObjectInternal(ITERATOR_PREFIX)); //NASHORN-73
}
return end(forNode);
@@ -847,7 +824,7 @@
lc.applyTopFlags(functionNode))))
.setThisProperties(lc, thisProperties.pop().size()));
}
- return finalizedFunction.setState(lc, CompilationState.SYMBOLS_ASSIGNED);
+ return finalizedFunction;
}
@Override
@@ -903,19 +880,18 @@
public Node leaveSwitchNode(final SwitchNode switchNode) {
// We only need a symbol for the tag if it's not an integer switch node
if(!switchNode.isUniqueInteger()) {
- switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX));
+ return switchNode.setTag(lc, newObjectInternal(SWITCH_TAG_PREFIX));
}
return switchNode;
}
@Override
public Node leaveTryNode(final TryNode tryNode) {
- tryNode.setException(exceptionSymbol());
assert tryNode.getFinallyBody() == null;
end(tryNode);
- return tryNode;
+ return tryNode.setException(lc, exceptionSymbol());
}
private Node leaveTYPEOF(final UnaryNode unaryNode) {
@@ -924,13 +900,13 @@
final List<Expression> args = new ArrayList<>();
if (rhs instanceof IdentNode && !isParamOrVar((IdentNode)rhs)) {
args.add(compilerConstantIdentifier(SCOPE));
- args.add((Expression)LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null
+ args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName())); //null
} else {
args.add(rhs);
- args.add((Expression)LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
+ args.add(LiteralNode.newInstance(unaryNode)); //null, do not reuse token of identifier rhs, it can be e.g. 'this'
}
- final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args).accept(this);
+ final Node runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
end(unaryNode);
@@ -938,7 +914,7 @@
}
private FunctionNode markProgramBlock(final FunctionNode functionNode) {
- if (compiler.isOnDemandCompilation() || !functionNode.isProgram()) {
+ if (isOnDemand || !functionNode.isProgram()) {
return functionNode;
}
@@ -1005,7 +981,7 @@
boolean previousWasBlock = false;
for (final Iterator<LexicalContextNode> it = lc.getAllNodes(); it.hasNext();) {
final LexicalContextNode node = it.next();
- if (node instanceof FunctionNode || isSplitArray(node)) {
+ if (node instanceof FunctionNode || isSplitLiteral(node)) {
// We reached the function boundary or a splitting boundary without seeing a definition for the symbol.
// It needs to be in scope.
return true;
@@ -1031,12 +1007,8 @@
throw new AssertionError();
}
- private static boolean isSplitArray(final LexicalContextNode expr) {
- if(!(expr instanceof ArrayLiteralNode)) {
- return false;
- }
- final List<ArrayUnit> units = ((ArrayLiteralNode)expr).getUnits();
- return !(units == null || units.isEmpty());
+ private static boolean isSplitLiteral(final LexicalContextNode expr) {
+ return expr instanceof Splittable && ((Splittable) expr).getSplitRanges() != null;
}
private void throwUnprotectedSwitchError(final VarNode varNode) {
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CacheAst.java b/nashorn/src/jdk/nashorn/internal/codegen/CacheAst.java
new file mode 100644
index 0000000..6f66ea3
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CacheAst.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.codegen;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Statement;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
+import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
+
+class CacheAst extends SimpleNodeVisitor {
+ private final Deque<RecompilableScriptFunctionData> dataStack = new ArrayDeque<>();
+
+ private final Compiler compiler;
+
+ CacheAst(final Compiler compiler) {
+ this.compiler = compiler;
+ assert !compiler.isOnDemandCompilation();
+ }
+
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ final int id = functionNode.getId();
+ // It isn't necessary to keep a stack of RecompilableScriptFunctionData, but then we'd need to do a
+ // potentially transitive lookup with compiler.getScriptFunctionData(id) for deeper functions; this way
+ // we keep it constant time.
+ dataStack.push(dataStack.isEmpty() ? compiler.getScriptFunctionData(id) : dataStack.peek().getScriptFunctionData(id));
+ return true;
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ final RecompilableScriptFunctionData data = dataStack.pop();
+ if (functionNode.isSplit()) {
+ // NOTE: cache only split function ASTs from eager pass. Caching non-split functions would require
+ // some additional work, namely creating the concept of "uncacheable" function and reworking
+ // ApplySpecialization to ensure that functions undergoing apply-to-call transformations are not
+ // cacheable as well as recomputing Symbol.useCount when caching the eagerly parsed AST.
+ // Recomputing Symbol.useCount would be needed so it will only reflect uses from within the
+ // function being cached (and not reflect uses from its own nested functions or functions it is
+ // nested in). This is consistent with the count an on-demand recompilation of the function would
+ // produce. This is important as the decision to emit shared scope calls is based on this count,
+ // and if it is not matched between a previous version of the code and its deoptimizing rest-of
+ // compilation, it can result in rest-of not emitting a shared scope call where a previous version
+ // of the code (compiled from a cached eager pre-pass seeing higher (global) useCount) would emit
+ // it, causing a mismatch in stack shapes between previous code and its rest-of.
+ data.setCachedAst(functionNode);
+ }
+
+ if (!dataStack.isEmpty() && ((dataStack.peek().getFunctionFlags() & FunctionNode.IS_SPLIT) != 0)) {
+ // Return a function node with no body so that caching outer functions doesn't hold on to nested
+ // functions' bodies. Note we're doing this only for functions directly nested inside split
+ // functions, since we're only caching the split ones. It is not necessary to limit body removal
+ // to just these functions, but it's a cheap way to prevent unnecessary AST mutations.
+ return functionNode.setBody(lc, functionNode.getBody().setStatements(null, Collections.<Statement>emptyList()));
+ }
+ return functionNode;
+ }
+}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index b9ad1e9..1f6aaad 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -93,7 +93,6 @@
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.GetSplitState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
@@ -106,7 +105,6 @@
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.LoopNode;
@@ -119,6 +117,7 @@
import jdk.nashorn.internal.ir.RuntimeNode.Request;
import jdk.nashorn.internal.ir.SetSplitState;
import jdk.nashorn.internal.ir.SplitReturn;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.Symbol;
@@ -130,9 +129,8 @@
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.objects.Global;
-import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.parser.Lexer.RegexToken;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
@@ -195,9 +193,9 @@
private static final Call ENSURE_NUMBER = CompilerConstants.staticCallNoLookup(OptimisticReturnFilters.class,
"ensureNumber", double.class, Object.class, int.class);
- private static final Call CREATE_FUNCTION_OBJECT = CompilerConstants.staticCallNoLookup(ScriptFunctionImpl.class,
+ private static final Call CREATE_FUNCTION_OBJECT = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
"create", ScriptFunction.class, Object[].class, int.class, ScriptObject.class);
- private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunctionImpl.class,
+ private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunction.class,
"create", ScriptFunction.class, Object[].class, int.class);
private static final Call TO_NUMBER_FOR_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
@@ -244,12 +242,12 @@
private final DebugLogger log;
/** From what size should we use spill instead of fields for JavaScript objects? */
- private static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
+ static final int OBJECT_SPILL_THRESHOLD = Options.getIntProperty("nashorn.spill.threshold", 256);
private final Set<String> emittedMethods = new HashSet<>();
// Function Id -> ContinuationInfo. Used by compilation of rest-of function only.
- private final Map<Integer, ContinuationInfo> fnIdToContinuationInfo = new HashMap<>();
+ private ContinuationInfo continuationInfo;
private final Deque<Label> scopeEntryLabels = new ArrayDeque<>();
@@ -349,11 +347,20 @@
final int flags = getScopeCallSiteFlags(symbol);
if (isFastScope(symbol)) {
// Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
- if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD && !isOptimisticOrRestOf()) {
- method.loadCompilerConstant(SCOPE);
- // As shared scope vars are only used in non-optimistic compilation, we switch from using TypeBounds to
+ if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD && !identNode.isOptimistic()) {
+ // As shared scope vars are only used with non-optimistic identifiers, we switch from using TypeBounds to
// just a single definitive type, resultBounds.widest.
- loadSharedScopeVar(resultBounds.widest, symbol, flags);
+ new OptimisticOperation(identNode, TypeBounds.OBJECT) {
+ @Override
+ void loadStack() {
+ method.loadCompilerConstant(SCOPE);
+ }
+
+ @Override
+ void consumeStack() {
+ loadSharedScopeVar(resultBounds.widest, symbol, flags);
+ }
+ }.emit();
} else {
new LoadFastScopeVar(identNode, resultBounds, flags).emit();
}
@@ -384,10 +391,6 @@
return continuationEntryPoints != null;
}
- private boolean isOptimisticOrRestOf() {
- return useOptimisticTypes() || isRestOf();
- }
-
private boolean isCurrentContinuationEntryPoint(final int programPoint) {
return isRestOf() && getCurrentContinuationEntryPoint() == programPoint;
}
@@ -464,12 +467,8 @@
}
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
- assert !isOptimisticOrRestOf();
- if (isFastScope(symbol)) {
- method.load(getScopeProtoDepth(lc.getCurrentBlock(), symbol));
- } else {
- method.load(-1);
- }
+ assert isFastScope(symbol);
+ method.load(getScopeProtoDepth(lc.getCurrentBlock(), symbol));
return lc.getScopeGet(unit, symbol, valueType, flags).generateInvoke(method);
}
@@ -1434,8 +1433,7 @@
final Block currentBlock = lc.getCurrentBlock();
final CodeGeneratorLexicalContext codegenLexicalContext = lc;
- function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
-
+ function.accept(new SimpleNodeVisitor() {
private MethodEmitter sharedScopeCall(final IdentNode identNode, final int flags) {
final Symbol symbol = identNode.getSymbol();
final boolean isFastScope = isFastScope(symbol);
@@ -1480,7 +1478,7 @@
}
@Override
void consumeStack() {
- dynamicCall(2 + argsCount, flags);
+ dynamicCall(2 + argsCount, flags, ident.getName());
}
}.emit();
}
@@ -1494,7 +1492,7 @@
int argsCount;
@Override
void loadStack() {
- /**
+ /*
* We want to load 'eval' to check if it is indeed global builtin eval.
* If this eval call is inside a 'with' statement, dyn:getMethod|getProp|getElem
* would be generated if ident is a "isFunction". But, that would result in a
@@ -1538,7 +1536,7 @@
@Override
void consumeStack() {
// Ordinary call
- dynamicCall(2 + argsCount, flags);
+ dynamicCall(2 + argsCount, flags, "eval");
method._goto(eval_done);
method.label(invoke_direct_eval);
@@ -1573,7 +1571,7 @@
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
|| !isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD
|| CodeGenerator.this.lc.inDynamicScope()
- || isOptimisticOrRestOf()) {
+ || callNode.isOptimistic()) {
scopeCall(node, flags);
} else {
sharedScopeCall(node, flags);
@@ -1610,7 +1608,7 @@
}
@Override
void consumeStack() {
- dynamicCall(2 + argCount, flags);
+ dynamicCall(2 + argCount, flags, node.toString(false));
}
}.emit();
@@ -1635,9 +1633,7 @@
@Override
void consumeStack() {
- final int flags = getCallSiteFlags();
- //assert callNodeType.equals(callee.getReturnType()) : callNodeType + " != " + callee.getReturnType();
- dynamicCall(2 + argsCount, flags);
+ dynamicCall(2 + argsCount, getCallSiteFlags(), null);
}
}.emit();
return false;
@@ -1666,8 +1662,7 @@
}
@Override
void consumeStack() {
- final int flags = getCallSiteFlags();
- dynamicCall(2 + argsCount, flags);
+ dynamicCall(2 + argsCount, getCallSiteFlags(), node.toString(false));
}
}.emit();
return false;
@@ -1687,7 +1682,7 @@
@Override
void consumeStack() {
final int flags = getCallSiteFlags() | CALLSITE_SCOPE;
- dynamicCall(2 + argsCount, flags);
+ dynamicCall(2 + argsCount, flags, node.toString(false));
}
}.emit();
return false;
@@ -2073,8 +2068,6 @@
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
- final int fnId = functionNode.getId();
-
if (skipFunction(functionNode)) {
// In case we are not generating code for the function, we must create or retrieve the function object and
// load it on the stack here.
@@ -2112,9 +2105,9 @@
method.begin();
if (isRestOf()) {
- final ContinuationInfo ci = new ContinuationInfo();
- fnIdToContinuationInfo.put(fnId, ci);
- method.gotoLoopStart(ci.getHandlerLabel());
+ assert continuationInfo == null;
+ continuationInfo = new ContinuationInfo();
+ method.gotoLoopStart(continuationInfo.getHandlerLabel());
}
}
@@ -2147,7 +2140,7 @@
markOptimistic = false;
}
- FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.BYTECODE_GENERATED);
+ FunctionNode newFunctionNode = functionNode;
if (markOptimistic) {
newFunctionNode = newFunctionNode.setFlag(lc, FunctionNode.IS_DEOPTIMIZABLE);
}
@@ -2240,73 +2233,33 @@
*
* @param arrayLiteralNode the array of contents
* @param arrayType the type of the array, e.g. ARRAY_NUMBER or ARRAY_OBJECT
- *
- * @return the method generator that was used
*/
- private MethodEmitter loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
+ private void loadArray(final ArrayLiteralNode arrayLiteralNode, final ArrayType arrayType) {
assert arrayType == Type.INT_ARRAY || arrayType == Type.LONG_ARRAY || arrayType == Type.NUMBER_ARRAY || arrayType == Type.OBJECT_ARRAY;
- final Expression[] nodes = arrayLiteralNode.getValue();
- final Object presets = arrayLiteralNode.getPresets();
- final int[] postsets = arrayLiteralNode.getPostsets();
- final Class<?> type = arrayType.getTypeClass();
- final List<ArrayUnit> units = arrayLiteralNode.getUnits();
+ final Expression[] nodes = arrayLiteralNode.getValue();
+ final Object presets = arrayLiteralNode.getPresets();
+ final int[] postsets = arrayLiteralNode.getPostsets();
+ final List<Splittable.SplitRange> ranges = arrayLiteralNode.getSplitRanges();
loadConstant(presets);
final Type elementType = arrayType.getElementType();
- if (units != null) {
- final MethodEmitter savedMethod = method;
- final FunctionNode currentFunction = lc.getCurrentFunction();
+ if (ranges != null) {
- for (final ArrayUnit arrayUnit : units) {
- unit = lc.pushCompileUnit(arrayUnit.getCompileUnit());
-
- final String className = unit.getUnitClassName();
- assert unit != null;
- final String name = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
- final String signature = methodDescriptor(type, ScriptFunction.class, Object.class, ScriptObject.class, type);
-
- pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
-
- method.setFunctionNode(currentFunction);
- method.begin();
-
- defineCommonSplitMethodParameters();
- defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), arrayType);
-
- // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
- // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
- final int arraySlot = fixScopeSlot(currentFunction, 3);
-
- lc.enterSplitNode();
-
- for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) {
- method.load(arrayType, arraySlot);
- storeElement(nodes, elementType, postsets[i]);
+ loadSplitLiteral(new SplitLiteralCreator() {
+ @Override
+ public void populateRange(final MethodEmitter method, final Type type, final int slot, final int start, final int end) {
+ for (int i = start; i < end; i++) {
+ method.load(type, slot);
+ storeElement(nodes, elementType, postsets[i]);
+ }
+ method.load(type, slot);
}
+ }, ranges, arrayType);
- method.load(arrayType, arraySlot);
- method._return();
- lc.exitSplitNode();
- method.end();
- lc.releaseSlots();
- popMethodEmitter();
-
- assert method == savedMethod;
- method.loadCompilerConstant(CALLEE);
- method.swap();
- method.loadCompilerConstant(THIS);
- method.swap();
- method.loadCompilerConstant(SCOPE);
- method.swap();
- method.invokestatic(className, name, signature);
-
- unit = lc.popCompileUnit(unit);
- }
-
- return method;
+ return;
}
if(postsets.length > 0) {
@@ -2318,7 +2271,6 @@
}
method.load(arrayType, arraySlot);
}
- return method;
}
private void storeElement(final Expression[] nodes, final Type elementType, final int index) {
@@ -2508,7 +2460,7 @@
@Override
public Boolean get() {
- value.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ value.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
return false;
@@ -2543,6 +2495,7 @@
final List<MapTuple<Expression>> tuples = new ArrayList<>();
final List<PropertyNode> gettersSetters = new ArrayList<>();
final int ccp = getCurrentContinuationEntryPoint();
+ final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
Expression protoNode = null;
boolean restOfProperty = false;
@@ -2589,7 +2542,13 @@
loadExpressionAsType(node, type);
}};
}
- oc.makeObject(method);
+
+ if (ranges != null) {
+ oc.createObject(method);
+ loadSplitLiteral(oc, ranges, Type.typeFor(oc.getAllocatorClass()));
+ } else {
+ oc.makeObject(method);
+ }
//if this is a rest of method and our continuation point was found as one of the values
//in the properties above, we need to reset the map to oc.getMap() in the continuation
@@ -2839,7 +2798,7 @@
boolean contains;
@Override
public Boolean get() {
- rootExpr.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ rootExpr.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
return false;
@@ -2905,6 +2864,54 @@
method.onLocalStore(type, slot);
}
+ private void loadSplitLiteral(final SplitLiteralCreator creator, final List<Splittable.SplitRange> ranges, final Type literalType) {
+ assert ranges != null;
+
+ // final Type literalType = Type.typeFor(literalClass);
+ final MethodEmitter savedMethod = method;
+ final FunctionNode currentFunction = lc.getCurrentFunction();
+
+ for (final Splittable.SplitRange splitRange : ranges) {
+ unit = lc.pushCompileUnit(splitRange.getCompileUnit());
+
+ assert unit != null;
+ final String className = unit.getUnitClassName();
+ final String name = currentFunction.uniqueName(SPLIT_PREFIX.symbolName());
+ final Class<?> clazz = literalType.getTypeClass();
+ final String signature = methodDescriptor(clazz, ScriptFunction.class, Object.class, ScriptObject.class, clazz);
+
+ pushMethodEmitter(unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
+
+ method.setFunctionNode(currentFunction);
+ method.begin();
+
+ defineCommonSplitMethodParameters();
+ defineSplitMethodParameter(CompilerConstants.SPLIT_ARRAY_ARG.slot(), literalType);
+
+ // NOTE: when this is no longer needed, SplitIntoFunctions will no longer have to add IS_SPLIT
+ // to synthetic functions, and FunctionNode.needsCallee() will no longer need to test for isSplit().
+ final int literalSlot = fixScopeSlot(currentFunction, 3);
+
+ lc.enterSplitNode();
+
+ creator.populateRange(method, literalType, literalSlot, splitRange.getLow(), splitRange.getHigh());
+
+ method._return();
+ lc.exitSplitNode();
+ method.end();
+ lc.releaseSlots();
+ popMethodEmitter();
+
+ assert method == savedMethod;
+ method.loadCompilerConstant(CALLEE).swap();
+ method.loadCompilerConstant(THIS).swap();
+ method.loadCompilerConstant(SCOPE).swap();
+ method.invokestatic(className, name, signature);
+
+ unit = lc.popCompileUnit(unit);
+ }
+ }
+
private int fixScopeSlot(final FunctionNode functionNode, final int extraSlot) {
// TODO hack to move the scope to the expected slot (needed because split methods reuse the same slots as the root method)
final int actualScopeSlot = functionNode.compilerConstant(SCOPE).getSlot(SCOPE_TYPE);
@@ -3707,10 +3714,11 @@
final CallNode callNode = (CallNode)unaryNode.getExpression();
final List<Expression> args = callNode.getArgs();
+ final Expression func = callNode.getFunction();
// Load function reference.
- loadExpressionAsObject(callNode.getFunction()); // must detect type error
+ loadExpressionAsObject(func); // must detect type error
- method.dynamicNew(1 + loadArgs(args), getCallSiteFlags());
+ method.dynamicNew(1 + loadArgs(args), getCallSiteFlags(), func.toString(false));
}
private void loadNOT(final UnaryNode unaryNode) {
@@ -4333,12 +4341,12 @@
}
private void prologue() {
- /**
+ /*
* This loads the parts of the target, e.g base and index. they are kept
* on the stack throughout the store and used at the end to execute it
*/
- target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ target.accept(new SimpleNodeVisitor() {
@Override
public boolean enterIdentNode(final IdentNode node) {
if (node.getSymbol().isScope()) {
@@ -4437,7 +4445,7 @@
* need to do a conversion on non-equivalent types exists, but is
* very rare. See for example test/script/basic/access-specializer.js
*/
- target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ target.accept(new SimpleNodeVisitor() {
@Override
protected boolean enterDefault(final Node node) {
throw new AssertionError("Unexpected node " + node + " in store epilogue");
@@ -4801,7 +4809,7 @@
* conversion has no side effects.
* @param name the name of the property being get
* @param flags call site flags
- * @param isMethod whether we're preferrably retrieving a function
+ * @param isMethod whether we're preferably retrieving a function
* @return the current method emitter
*/
MethodEmitter dynamicGet(final String name, final int flags, final boolean isMethod, final boolean isIndex) {
@@ -4818,11 +4826,11 @@
return method.dynamicGetIndex(resultBounds.within(expression.getType()), nonOptimisticFlags(flags), isMethod);
}
- MethodEmitter dynamicCall(final int argCount, final int flags) {
+ MethodEmitter dynamicCall(final int argCount, final int flags, final String msg) {
if (isOptimistic) {
- return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags));
+ return method.dynamicCall(getOptimisticCoercedType(), argCount, getOptimisticFlags(flags), msg);
}
- return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags));
+ return method.dynamicCall(resultBounds.within(expression.getType()), argCount, nonOptimisticFlags(flags), msg);
}
int getOptimisticFlags(final int flags) {
@@ -5233,7 +5241,7 @@
private Type returnValueType;
// If we are in the middle of an object literal initialization, we need to update the map
private PropertyMap objectLiteralMap;
- // Object literal stack depth for object literal - not necessarly top if property is a tree
+ // Object literal stack depth for object literal - not necessarily top if property is a tree
private int objectLiteralStackDepth = -1;
// The line number at the continuation point
private int lineNumber;
@@ -5310,7 +5318,7 @@
}
private ContinuationInfo getContinuationInfo() {
- return fnIdToContinuationInfo.get(lc.getCurrentFunction().getId());
+ return continuationInfo;
}
private void generateContinuationHandler() {
@@ -5398,7 +5406,7 @@
method.load(lvarTypes.get(slot), slot);
method.convert(stackTypes[i]);
// stack: s0=object literal being initialized
- // change map of s0 so that the property we are initilizing when we failed
+ // change map of s0 so that the property we are initializing when we failed
// is now ci.returnValueType
if (i == objectLiteralStackDepth) {
method.dup();
@@ -5466,4 +5474,21 @@
method.uncheckedGoto(targetCatchLabel);
}
}
+
+ /**
+ * Interface implemented by object creators that support splitting over multiple methods.
+ */
+ interface SplitLiteralCreator {
+ /**
+ * Generate code to populate a range of the literal object. A reference to the object
+ * should be left on the stack when the method terminates.
+ *
+ * @param method the method emitter
+ * @param type the type of the literal object
+ * @param slot the local slot containing the literal object
+ * @param start the start index (inclusive)
+ * @param end the end index (exclusive)
+ */
+ void populateRange(MethodEmitter method, Type type, int slot, int start, int end);
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java
index 2d0491e..e0a6945 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java
@@ -25,37 +25,24 @@
package jdk.nashorn.internal.codegen;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BUILTINS_TRANSFORMED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_GENERATED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.BYTECODE_INSTALLED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.CONSTANT_FOLDED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.INITIALIZED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOCAL_VARIABLE_TYPES_CALCULATED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.LOWERED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.OPTIMISTIC_TYPES_ASSIGNED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.PARSED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SCOPE_DEPTHS_COMPUTED;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SPLIT;
-import static jdk.nashorn.internal.ir.FunctionNode.CompilationState.SYMBOLS_ASSIGNED;
import static jdk.nashorn.internal.runtime.logging.DebugLogger.quote;
import java.io.PrintWriter;
-import java.util.EnumSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
+import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.runtime.CodeInstaller;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -65,15 +52,9 @@
* A compilation phase is a step in the processes of turning a JavaScript
* FunctionNode into bytecode. It has an optional return value.
*/
-enum CompilationPhase {
- /**
- * Constant folding pass Simple constant folding that will make elementary
- * constructs go away
- */
- CONSTANT_FOLDING_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED)) {
+abstract class CompilationPhase {
+
+ private static final class ConstantFoldingPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
return transformFunction(fn, new FoldConstants(compiler));
@@ -83,20 +64,15 @@
public String toString() {
return "'Constant Folding'";
}
- },
+ }
/**
- * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
- * finally constructs and similar things. Establishes termination criteria
- * for nodes Guarantee return instructions to method making sure control
- * flow cannot fall off the end. Replacing high level nodes with lower such
- * as runtime nodes where applicable.
+ * Constant folding pass Simple constant folding that will make elementary
+ * constructs go away
*/
- LOWERING_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED)) {
+ static final CompilationPhase CONSTANT_FOLDING_PHASE = new ConstantFoldingPhase();
+
+ private static final class LoweringPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
return transformFunction(fn, new Lower(compiler));
@@ -106,42 +82,35 @@
public String toString() {
return "'Control Flow Lowering'";
}
- },
+ }
/**
- * Phase used only when doing optimistic code generation. It assigns all potentially
- * optimistic ops a program point so that an UnwarrantedException knows from where
- * a guess went wrong when creating the continuation to roll back this execution
+ * Lower (Control flow pass) Finalizes the control flow. Clones blocks for
+ * finally constructs and similar things. Establishes termination criteria
+ * for nodes Guarantee return instructions to method making sure control
+ * flow cannot fall off the end. Replacing high level nodes with lower such
+ * as runtime nodes where applicable.
*/
- TRANSFORM_BUILTINS_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED)) {
- //we only do this if we have a param type map, otherwise this is not a specialized recompile
+ static final CompilationPhase LOWERING_PHASE = new LoweringPhase();
+
+ private static final class ApplySpecializationPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
- return setStates(transformFunction(fn, new ApplySpecialization(compiler)), BUILTINS_TRANSFORMED);
+ return transformFunction(fn, new ApplySpecialization(compiler));
}
@Override
public String toString() {
return "'Builtin Replacement'";
}
- },
+ };
/**
- * Splitter Split the AST into several compile units based on a heuristic size calculation.
- * Split IR can lead to scope information being changed.
+ * Phase used to transform Function.prototype.apply.
*/
- SPLITTING_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED)) {
+ static final CompilationPhase APPLY_SPECIALIZATION_PHASE = new ApplySpecializationPhase();
+
+ private static final class SplittingPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final CompileUnit outermostCompileUnit = compiler.addCompileUnit(0L);
@@ -149,7 +118,7 @@
FunctionNode newFunctionNode;
//ensure elementTypes, postsets and presets exist for splitter and arraynodes
- newFunctionNode = transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ newFunctionNode = transformFunction(fn, new SimpleNodeVisitor() {
@Override
public LiteralNode<?> leaveLiteralNode(final LiteralNode<?> literalNode) {
return literalNode.initialize(lc);
@@ -168,16 +137,15 @@
public String toString() {
return "'Code Splitting'";
}
- },
+ };
- PROGRAM_POINT_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT)) {
+ /**
+ * Splitter Split the AST into several compile units based on a heuristic size calculation.
+ * Split IR can lead to scope information being changed.
+ */
+ static final CompilationPhase SPLITTING_PHASE = new SplittingPhase();
+
+ private static final class ProgramPointPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
return transformFunction(fn, new ProgramPoints());
@@ -187,43 +155,34 @@
public String toString() {
return "'Program Point Calculation'";
}
- },
+ };
- SERIALIZE_SPLIT_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT)) {
+ static final CompilationPhase PROGRAM_POINT_PHASE = new ProgramPointPhase();
+
+ private static final class CacheAstPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
- return transformFunction(fn, new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public boolean enterFunctionNode(final FunctionNode functionNode) {
- if (functionNode.isSplit()) {
- compiler.serializeAst(functionNode);
- }
- return true;
- }
- });
+ if (!compiler.isOnDemandCompilation()) {
+ // Only do this on initial preprocessing of the source code. For on-demand compilations from
+ // source, FindScopeDepths#leaveFunctionNode() calls data.setCachedAst() for the sole function
+ // being compiled.
+ transformFunction(fn, new CacheAst(compiler));
+ }
+ // NOTE: we're returning the original fn as we have destructively modified the cached functions by
+ // removing their bodies. This step is associating FunctionNode objects with
+ // RecompilableScriptFunctionData; it's not really modifying the AST.
+ return fn;
}
@Override
public String toString() {
- return "'Serialize Split Functions'";
+ return "'Cache ASTs'";
}
- },
+ };
- SYMBOL_ASSIGNMENT_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT)) {
+ static final CompilationPhase CACHE_AST_PHASE = new CacheAstPhase();
+
+ private static final class SymbolAssignmentPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
return transformFunction(fn, new AssignSymbols(compiler));
@@ -233,17 +192,11 @@
public String toString() {
return "'Symbol Assignment'";
}
- },
+ };
- SCOPE_DEPTH_COMPUTATION_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED)) {
+ static final CompilationPhase SYMBOL_ASSIGNMENT_PHASE = new SymbolAssignmentPhase();
+
+ private static final class ScopeDepthComputationPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
return transformFunction(fn, new FindScopeDepths(compiler));
@@ -253,43 +206,66 @@
public String toString() {
return "'Scope Depth Computation'";
}
- },
+ };
- OPTIMISTIC_TYPE_ASSIGNMENT_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED,
- SCOPE_DEPTHS_COMPUTED)) {
+ static final CompilationPhase SCOPE_DEPTH_COMPUTATION_PHASE = new ScopeDepthComputationPhase();
+
+ private static final class DeclareLocalSymbolsPhase extends CompilationPhase {
+ @Override
+ FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
+ // It's not necessary to guard the marking of symbols as locals with this "if" condition for
+ // correctness, it's just an optimization -- runtime type calculation is not used when the compilation
+ // is not an on-demand optimistic compilation, so we can skip locals marking then.
+ if (compiler.useOptimisticTypes() && compiler.isOnDemandCompilation()) {
+ fn.getBody().accept(new SimpleNodeVisitor() {
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ // OTOH, we must not declare symbols from nested functions to be locals. As we're doing on-demand
+ // compilation, and we're skipping parsing the function bodies for nested functions, this
+ // basically only means their parameters. It'd be enough to mistakenly declare to be a local a
+ // symbol in the outer function named the same as one of the parameters, though.
+ return false;
+ };
+ @Override
+ public boolean enterBlock(final Block block) {
+ for (final Symbol symbol: block.getSymbols()) {
+ if (!symbol.isScope()) {
+ compiler.declareLocalSymbol(symbol.getName());
+ }
+ }
+ return true;
+ };
+ });
+ }
+ return fn;
+ }
+
+ @Override
+ public String toString() {
+ return "'Local Symbols Declaration'";
+ }
+ };
+
+ static final CompilationPhase DECLARE_LOCAL_SYMBOLS_PHASE = new DeclareLocalSymbolsPhase();
+
+ private static final class OptimisticTypeAssignmentPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
if (compiler.useOptimisticTypes()) {
return transformFunction(fn, new OptimisticTypesCalculator(compiler));
}
- return setStates(fn, OPTIMISTIC_TYPES_ASSIGNED);
+ return fn;
}
@Override
public String toString() {
return "'Optimistic Type Assignment'";
}
- },
+ }
- LOCAL_VARIABLE_TYPE_CALCULATION_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED,
- SCOPE_DEPTHS_COMPUTED,
- OPTIMISTIC_TYPES_ASSIGNED)) {
+ static final CompilationPhase OPTIMISTIC_TYPE_ASSIGNMENT_PHASE = new OptimisticTypeAssignmentPhase();
+
+ private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
@@ -314,25 +290,11 @@
public String toString() {
return "'Local Variable Type Calculation'";
}
- },
+ };
+ static final CompilationPhase LOCAL_VARIABLE_TYPE_CALCULATION_PHASE = new LocalVariableTypeCalculationPhase();
- /**
- * Reuse compile units, if they are already present. We are using the same compiler
- * to recompile stuff
- */
- REUSE_COMPILE_UNITS_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED,
- SCOPE_DEPTHS_COMPUTED,
- OPTIMISTIC_TYPES_ASSIGNED,
- LOCAL_VARIABLE_TYPES_CALCULATED)) {
+ private static final class ReuseCompileUnitsPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
assert phases.isRestOfCompilation() : "reuse compile units currently only used for Rest-Of methods";
@@ -380,16 +342,15 @@
public String toString() {
return "'Reuse Compile Units'";
}
- },
+ }
- REINITIALIZE_SERIALIZED(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT)) {
+ /**
+ * Reuse compile units, if they are already present. We are using the same compiler
+ * to recompile stuff
+ */
+ static final CompilationPhase REUSE_COMPILE_UNITS_PHASE = new ReuseCompileUnitsPhase();
+
+ private static final class ReinitializeCachedPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final Set<CompileUnit> unitSet = CompileUnit.createCompileUnitSet();
@@ -430,28 +391,13 @@
@Override
public String toString() {
- return "'Deserialize'";
+ return "'Reinitialize cached'";
}
- },
+ }
- /**
- * Bytecode generation:
- *
- * Generate the byte code class(es) resulting from the compiled FunctionNode
- */
- BYTECODE_GENERATION_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED,
- SCOPE_DEPTHS_COMPUTED,
- OPTIMISTIC_TYPES_ASSIGNED,
- LOCAL_VARIABLE_TYPES_CALCULATED)) {
+ static final CompilationPhase REINITIALIZE_CACHED = new ReinitializeCachedPhase();
+ private static final class BytecodeGenerationPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final ScriptEnvironment senv = compiler.getScriptEnvironment();
@@ -469,7 +415,7 @@
try {
// Explicitly set BYTECODE_GENERATED here; it can not be set in case of skipping codegen for :program
// in the lazy + optimistic world. See CodeGenerator.skipFunction().
- newFunctionNode = transformFunction(newFunctionNode, codegen).setState(null, BYTECODE_GENERATED);
+ newFunctionNode = transformFunction(newFunctionNode, codegen);
codegen.generateScopeCalls();
} catch (final VerifyError e) {
if (senv._verify_code || senv._print_code) {
@@ -517,22 +463,16 @@
public String toString() {
return "'Bytecode Generation'";
}
- },
+ }
- INSTALL_PHASE(
- EnumSet.of(
- INITIALIZED,
- PARSED,
- CONSTANT_FOLDED,
- LOWERED,
- BUILTINS_TRANSFORMED,
- SPLIT,
- SYMBOLS_ASSIGNED,
- SCOPE_DEPTHS_COMPUTED,
- OPTIMISTIC_TYPES_ASSIGNED,
- LOCAL_VARIABLE_TYPES_CALCULATED,
- BYTECODE_GENERATED)) {
+ /**
+ * Bytecode generation:
+ *
+ * Generate the byte code class(es) resulting from the compiled FunctionNode
+ */
+ static final CompilationPhase BYTECODE_GENERATION_PHASE = new BytecodeGenerationPhase();
+ private static final class InstallPhase extends CompilationPhase {
@Override
FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
final DebugLogger log = compiler.getLogger();
@@ -543,8 +483,8 @@
Class<?> rootClass = null;
long length = 0L;
- final CodeInstaller<ScriptEnvironment> codeInstaller = compiler.getCodeInstaller();
- final Map<String, byte[]> bytecode = compiler.getBytecode();
+ final CodeInstaller codeInstaller = compiler.getCodeInstaller();
+ final Map<String, byte[]> bytecode = compiler.getBytecode();
for (final Entry<String, byte[]> entry : bytecode.entrySet()) {
final String className = entry.getKey();
@@ -600,18 +540,16 @@
log.fine(sb.toString());
}
- return setStates(fn.setRootClass(null, rootClass), BYTECODE_INSTALLED);
+ return fn.setRootClass(null, rootClass);
}
@Override
public String toString() {
return "'Class Installation'";
}
+ }
- };
-
- /** pre conditions required for function node to which this transform is to be applied */
- private final EnumSet<CompilationState> pre;
+ static final CompilationPhase INSTALL_PHASE = new InstallPhase();
/** start time of transform - used for timing, see {@link jdk.nashorn.internal.runtime.Timing} */
private long startTime;
@@ -622,21 +560,7 @@
/** boolean that is true upon transform completion */
private boolean isFinished;
- private CompilationPhase(final EnumSet<CompilationState> pre) {
- this.pre = pre;
- }
-
- private static FunctionNode setStates(final FunctionNode functionNode, final CompilationState state) {
- if (!AssertsEnabled.assertsEnabled()) {
- return functionNode;
- }
- return transformFunction(functionNode, new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public Node leaveFunctionNode(final FunctionNode fn) {
- return fn.setState(lc, state);
- }
- });
- }
+ private CompilationPhase() {}
/**
* Start a compilation phase
@@ -646,23 +570,7 @@
*/
protected FunctionNode begin(final Compiler compiler, final FunctionNode functionNode) {
compiler.getLogger().indent();
-
- assert pre != null;
-
- if (!functionNode.hasState(pre)) {
- final StringBuilder sb = new StringBuilder("Compilation phase ");
- sb.append(this).
- append(" is not applicable to ").
- append(quote(functionNode.getName())).
- append("\n\tFunctionNode state = ").
- append(functionNode.getState()).
- append("\n\tRequired state = ").
- append(this.pre);
-
- throw new CompilationException(sb.toString());
- }
-
- startTime = System.nanoTime();
+ startTime = System.nanoTime();
return functionNode;
}
@@ -697,7 +605,7 @@
abstract FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode functionNode) throws CompilationException;
/**
- * Apply a transform to a function node, returning the transfored function node. If the transform is not
+ * Apply a transform to a function node, returning the transformed function node. If the transform is not
* applicable, an exception is thrown. Every transform requires the function to have a certain number of
* states to operate. It can have more states set, but not fewer. The state list, i.e. the constructor
* arguments to any of the CompilationPhase enum entries, is a set of REQUIRED states.
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
index b9f6b10..2f2fe52 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -101,7 +101,7 @@
private final ConstantData constantData;
- private final CodeInstaller<ScriptEnvironment> installer;
+ private final CodeInstaller installer;
/** logger for compiler, trampolines and related code generation events
* that affect classes */
@@ -160,42 +160,40 @@
*/
private static final int COMPILE_UNIT_NAME_BUFFER_SIZE = 32;
- private final Map<Integer, byte[]> serializedAsts = new HashMap<>();
-
/**
* Compilation phases that a compilation goes through
*/
public static class CompilationPhases implements Iterable<CompilationPhase> {
/**
- * Singleton that describes compilation up to the phase where a function can be serialized.
+ * Singleton that describes compilation up to the phase where a function can be cached.
*/
- private final static CompilationPhases COMPILE_UPTO_SERIALIZABLE = new CompilationPhases(
+ private final static CompilationPhases COMPILE_UPTO_CACHED = new CompilationPhases(
"Common initial phases",
CompilationPhase.CONSTANT_FOLDING_PHASE,
CompilationPhase.LOWERING_PHASE,
- CompilationPhase.TRANSFORM_BUILTINS_PHASE,
+ CompilationPhase.APPLY_SPECIALIZATION_PHASE,
CompilationPhase.SPLITTING_PHASE,
CompilationPhase.PROGRAM_POINT_PHASE,
- CompilationPhase.SERIALIZE_SPLIT_PHASE
- );
-
- private final static CompilationPhases COMPILE_SERIALIZABLE_UPTO_BYTECODE = new CompilationPhases(
- "After common phases, before bytecode generator",
CompilationPhase.SYMBOL_ASSIGNMENT_PHASE,
CompilationPhase.SCOPE_DEPTH_COMPUTATION_PHASE,
+ CompilationPhase.CACHE_AST_PHASE
+ );
+
+ private final static CompilationPhases COMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
+ "After common phases, before bytecode generator",
CompilationPhase.OPTIMISTIC_TYPE_ASSIGNMENT_PHASE,
CompilationPhase.LOCAL_VARIABLE_TYPE_CALCULATION_PHASE
);
/**
- * Singleton that describes additional steps to be taken after deserializing, all the way up to (but not
- * including) generating and installing code.
+ * Singleton that describes additional steps to be taken after retrieving a cached function, all the
+ * way up to (but not including) generating and installing code.
*/
- public final static CompilationPhases RECOMPILE_SERIALIZED_UPTO_BYTECODE = new CompilationPhases(
- "Recompile serialized function up to bytecode",
- CompilationPhase.REINITIALIZE_SERIALIZED,
- COMPILE_SERIALIZABLE_UPTO_BYTECODE
+ public final static CompilationPhases RECOMPILE_CACHED_UPTO_BYTECODE = new CompilationPhases(
+ "Recompile cached function up to bytecode",
+ CompilationPhase.REINITIALIZE_CACHED,
+ COMPILE_CACHED_UPTO_BYTECODE
);
/**
@@ -211,8 +209,8 @@
/** Singleton that describes compilation up to the CodeGenerator, but not actually generating code */
public final static CompilationPhases COMPILE_UPTO_BYTECODE = new CompilationPhases(
"Compile upto bytecode",
- COMPILE_UPTO_SERIALIZABLE,
- COMPILE_SERIALIZABLE_UPTO_BYTECODE);
+ COMPILE_UPTO_CACHED,
+ COMPILE_CACHED_UPTO_BYTECODE);
/** Singleton that describes a standard eager compilation, but no installation, for example used by --compile-only */
public final static CompilationPhases COMPILE_ALL_NO_INSTALL = new CompilationPhases(
@@ -227,9 +225,9 @@
GENERATE_BYTECODE_AND_INSTALL);
/** Singleton that describes a full compilation - this includes code installation - from serialized state*/
- public final static CompilationPhases COMPILE_ALL_SERIALIZED = new CompilationPhases(
+ public final static CompilationPhases COMPILE_ALL_CACHED = new CompilationPhases(
"Eager compilation from serializaed state",
- RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+ RECOMPILE_CACHED_UPTO_BYTECODE,
GENERATE_BYTECODE_AND_INSTALL);
/**
@@ -248,9 +246,9 @@
GENERATE_BYTECODE_AND_INSTALL_RESTOF);
/** Compile from serialized for a rest of method */
- public final static CompilationPhases COMPILE_SERIALIZED_RESTOF = new CompilationPhases(
+ public final static CompilationPhases COMPILE_CACHED_RESTOF = new CompilationPhases(
"Compile serialized, rest of",
- RECOMPILE_SERIALIZED_UPTO_BYTECODE,
+ RECOMPILE_CACHED_UPTO_BYTECODE,
GENERATE_BYTECODE_AND_INSTALL_RESTOF);
private final List<CompilationPhase> phases;
@@ -313,7 +311,7 @@
}
boolean isRestOfCompilation() {
- return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_SERIALIZED_RESTOF;
+ return this == COMPILE_ALL_RESTOF || this == GENERATE_BYTECODE_AND_INSTALL_RESTOF || this == COMPILE_CACHED_RESTOF;
}
String getDesc() {
@@ -353,47 +351,83 @@
private static final AtomicInteger COMPILATION_ID = new AtomicInteger(0);
/**
- * Constructor
+ * Creates a new compiler instance for initial compilation of a script.
*
- * @param context context
- * @param env script environment
* @param installer code installer
* @param source source to compile
* @param errors error manager
* @param isStrict is this a strict compilation
+ * @return a new compiler
*/
- public Compiler(
- final Context context,
- final ScriptEnvironment env,
- final CodeInstaller<ScriptEnvironment> installer,
+ public static Compiler forInitialCompilation(
+ final CodeInstaller installer,
final Source source,
final ErrorManager errors,
final boolean isStrict) {
- this(context, env, installer, source, errors, isStrict, false, null, null, null, null, null, null);
+ return new Compiler(installer.getContext(), installer, source, errors, isStrict);
}
/**
- * Constructor
+ * Creates a compiler without a code installer. It can only be used to compile code, not install the
+ * generated classes and as such it is useful only for implementation of {@code --compile-only} command
+ * line option.
+ * @param context the current context
+ * @param source source to compile
+ * @param isStrict is this a strict compilation
+ * @return a new compiler
+ */
+ public static Compiler forNoInstallerCompilation(
+ final Context context,
+ final Source source,
+ final boolean isStrict) {
+ return new Compiler(context, null, source, context.getErrorManager(), isStrict);
+ }
+
+ /**
+ * Creates a compiler for an on-demand compilation job.
*
- * @param context context
- * @param env script environment
* @param installer code installer
* @param source source to compile
- * @param errors error manager
* @param isStrict is this a strict compilation
- * @param isOnDemand is this an on demand compilation
* @param compiledFunction compiled function, if any
* @param types parameter and return value type information, if any is known
* @param invalidatedProgramPoints invalidated program points for recompilation
* @param typeInformationFile descriptor of the location where type information is persisted
* @param continuationEntryPoints continuation entry points for restof method
* @param runtimeScope runtime scope for recompilation type lookup in {@code TypeEvaluator}
+ * @return a new compiler
*/
- @SuppressWarnings("unused")
- public Compiler(
+ public static Compiler forOnDemandCompilation(
+ final CodeInstaller installer,
+ final Source source,
+ final boolean isStrict,
+ final RecompilableScriptFunctionData compiledFunction,
+ final TypeMap types,
+ final Map<Integer, Type> invalidatedProgramPoints,
+ final Object typeInformationFile,
+ final int[] continuationEntryPoints,
+ final ScriptObject runtimeScope) {
+ final Context context = installer.getContext();
+ return new Compiler(context, installer, source, context.getErrorManager(), isStrict, true,
+ compiledFunction, types, invalidatedProgramPoints, typeInformationFile,
+ continuationEntryPoints, runtimeScope);
+ }
+
+ /**
+ * Convenience constructor for non on-demand compiler instances.
+ */
+ private Compiler(
final Context context,
- final ScriptEnvironment env,
- final CodeInstaller<ScriptEnvironment> installer,
+ final CodeInstaller installer,
+ final Source source,
+ final ErrorManager errors,
+ final boolean isStrict) {
+ this(context, installer, source, errors, isStrict, false, null, null, null, null, null, null);
+ }
+
+ private Compiler(
+ final Context context,
+ final CodeInstaller installer,
final Source source,
final ErrorManager errors,
final boolean isStrict,
@@ -405,7 +439,7 @@
final int[] continuationEntryPoints,
final ScriptObject runtimeScope) {
this.context = context;
- this.env = env;
+ this.env = context.getEnv();
this.installer = installer;
this.constantData = new ConstantData();
this.compileUnits = CompileUnit.createCompileUnitSet();
@@ -427,7 +461,7 @@
this.optimistic = env._optimistic_types;
}
- private static String safeSourceName(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final Source source) {
+ private String safeSourceName() {
String baseName = new File(source.getName()).getName();
final int index = baseName.lastIndexOf(".js");
@@ -486,7 +520,7 @@
sb.append('$');
}
- sb.append(Compiler.safeSourceName(env, installer, source));
+ sb.append(safeSourceName());
return sb.toString();
}
@@ -607,7 +641,7 @@
newFunctionNode.uniqueName(reservedName);
}
- final boolean info = log.levelFinerThanOrEqual(Level.INFO);
+ final boolean info = log.isLoggable(Level.INFO);
final DebugLogger timeLogger = env.isTimingEnabled() ? env._timing.getLogger() : null;
@@ -644,8 +678,8 @@
if (info) {
final StringBuilder sb = new StringBuilder("<< Finished compile job for ");
sb.append(newFunctionNode.getSource()).
- append(':').
- append(quote(newFunctionNode.getName()));
+ append(':').
+ append(quote(newFunctionNode.getName()));
if (time > 0L && timeLogger != null) {
assert env.isTimingEnabled();
@@ -685,7 +719,7 @@
return constantData;
}
- CodeInstaller<ScriptEnvironment> getCodeInstaller() {
+ CodeInstaller getCodeInstaller() {
return installer;
}
@@ -713,7 +747,7 @@
if (cacheKey != null && env._persistent_cache) {
// If this is an on-demand compilation create a function initializer for the function being compiled.
// Otherwise use function initializer map generated by codegen.
- Map<Integer, FunctionInitializer> initializers = new HashMap<>();
+ final Map<Integer, FunctionInitializer> initializers = new HashMap<>();
if (isOnDemandCompilation()) {
initializers.put(functionNode.getId(), new FunctionInitializer(functionNode, getInvalidatedProgramPoints()));
} else {
@@ -766,14 +800,6 @@
compileUnits.addAll(newUnits);
}
- void serializeAst(final FunctionNode fn) {
- serializedAsts.put(fn.getId(), AstSerializer.serialize(fn));
- }
-
- byte[] removeSerializedAst(final int fnId) {
- return serializedAsts.remove(fnId);
- }
-
CompileUnit findUnit(final long weight) {
for (final CompileUnit unit : compileUnits) {
if (unit.canHold(weight)) {
@@ -829,9 +855,9 @@
final long totalSize = osc.calculateObjectSize(functionNode);
sb.append(phaseName).
- append(" Total size = ").
- append(totalSize / 1024 / 1024).
- append("MB");
+ append(" Total size = ").
+ append(totalSize / 1024 / 1024).
+ append("MB");
log.info(sb);
Collections.sort(list, new Comparator<ClassHistogramElement>() {
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
index a7f31d5..0d64ac2 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java
@@ -192,7 +192,7 @@
private static Set<String> symbolNames;
/**
- * Prefix used for internal methods generated in script clases.
+ * Prefix used for internal methods generated in script classes.
*/
private static final String INTERNAL_METHOD_PREFIX = ":";
@@ -225,7 +225,7 @@
}
/**
- * Check whether a name is that of a reserved compiler constnat
+ * Check whether a name is that of a reserved compiler constant
* @param name name
* @return true if compiler constant name
*/
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java b/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java
index cd87f0f..a7e6653 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ConstantData.java
@@ -30,6 +30,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
+
import jdk.nashorn.internal.runtime.PropertyMap;
/**
@@ -120,7 +122,7 @@
private final int hashCode;
public PropertyMapWrapper(final PropertyMap map) {
- this.hashCode = Arrays.hashCode(map.getProperties());
+ this.hashCode = Arrays.hashCode(map.getProperties()) + 31 * Objects.hashCode(map.getClassName());
this.propertyMap = map;
}
@@ -131,8 +133,13 @@
@Override
public boolean equals(final Object other) {
- return other instanceof PropertyMapWrapper &&
- Arrays.equals(propertyMap.getProperties(), ((PropertyMapWrapper) other).propertyMap.getProperties());
+ if (!(other instanceof PropertyMapWrapper)) {
+ return false;
+ }
+ final PropertyMap otherMap = ((PropertyMapWrapper) other).propertyMap;
+ return propertyMap == otherMap
+ || (Arrays.equals(propertyMap.getProperties(), otherMap.getProperties())
+ && Objects.equals(propertyMap.getClassName(), otherMap.getClassName()));
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java b/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java
index e677382..620a43e 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/DumpBytecode.java
@@ -88,7 +88,7 @@
}
- // should code be dumped to disk - only valid in compile_only mode?
+ // should code be dumped to disk
if (env._dest_dir != null) {
final String fileName = className.replace('.', File.separatorChar) + ".class";
final int index = fileName.lastIndexOf(File.separatorChar);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
index fd05192..9aa6465 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java
@@ -34,7 +34,6 @@
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
-import java.util.Iterator;
import java.util.List;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.Symbol;
@@ -91,27 +90,20 @@
findClass();
}
- /**
- * Construct an object.
- *
- * @param method the method emitter
- */
@Override
- protected void makeObject(final MethodEmitter method) {
+ public void createObject(final MethodEmitter method) {
makeMap();
final String className = getClassName();
- try {
- // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
- // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
- // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
- // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
- // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
- // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
- // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
- method._new(Context.forStructureClass(className.replace('/', '.'))).dup();
- } catch (final ClassNotFoundException e) {
- throw new AssertionError(e);
- }
+ // NOTE: we must load the actual structure class here, because the API operates with Nashorn Type objects,
+ // and Type objects need a loaded class, for better or worse. We also have to be specific and use the type
+ // of the actual structure class, we can't generalize it to e.g. Type.typeFor(ScriptObject.class) as the
+ // exact type information is needed for generating continuations in rest-of methods. If we didn't do this,
+ // object initializers like { x: arr[i] } would fail during deoptimizing compilation on arr[i], as the
+ // values restored from the RewriteException would be cast to "ScriptObject" instead of to e.g. "JO4", and
+ // subsequently the "PUTFIELD J04.L0" instruction in the continuation code would fail bytecode verification.
+ assert fieldObjectClass != null;
+ method._new(fieldObjectClass).dup();
+
loadMap(method); //load the map
if (isScope()) {
@@ -126,14 +118,14 @@
} else {
method.invoke(constructorNoLookup(className, PropertyMap.class));
}
+ }
- helpOptimisticRecognizeDuplicateIdentity(method);
-
+ @Override
+ public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+ method.load(objectType, objectSlot);
// Set values.
- final Iterator<MapTuple<T>> iter = tuples.iterator();
-
- while (iter.hasNext()) {
- final MapTuple<T> tuple = iter.next();
+ for (int i = start; i < end; i++) {
+ final MapTuple<T> tuple = tuples.get(i);
//we only load when we have both symbols and values (which can be == the symbol)
//if we didn't load, we need an array property
if (tuple.symbol != null && tuple.value != null) {
@@ -212,6 +204,11 @@
}
}
+ @Override
+ protected Class<? extends ScriptObject> getAllocatorClass() {
+ return fieldObjectClass;
+ }
+
/**
* Get the class name for the object class,
* e.g. {@code com.nashorn.oracle.scripts.JO2P0}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java b/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java
index 9f9abf9..bcdf73f 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FindScopeDepths.java
@@ -34,13 +34,12 @@
import java.util.Set;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -54,7 +53,7 @@
* FunctionNode being compiled
*/
@Logger(name="scopedepths")
-final class FindScopeDepths extends NodeVisitor<LexicalContext> implements Loggable {
+final class FindScopeDepths extends SimpleNodeVisitor implements Loggable {
private final Compiler compiler;
private final Map<Integer, Map<Integer, RecompilableScriptFunctionData>> fnIdToNestedFunctions = new HashMap<>();
@@ -67,7 +66,6 @@
private int dynamicScopeCount;
FindScopeDepths(final Compiler compiler) {
- super(new LexicalContext());
this.compiler = compiler;
this.log = initLogger(compiler.getContext());
}
@@ -182,14 +180,16 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
final String name = functionNode.getName();
- FunctionNode newFunctionNode = functionNode.setState(lc, CompilationState.SCOPE_DEPTHS_COMPUTED);
-
+ FunctionNode newFunctionNode = functionNode;
if (compiler.isOnDemandCompilation()) {
final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(newFunctionNode.getId());
if (data.inDynamicContext()) {
log.fine("Reviving scriptfunction ", quote(name), " as defined in previous (now lost) dynamic scope.");
newFunctionNode = newFunctionNode.setInDynamicContext(lc);
}
+ if (newFunctionNode == lc.getOutermostFunction() && !newFunctionNode.hasApplyToCallSpecialization()) {
+ data.setCachedAst(newFunctionNode);
+ }
return newFunctionNode;
}
@@ -210,8 +210,7 @@
ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties(), compiler.getContext().useDualFields()),
nestedFunctions,
externalSymbolDepths.get(fnId),
- internalSymbols.get(fnId),
- compiler.removeSerializedAst(fnId));
+ internalSymbols.get(fnId));
if (lc.getOutermostFunction() != newFunctionNode) {
final FunctionNode parentFn = lc.getParentFunction(newFunctionNode);
@@ -275,17 +274,13 @@
//get all symbols that are referenced inside this function body
final Set<Symbol> symbols = new HashSet<>();
- block.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ block.accept(new SimpleNodeVisitor() {
@Override
- public final boolean enterDefault(final Node node) {
- if (!compiler.isOnDemandCompilation()) {
- if (node instanceof IdentNode) {
- final Symbol symbol = ((IdentNode)node).getSymbol();
- if (symbol != null && symbol.isScope()) {
- //if this is an internal symbol, skip it.
- symbols.add(symbol);
- }
- }
+ public boolean enterIdentNode(final IdentNode identNode) {
+ final Symbol symbol = identNode.getSymbol();
+ if (symbol != null && symbol.isScope()) {
+ //if this is an internal symbol, skip it.
+ symbols.add(symbol);
}
return true;
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
index 092b788..e72ea03 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -37,9 +37,7 @@
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.Expression;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
@@ -48,7 +46,7 @@
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -60,12 +58,11 @@
* Simple constant folding pass, executed before IR is starting to be lowered.
*/
@Logger(name="fold")
-final class FoldConstants extends NodeVisitor<LexicalContext> implements Loggable {
+final class FoldConstants extends SimpleNodeVisitor implements Loggable {
private final DebugLogger log;
FoldConstants(final Compiler compiler) {
- super(new LexicalContext());
this.log = initLogger(compiler.getContext());
}
@@ -101,7 +98,7 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
- return functionNode.setState(lc, CompilationState.CONSTANT_FOLDED);
+ return functionNode;
}
@Override
@@ -117,7 +114,7 @@
statements.addAll(executed.getStatements()); // Get statements form executed branch
}
if (dropped != null) {
- extractVarNodes(dropped, statements); // Get var-nodes from non-executed branch
+ extractVarNodesFromDeadCode(dropped, statements); // Get var-nodes from non-executed branch
}
if (statements.isEmpty()) {
return new EmptyNode(ifNode);
@@ -186,14 +183,27 @@
protected abstract LiteralNode<?> eval();
}
- private static void extractVarNodes(final Block block, final List<Statement> statements) {
- final LexicalContext lc = new LexicalContext();
- block.accept(lc, new NodeVisitor<LexicalContext>(lc) {
+ /**
+ * When we eliminate dead code, we must preserve var declarations as they are scoped to the whole
+ * function. This method gathers var nodes from code passed to it, removing their initializers.
+ *
+ * @param deadCodeRoot the root node of eliminated dead code
+ * @param statements a list that will be receiving the var nodes from the dead code, with their
+ * initializers removed.
+ */
+ static void extractVarNodesFromDeadCode(final Node deadCodeRoot, final List<Statement> statements) {
+ deadCodeRoot.accept(new SimpleNodeVisitor() {
@Override
public boolean enterVarNode(final VarNode varNode) {
statements.add(varNode.setInit(null));
return false;
}
+
+ @Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ // Don't descend into nested functions
+ return false;
+ }
});
}
@@ -353,8 +363,8 @@
return null;
}
- isInteger &= JSType.isRepresentableAsInt(value) && !JSType.isNegativeZero(value);
- isLong &= JSType.isRepresentableAsLong(value) && !JSType.isNegativeZero(value);
+ isInteger &= JSType.isStrictlyRepresentableAsInt(value);
+ isLong &= JSType.isStrictlyRepresentableAsLong(value);
if (isInteger) {
return LiteralNode.newInstance(token, finish, (int)value);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Label.java b/nashorn/src/jdk/nashorn/internal/codegen/Label.java
index 5f1a169..a70165d 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Label.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Label.java
@@ -447,7 +447,7 @@
undefineLocalVariables(liveLocalCount, true);
// Temporaries are promoted
firstTemp = liveLocalCount;
- // No trailing undefineds
+ // No trailing undefined values
localVariableTypes.subList(firstTemp, localVariableTypes.size()).clear();
assert symbolBoundary.length() == firstTemp;
// Generalize all reference types to Object, and promote boolean to int
@@ -497,7 +497,7 @@
private transient Label.Stack stack;
/** ASM representation of this label */
- private jdk.internal.org.objectweb.asm.Label label;
+ private transient jdk.internal.org.objectweb.asm.Label label;
/** Id for debugging purposes, remove if footprint becomes unmanageable */
private final int id;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index 2645f24..c7f0800 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -54,7 +54,6 @@
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.GetSplitState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
@@ -88,6 +87,7 @@
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
/**
@@ -106,7 +106,7 @@
* instances of the calculator to be run on nested functions (when not lazy compiling).
*
*/
-final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{
+final class LocalVariableTypesCalculator extends SimpleNodeVisitor {
private static class JumpOrigin {
final JoinPredecessor node;
@@ -426,7 +426,6 @@
private final Deque<Label> catchLabels = new ArrayDeque<>();
LocalVariableTypesCalculator(final Compiler compiler) {
- super(new LexicalContext());
this.compiler = compiler;
}
@@ -1331,7 +1330,7 @@
// Sets the return type of the function and also performs the bottom-up pass of applying type and conversion
// information to nodes as well as doing the calculation on nested functions as required.
FunctionNode newFunction = functionNode;
- final NodeVisitor<LexicalContext> applyChangesVisitor = new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ final SimpleNodeVisitor applyChangesVisitor = new SimpleNodeVisitor() {
private boolean inOuterFunction = true;
private final Deque<JoinPredecessor> joinPredecessors = new ArrayDeque<>();
@@ -1478,7 +1477,6 @@
newFunction = newFunction.setReturnType(lc, returnType);
- newFunction = newFunction.setState(lc, CompilationState.LOCAL_VARIABLE_TYPES_CALCULATED);
newFunction = newFunction.setParameters(lc, newFunction.visitParameters(applyChangesVisitor));
return newFunction;
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
index 90afc9b..1f0e5ae 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java
@@ -51,7 +51,6 @@
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
@@ -74,7 +73,7 @@
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
@@ -121,13 +120,7 @@
terminated = true;
}
} else {
- statement.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public boolean enterVarNode(final VarNode varNode) {
- newStatements.add(varNode.setInit(null));
- return false;
- }
- });
+ FoldConstants.extractVarNodesFromDeadCode(statement, newStatements);
}
}
return newStatements;
@@ -266,7 +259,7 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
log.info("END FunctionNode: ", functionNode.getName());
- return functionNode.setState(lc, CompilationState.LOWERED);
+ return functionNode;
}
@Override
@@ -328,7 +321,7 @@
@SuppressWarnings("unchecked")
private static <T extends Node> T ensureUniqueNamesIn(final T node) {
- return (T)node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ return (T)node.accept(new SimpleNodeVisitor() {
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
final String name = functionNode.getName();
@@ -393,7 +386,7 @@
final Block finallyBlock = createFinallyBlock(finallyBody);
final ArrayList<Block> inlinedFinallies = new ArrayList<>();
final FunctionNode fn = lc.getCurrentFunction();
- final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ final TryNode newTryNode = (TryNode)tryNode.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
@@ -511,7 +504,7 @@
}
/*
- * create a new trynode
+ * create a new try node
* if we have catches:
*
* try try
@@ -522,7 +515,7 @@
* catchall
* rethrow
*
- * otheriwse
+ * otherwise
*
* try try
* x x
@@ -536,7 +529,7 @@
final Block catchAll = catchAllBlock(tryNode);
final List<ThrowNode> rethrows = new ArrayList<>(1);
- catchAll.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ catchAll.accept(new SimpleNodeVisitor() {
@Override
public boolean enterThrowNode(final ThrowNode throwNode) {
rethrows.add(throwNode);
@@ -681,7 +674,7 @@
private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) {
final List<Node> escapes = new ArrayList<>();
- loopBody.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ loopBody.accept(new SimpleNodeVisitor() {
@Override
public Node leaveBreakNode(final BreakNode node) {
escapes.add(node);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
index 0a3e241..f5bc303 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java
@@ -258,8 +258,7 @@
*/
private Type popType(final Type expected) {
final Type type = popType();
- assert type.isObject() && expected.isObject() ||
- type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
+ assert type.isEquivalentTo(expected) : type + " is not compatible with " + expected;
return type;
}
@@ -1159,7 +1158,7 @@
/**
* Pop a value from the stack and store it in a variable denoted by the given symbol. The variable should be either
* a local variable, or a function parameter (and not a scoped variable). For local variables, this method will also
- * do the bookeeping of the local variable table as well as mark values in all alternative slots for the symbol as
+ * do the bookkeeping of the local variable table as well as mark values in all alternative slots for the symbol as
* dead. In this regard it differs from {@link #storeHidden(Type, int)}.
*
* @param symbol the symbol to store into.
@@ -2133,10 +2132,25 @@
* @return the method emitter
*/
MethodEmitter dynamicNew(final int argCount, final int flags) {
+ return dynamicNew(argCount, flags, null);
+ }
+
+ /**
+ * Generate a dynamic new
+ *
+ * @param argCount number of arguments
+ * @param flags callsite flags
+ * @param msg additional message to be used when reporting error
+ *
+ * @return the method emitter
+ */
+ MethodEmitter dynamicNew(final int argCount, final int flags, final String msg) {
assert !isOptimistic(flags);
debug("dynamic_new", "argcount=", argCount);
final String signature = getDynamicSignature(Type.OBJECT, argCount);
- method.visitInvokeDynamicInsn("dyn:new", signature, LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(
+ msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:new:" + NameCodec.encode(msg) : "dyn:new",
+ signature, LINKERBOOTSTRAP, flags);
pushType(Type.OBJECT); //TODO fix result type
return this;
}
@@ -2151,10 +2165,26 @@
* @return the method emitter
*/
MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags) {
+ return dynamicCall(returnType, argCount, flags, null);
+ }
+
+ /**
+ * Generate a dynamic call
+ *
+ * @param returnType return type
+ * @param argCount number of arguments
+ * @param flags callsite flags
+ * @param msg additional message to be used when reporting error
+ *
+ * @return the method emitter
+ */
+ MethodEmitter dynamicCall(final Type returnType, final int argCount, final int flags, final String msg) {
debug("dynamic_call", "args=", argCount, "returnType=", returnType);
final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
debug(" signature", signature);
- method.visitInvokeDynamicInsn("dyn:call", signature, LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(
+ msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:call:" + NameCodec.encode(msg) : "dyn:call",
+ signature, LINKERBOOTSTRAP, flags);
pushType(returnType);
return this;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
index 383d2f1..f753685 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java
@@ -69,7 +69,6 @@
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
-import jdk.nashorn.internal.runtime.options.Options;
/**
* Generates the ScriptObject subclass structure with fields for a user objects.
@@ -787,7 +786,7 @@
* @param primitiveSetter primitive setter for the current type with an element of the current type
* @param objectSetter the object setter
*
- * @return method handle that checks if the element to be set is of the currenttype, even though it's boxed
+ * @return method handle that checks if the element to be set is of the current type, even though it's boxed
* and instead of using the generic object setter, that would blow up the type and invalidate the map,
* unbox it and call the primitive setter instead
*/
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java
index 613c91e..0446c07 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java
@@ -36,7 +36,7 @@
* Base class for object creation code generation.
* @param <T> value type
*/
-public abstract class ObjectCreator<T> {
+public abstract class ObjectCreator<T> implements CodeGenerator.SplitLiteralCreator {
/** List of keys & symbols to initiate in this ObjectCreator */
final List<MapTuple<T>> tuples;
@@ -69,7 +69,23 @@
* Generate code for making the object.
* @param method Script method.
*/
- protected abstract void makeObject(final MethodEmitter method);
+ public void makeObject(final MethodEmitter method) {
+ createObject(method);
+ // We need to store the object in a temporary slot as populateRange expects to load the
+ // object from a slot (as it is also invoked within split methods). Note that this also
+ // helps optimistic continuations to handle the stack in case an optimistic assumption
+ // fails during initialization (see JDK-8079269).
+ final int objectSlot = method.getUsedSlotsWithLiveTemporaries();
+ final Type objectType = method.peekType();
+ method.storeTemp(objectType, objectSlot);
+ populateRange(method, objectType, objectSlot, 0, tuples.size());
+ }
+
+ /**
+ * Generate code for creating and initializing the object.
+ * @param method the method emitter
+ */
+ protected abstract void createObject(final MethodEmitter method);
/**
* Construct the property map appropriate for the object.
@@ -125,6 +141,12 @@
}
/**
+ * Get the class of objects created by this ObjectCreator
+ * @return class of created object
+ */
+ abstract protected Class<? extends ScriptObject> getAllocatorClass();
+
+ /**
* Technique for loading an initial value. Defined by anonymous subclasses in code gen.
*
* @param value Value to load.
@@ -145,29 +167,4 @@
MethodEmitter loadTuple(final MethodEmitter method, final MapTuple<T> tuple) {
return loadTuple(method, tuple, true);
}
-
- /**
- * If using optimistic typing, let the code generator realize that the newly created object on the stack
- * when DUP-ed will be the same value. Basically: {NEW, DUP, INVOKESPECIAL init, DUP} will leave a stack
- * load specification {unknown, unknown} on stack (that is "there's two values on the stack, but neither
- * comes from a known local load"). If there's an optimistic operation in the literal initializer,
- * OptimisticOperation.storeStack will allocate two temporary locals for it and store them as
- * {ASTORE 4, ASTORE 3}. If we instead do {NEW, DUP, INVOKESPECIAL init, ASTORE 3, ALOAD 3, DUP} we end up
- * with stack load specification {ALOAD 3, ALOAD 3} (as DUP can track that the value it duplicated came
- * from a local load), so if/when a continuation needs to be recreated from it, it'll be
- * able to emit ALOAD 3, ALOAD 3 to recreate the stack. If we didn't do this, deoptimization within an
- * object literal initialization could in rare cases cause an incompatible change in the shape of the
- * local variable table for the temporaries, e.g. in the following snippet where a variable is reassigned
- * to a wider type in an object initializer:
- * <code>var m = 1; var obj = {p0: m, p1: m = "foo", p2: m}</code>
- * @param method the current method emitter.
- */
- void helpOptimisticRecognizeDuplicateIdentity(final MethodEmitter method) {
- if (codegen.useOptimisticTypes()) {
- final Type objectType = method.peekType();
- final int tempSlot = method.defineTemporaryLocalVariable(objectType.getSlots());
- method.storeHidden(objectType, tempSlot);
- method.load(objectType, tempSlot);
- }
- }
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java b/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java
index c802907..275bf5c 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/OptimisticTypesCalculator.java
@@ -38,12 +38,10 @@
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Optimistic;
@@ -53,7 +51,7 @@
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -62,7 +60,7 @@
* must not ever be marked as optimistic, assigning narrowest non-invalidated types to program points from the
* compilation environment, as well as initializing optimistic types of global properties for scripts.
*/
-final class OptimisticTypesCalculator extends NodeVisitor<LexicalContext> {
+final class OptimisticTypesCalculator extends SimpleNodeVisitor {
final Compiler compiler;
@@ -70,7 +68,6 @@
final Deque<BitSet> neverOptimistic = new ArrayDeque<>();
OptimisticTypesCalculator(final Compiler compiler) {
- super(new LexicalContext());
this.compiler = compiler;
}
@@ -208,7 +205,7 @@
@Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
neverOptimistic.pop();
- return functionNode.setState(lc, CompilationState.OPTIMISTIC_TYPES_ASSIGNED);
+ return functionNode;
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ProgramPoints.java b/nashorn/src/jdk/nashorn/internal/codegen/ProgramPoints.java
index 4606989..bfc47ea 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ProgramPoints.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ProgramPoints.java
@@ -37,25 +37,20 @@
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.Optimistic;
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
/**
* Find program points in the code that are needed for optimistic assumptions
*/
-class ProgramPoints extends NodeVisitor<LexicalContext> {
+class ProgramPoints extends SimpleNodeVisitor {
private final IntDeque nextProgramPoint = new IntDeque();
private final Set<Node> noProgramPoint = new HashSet<>();
- ProgramPoints() {
- super(new LexicalContext());
- }
-
private int next() {
final int next = nextProgramPoint.getAndIncrement();
if(next > MAX_PROGRAM_POINT_VALUE) {
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java b/nashorn/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java
index 57f9e68..594ba66 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ReplaceCompileUnits.java
@@ -29,21 +29,17 @@
import java.util.List;
import jdk.nashorn.internal.ir.CompileUnitHolder;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.ObjectNode;
+import jdk.nashorn.internal.ir.Splittable;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
/**
* Base class for a node visitor that replaces {@link CompileUnit}s in {@link CompileUnitHolder}s.
*/
-abstract class ReplaceCompileUnits extends NodeVisitor<LexicalContext> {
- ReplaceCompileUnits() {
- super(new LexicalContext());
- }
+abstract class ReplaceCompileUnits extends SimpleNodeVisitor {
/**
* Override to provide a replacement for an old compile unit.
@@ -64,22 +60,35 @@
@Override
public Node leaveFunctionNode(final FunctionNode node) {
- return node.setCompileUnit(lc, getExistingReplacement(node)).setState(lc, CompilationState.COMPILE_UNITS_REUSED);
+ return node.setCompileUnit(lc, getExistingReplacement(node));
}
@Override
public Node leaveLiteralNode(final LiteralNode<?> node) {
if (node instanceof ArrayLiteralNode) {
final ArrayLiteralNode aln = (ArrayLiteralNode)node;
- if (aln.getUnits() == null) {
+ if (aln.getSplitRanges() == null) {
return node;
}
- final List<ArrayUnit> newArrayUnits = new ArrayList<>();
- for (final ArrayUnit au : aln.getUnits()) {
- newArrayUnits.add(new ArrayUnit(getExistingReplacement(au), au.getLo(), au.getHi()));
+ final List<Splittable.SplitRange> newArrayUnits = new ArrayList<>();
+ for (final Splittable.SplitRange au : aln.getSplitRanges()) {
+ newArrayUnits.add(new Splittable.SplitRange(getExistingReplacement(au), au.getLow(), au.getHigh()));
}
- return aln.setUnits(lc, newArrayUnits);
+ return aln.setSplitRanges(lc, newArrayUnits);
}
return node;
}
+
+ @Override
+ public Node leaveObjectNode(final ObjectNode objectNode) {
+ final List<Splittable.SplitRange> ranges = objectNode.getSplitRanges();
+ if (ranges != null) {
+ final List<Splittable.SplitRange> newRanges = new ArrayList<>();
+ for (final Splittable.SplitRange range : ranges) {
+ newRanges.add(new Splittable.SplitRange(getExistingReplacement(range), range.getLow(), range.getHigh()));
+ }
+ return objectNode.setSplitRanges(lc, newRanges);
+ }
+ return super.leaveObjectNode(objectNode);
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
index 078324c..eb4758f 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SharedScopeCall.java
@@ -169,7 +169,7 @@
slot += type.getSlots();
}
// Shared scope calls disabled in optimistic world. TODO is this right?
- method.dynamicCall(returnType, 2 + paramTypes.length, flags);
+ method.dynamicCall(returnType, 2 + paramTypes.length, flags, symbol.getName());
}
method._return(returnType);
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
index 1de5bd5..9cda8dd 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
@@ -61,7 +61,7 @@
}
@Override
- protected void makeObject(final MethodEmitter method) {
+ public void createObject(final MethodEmitter method) {
assert !isScope() : "spill scope objects are not currently supported";
final int length = tuples.size();
@@ -69,9 +69,7 @@
final int spillLength = ScriptObject.spillAllocationLength(length);
final long[] jpresetValues = dualFields ? new long[spillLength] : null;
final Object[] opresetValues = new Object[spillLength];
- final Set<Integer> postsetValues = new LinkedHashSet<>();
- final int callSiteFlags = codegen.getCallSiteFlags();
- final Class<?> objectClass = dualFields ? JD.class : JO.class;
+ final Class<?> objectClass = getAllocatorClass();
ArrayData arrayData = ArrayData.allocate(ScriptRuntime.EMPTY_ARRAY);
// Compute constant property values
@@ -85,9 +83,7 @@
if (value != null) {
final Object constantValue = LiteralNode.objectAsConstant(value);
- if (constantValue == LiteralNode.POSTSET_MARKER) {
- postsetValues.add(pos);
- } else {
+ if (constantValue != LiteralNode.POSTSET_MARKER) {
final Property property = propertyMap.findProperty(key);
if (property != null) {
// normal property key
@@ -146,25 +142,34 @@
// instantiate the script object with spill objects
method.invoke(constructorNoLookup(objectClass, PropertyMap.class, long[].class, Object[].class));
- helpOptimisticRecognizeDuplicateIdentity(method);
-
// Set prefix array data if any
if (arrayData.length() > 0) {
method.dup();
codegen.loadConstant(arrayData);
method.invoke(virtualCallNoLookup(ScriptObject.class, "setArray", void.class, ArrayData.class));
}
+ }
+
+ @Override
+ public void populateRange(final MethodEmitter method, final Type objectType, final int objectSlot, final int start, final int end) {
+ final int callSiteFlags = codegen.getCallSiteFlags();
+ method.load(objectType, objectSlot);
// set postfix values
- for (final int i : postsetValues) {
+ for (int i = start; i < end; i++) {
final MapTuple<Expression> tuple = tuples.get(i);
+
+ if (LiteralNode.isConstant(tuple.value)) {
+ continue;
+ }
+
final Property property = propertyMap.findProperty(tuple.key);
+
if (property == null) {
final int index = ArrayIndex.getArrayIndex(tuple.key);
assert ArrayIndex.isValidArrayIndex(index);
method.dup();
method.load(ArrayIndex.toLongIndex(index));
- //method.println("putting " + tuple + " into arraydata");
loadTuple(method, tuple);
method.dynamicSetIndex(callSiteFlags);
} else {
@@ -178,8 +183,7 @@
@Override
protected PropertyMap makeMap() {
assert propertyMap == null : "property map already initialized";
- final boolean dualFields = codegen.useDualFields();
- final Class<? extends ScriptObject> clazz = dualFields ? JD.class : JO.class;
+ final Class<? extends ScriptObject> clazz = getAllocatorClass();
propertyMap = new MapCreator<>(clazz, tuples).makeSpillMap(false, codegen.useDualFields());
return propertyMap;
}
@@ -188,4 +192,9 @@
protected void loadValue(final Expression expr, final Type type) {
codegen.loadExpressionAsType(expr, type);
}
+
+ @Override
+ protected Class<? extends ScriptObject> getAllocatorClass() {
+ return codegen.useDualFields() ? JD.class : JO.class;
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java b/nashorn/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
index 6a73907..019815a 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/SplitIntoFunctions.java
@@ -175,8 +175,7 @@
FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT
)
.setBody(lc, body)
- .setCompileUnit(lc, splitNode.getCompileUnit())
- .copyCompilationState(lc, originalFn);
+ .setCompileUnit(lc, splitNode.getCompileUnit());
// Call the function:
// either "(function () { ... }).call(this)"
@@ -308,10 +307,6 @@
assert !varNode.isBlockScoped(); //TODO: we must handle these too, but we currently don't
final Expression init = varNode.getInit();
- if (varNode.isAnonymousFunctionDeclaration()) {
- // We ain't moving anonymous function declarations.
- return super.enterVarNode(varNode);
- }
// Move a declaration-only var statement to the top of the outermost function.
getCurrentFunctionState().varStatements.add(varNode.setInit(null));
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
index 929e954..1fe97fe 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java
@@ -33,15 +33,15 @@
import java.util.Map;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
+import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.Statement;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -52,7 +52,7 @@
* Split the IR into smaller compile units.
*/
@Logger(name="splitter")
-final class Splitter extends NodeVisitor<LexicalContext> implements Loggable {
+final class Splitter extends SimpleNodeVisitor implements Loggable {
/** Current compiler. */
private final Compiler compiler;
@@ -78,7 +78,6 @@
* @param outermostCompileUnit compile unit for outermost function, if non-lazy this is the script's compile unit
*/
public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) {
- super(new LexicalContext());
this.compiler = compiler;
this.outermost = functionNode;
this.outermostCompileUnit = outermostCompileUnit;
@@ -141,7 +140,7 @@
final Block body = functionNode.getBody();
final List<FunctionNode> dc = directChildren(functionNode);
- final Block newBody = (Block)body.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ final Block newBody = (Block)body.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode nestedFunction) {
return dc.contains(nestedFunction);
@@ -158,12 +157,12 @@
assert functionNode.getCompileUnit() != null;
- return functionNode.setState(null, CompilationState.SPLIT);
+ return functionNode;
}
private static List<FunctionNode> directChildren(final FunctionNode functionNode) {
final List<FunctionNode> dc = new ArrayList<>();
- functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ functionNode.accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode child) {
if (child == functionNode) {
@@ -296,7 +295,7 @@
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
final Node[] value = arrayLiteralNode.getValue();
final int[] postsets = arrayLiteralNode.getPostsets();
- final List<ArrayUnit> units = new ArrayList<>();
+ final List<Splittable.SplitRange> ranges = new ArrayList<>();
long totalWeight = 0;
int lo = 0;
@@ -310,7 +309,7 @@
if (totalWeight >= SPLIT_THRESHOLD) {
final CompileUnit unit = compiler.findUnit(totalWeight - weight);
- units.add(new ArrayUnit(unit, lo, i));
+ ranges.add(new Splittable.SplitRange(unit, lo, i));
lo = i;
totalWeight = weight;
}
@@ -318,16 +317,59 @@
if (lo != postsets.length) {
final CompileUnit unit = compiler.findUnit(totalWeight);
- units.add(new ArrayUnit(unit, lo, postsets.length));
+ ranges.add(new Splittable.SplitRange(unit, lo, postsets.length));
}
- return arrayLiteralNode.setUnits(lc, units);
+ return arrayLiteralNode.setSplitRanges(lc, ranges);
}
return literal;
}
@Override
+ public Node leaveObjectNode(final ObjectNode objectNode) {
+ long weight = WeighNodes.weigh(objectNode);
+
+ if (weight < SPLIT_THRESHOLD) {
+ return objectNode;
+ }
+
+ final FunctionNode functionNode = lc.getCurrentFunction();
+ lc.setFlag(functionNode, FunctionNode.IS_SPLIT);
+
+ final List<Splittable.SplitRange> ranges = new ArrayList<>();
+ final List<PropertyNode> properties = objectNode.getElements();
+ final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+ long totalWeight = 0;
+ int lo = 0;
+
+ for (int i = 0; i < properties.size(); i++) {
+
+ final PropertyNode property = properties.get(i);
+ final boolean isConstant = LiteralNode.isConstant(property.getValue());
+
+ if (!isConstant || !isSpillObject) {
+ weight = isConstant ? 0 : WeighNodes.weigh(property.getValue());
+ totalWeight += WeighNodes.AASTORE_WEIGHT + weight;
+
+ if (totalWeight >= SPLIT_THRESHOLD) {
+ final CompileUnit unit = compiler.findUnit(totalWeight - weight);
+ ranges.add(new Splittable.SplitRange(unit, lo, i));
+ lo = i;
+ totalWeight = weight;
+ }
+ }
+ }
+
+ if (lo != properties.size()) {
+ final CompileUnit unit = compiler.findUnit(totalWeight);
+ ranges.add(new Splittable.SplitRange(unit, lo, properties.size()));
+ }
+
+ return objectNode.setSplitRanges(lc, ranges);
+ }
+
+ @Override
public boolean enterFunctionNode(final FunctionNode node) {
//only go into the function node for this splitter. any subfunctions are rejected
return node == outermost;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/TypeMap.java b/nashorn/src/jdk/nashorn/internal/codegen/TypeMap.java
index 11efce1..a26e6b9 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/TypeMap.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/TypeMap.java
@@ -27,21 +27,18 @@
import java.lang.invoke.MethodType;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
import java.util.NoSuchElementException;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.runtime.ScriptFunction;
/**
- * A data structure that maps one or several function nodes (by their unique id:s, not by
- * the FunctionNode object itself, due to copy on write changing it several times through
- * code generation.
+ * A tuple containing function id, parameter types, return type and needsCallee flag.
*/
-public class TypeMap {
- private final Map<Integer, Type[]> paramTypeMap = new HashMap<>();
- private final Map<Integer, Type> returnTypeMap = new HashMap<>();
+public final class TypeMap {
+ private final int functionNodeId;
+ private final Type[] paramTypes;
+ private final Type returnType;
private final boolean needsCallee;
/**
@@ -56,9 +53,10 @@
for (final Class<?> p : type.parameterArray()) {
types[pos++] = Type.typeFor(p);
}
- paramTypeMap.put(functionNodeId, types);
- returnTypeMap.put(functionNodeId, Type.typeFor(type.returnType()));
+ this.functionNodeId = functionNodeId;
+ this.paramTypes = types;
+ this.returnType = Type.typeFor(type.returnType());
this.needsCallee = needsCallee;
}
@@ -69,20 +67,14 @@
* @throws NoSuchElementException if the type map has no mapping for the requested function
*/
public Type[] getParameterTypes(final int functionNodeId) {
- final Type[] paramTypes = paramTypeMap.get(functionNodeId);
- if (paramTypes == null) {
- throw new NoSuchElementException(Integer.toString(functionNodeId));
- }
+ assert this.functionNodeId == functionNodeId;
return paramTypes.clone();
}
MethodType getCallSiteType(final FunctionNode functionNode) {
- final Type[] types = paramTypeMap.get(functionNode.getId());
- if (types == null) {
- return null;
- }
-
- MethodType mt = MethodType.methodType(returnTypeMap.get(functionNode.getId()).getTypeClass());
+ assert this.functionNodeId == functionNode.getId();
+ final Type[] types = paramTypes;
+ MethodType mt = MethodType.methodType(returnType.getTypeClass());
if (needsCallee) {
mt = mt.appendParameterTypes(ScriptFunction.class);
}
@@ -116,7 +108,8 @@
* @return parameter type for this callsite if known
*/
Type get(final FunctionNode functionNode, final int pos) {
- final Type[] types = paramTypeMap.get(functionNode.getId());
+ assert this.functionNodeId == functionNode.getId();
+ final Type[] types = paramTypes;
assert types == null || pos < types.length : "fn = " + functionNode.getId() + " " + "types=" + Arrays.toString(types) + " || pos=" + pos + " >= length=" + types.length + " in " + this;
if (types != null && pos < types.length) {
return types[pos];
@@ -124,13 +117,6 @@
return null;
}
- boolean has(final FunctionNode functionNode) {
- final int id = functionNode.getId();
- final Type[] paramTypes = paramTypeMap.get(id);
- assert (paramTypes == null) == (returnTypeMap.get(id) == null) : "inconsistent param and return types in param map";
- return paramTypes != null;
- }
-
@Override
public String toString() {
return toString("");
@@ -139,27 +125,16 @@
String toString(final String prefix) {
final StringBuilder sb = new StringBuilder();
- if (paramTypeMap.isEmpty()) {
- sb.append(prefix).append("\t<empty>");
- return sb.toString();
- }
-
- for (final Map.Entry<Integer, Type[]> entry : paramTypeMap.entrySet()) {
- final int id = entry.getKey();
- sb.append(prefix).append('\t');
- sb.append("function ").append(id).append('\n');
- sb.append(prefix).append("\t\tparamTypes=");
- if (entry.getValue() == null) {
- sb.append("[]");
- } else {
- sb.append(Arrays.toString(entry.getValue()));
- }
- sb.append('\n');
- sb.append(prefix).append("\t\treturnType=");
- final Type ret = returnTypeMap.get(id);
- sb.append(ret == null ? "N/A" : ret);
- sb.append('\n');
- }
+ final int id = functionNodeId;
+ sb.append(prefix).append('\t');
+ sb.append("function ").append(id).append('\n');
+ sb.append(prefix).append("\t\tparamTypes=");
+ sb.append(Arrays.toString(paramTypes));
+ sb.append('\n');
+ sb.append(prefix).append("\t\treturnType=");
+ final Type ret = returnType;
+ sb.append(ret == null ? "N/A" : ret);
+ sb.append('\n');
return sb.toString();
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
index b1181c8..494afb4 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java
@@ -44,12 +44,13 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
-import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
+import jdk.nashorn.internal.ir.Splittable;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode;
@@ -88,6 +89,8 @@
static final long THROW_WEIGHT = 2;
static final long VAR_WEIGHT = 40;
static final long WITH_WEIGHT = 8;
+ static final long OBJECT_WEIGHT = 16;
+ static final long SETPROP_WEIGHT = 5;
/** Accumulated weight. */
private long weight;
@@ -213,7 +216,7 @@
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] value = arrayLiteralNode.getValue();
final int[] postsets = arrayLiteralNode.getPostsets();
- final List<ArrayUnit> units = arrayLiteralNode.getUnits();
+ final List<Splittable.SplitRange> units = arrayLiteralNode.getSplitRanges();
if (units == null) {
for (final int postset : postsets) {
@@ -233,6 +236,27 @@
}
@Override
+ public boolean enterObjectNode(final ObjectNode objectNode) {
+ weight += OBJECT_WEIGHT;
+ final List<PropertyNode> properties = objectNode.getElements();
+ final boolean isSpillObject = properties.size() > CodeGenerator.OBJECT_SPILL_THRESHOLD;
+
+ for (final PropertyNode property : properties) {
+ if (!LiteralNode.isConstant(property.getValue())) {
+ weight += SETPROP_WEIGHT;
+ property.getValue().accept(this);
+ } else if (!isSpillObject) {
+ // constants in spill object are set via preset spill array,
+ // but fields objects need to set constants.
+ weight += SETPROP_WEIGHT;
+ }
+
+ }
+
+ return false;
+ }
+
+ @Override
public Node leavePropertyNode(final PropertyNode propertyNode) {
weight += LITERAL_WEIGHT;
return propertyNode;
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java b/nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java
index 1cfb757..31e4bb6 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/BytecodeOps.java
@@ -36,7 +36,7 @@
* The bytecode ops are coupled to a MethodVisitor from ASM for
* byte code generation. They know nothing about our MethodGenerator,
* which is the abstraction for working with Nashorn JS types
- * For exmaple, anything like "two or one slots" for a type, which
+ * For example, anything like "two or one slots" for a type, which
* is represented in bytecode and ASM, is abstracted away in the
* MethodGenerator. There you just say "dup" or "store".
*
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
index 2cf2d9b..cf53c66 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/nashorn/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -65,6 +65,7 @@
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Undefined;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
@@ -256,6 +257,9 @@
case jdk.internal.org.objectweb.asm.Type.DOUBLE:
return NUMBER;
case jdk.internal.org.objectweb.asm.Type.OBJECT:
+ if (Context.isStructureClass(itype.getClassName())) {
+ return SCRIPT_OBJECT;
+ }
try {
return Type.typeFor(Class.forName(itype.getClassName()));
} catch(final ClassNotFoundException e) {
@@ -949,7 +953,7 @@
/**
* This is the singleton for integer arrays
*/
- public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
+ public static final ArrayType INT_ARRAY = putInCache(new ArrayType(int[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -973,12 +977,12 @@
public Type getElementType() {
return INT;
}
- };
+ });
/**
* This is the singleton for long arrays
*/
- public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
+ public static final ArrayType LONG_ARRAY = putInCache(new ArrayType(long[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -1002,12 +1006,12 @@
public Type getElementType() {
return LONG;
}
- };
+ });
/**
* This is the singleton for numeric arrays
*/
- public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
+ public static final ArrayType NUMBER_ARRAY = putInCache(new ArrayType(double[].class) {
private static final long serialVersionUID = 1L;
@Override
@@ -1031,13 +1035,7 @@
public Type getElementType() {
return NUMBER;
}
- };
-
- /** Singleton for method handle arrays used for properties etc. */
- public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
-
- /** This is the singleton for string arrays */
- public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
+ });
/** This is the singleton for object arrays */
public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
diff --git a/nashorn/src/jdk/nashorn/internal/ir/Block.java b/nashorn/src/jdk/nashorn/internal/ir/Block.java
index ddb6699..1647a92 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/Block.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java
@@ -130,11 +130,42 @@
}
/**
- * Clear the symbols in the block.
- * TODO: make this immutable.
+ * Returns true if this block defines any symbols.
+ * @return true if this block defines any symbols.
*/
- public void clearSymbols() {
- symbols.clear();
+ public boolean hasSymbols() {
+ return !symbols.isEmpty();
+ }
+
+ /**
+ * Replaces symbols defined in this block with different symbols. Used to ensure symbol tables are
+ * immutable upon construction and have copy-on-write semantics. Note that this method only replaces the
+ * symbols in the symbol table, it does not act on any contained AST nodes that might reference the symbols.
+ * Those should be updated separately as this method is meant to be used as part of such an update pass.
+ * @param lc the current lexical context
+ * @param replacements the map of symbol replacements
+ * @return a new block with replaced symbols, or this block if none of the replacements modified the symbol
+ * table.
+ */
+ public Block replaceSymbols(final LexicalContext lc, final Map<Symbol, Symbol> replacements) {
+ if (symbols.isEmpty()) {
+ return this;
+ }
+ final LinkedHashMap<String, Symbol> newSymbols = new LinkedHashMap<>(symbols);
+ for (final Map.Entry<String, Symbol> entry: newSymbols.entrySet()) {
+ final Symbol newSymbol = replacements.get(entry.getValue());
+ assert newSymbol != null : "Missing replacement for " + entry.getKey();
+ entry.setValue(newSymbol);
+ }
+ return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, newSymbols, conversion));
+ }
+
+ /**
+ * Returns a copy of this block with a shallow copy of the symbol table.
+ * @return a copy of this block with a shallow copy of the symbol table.
+ */
+ public Block copyWithNewSymbols() {
+ return new Block(this, finish, statements, flags, new LinkedHashMap<>(symbols), conversion);
}
@Override
@@ -162,7 +193,7 @@
* @return symbol iterator
*/
public List<Symbol> getSymbols() {
- return Collections.unmodifiableList(new ArrayList<>(symbols.values()));
+ return symbols.isEmpty() ? Collections.<Symbol>emptyList() : Collections.unmodifiableList(new ArrayList<>(symbols.values()));
}
/**
@@ -326,10 +357,9 @@
/**
* Add or overwrite an existing symbol in the block
*
- * @param lc get lexical context
* @param symbol symbol
*/
- public void putSymbol(final LexicalContext lc, final Symbol symbol) {
+ public void putSymbol(final Symbol symbol) {
symbols.put(symbol.getName(), symbol);
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
index 0deb25f..1848d2a 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/BlockLexicalContext.java
@@ -34,7 +34,7 @@
* This is a subclass of lexical context used for filling
* blocks (and function nodes) with statements. When popping
* a block from the lexical context, any statements that have
- * been generated in it are commited to the block. This saves
+ * been generated in it are committed to the block. This saves
* unnecessary object mutations and lexical context replacement
*/
public class BlockLexicalContext extends LexicalContext {
diff --git a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java
index ef6f11d..d244bba 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java
@@ -43,7 +43,7 @@
private final JoinPredecessorExpression modify;
/** Iterator symbol. */
- private Symbol iterator;
+ private final Symbol iterator;
/** Is this a normal for in loop? */
public static final int IS_FOR_IN = 1 << 0;
@@ -70,22 +70,22 @@
this.flags = flags;
this.init = null;
this.modify = null;
+ this.iterator = null;
}
private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
- final Block body, final JoinPredecessorExpression modify, final int flags, final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
+ final Block body, final JoinPredecessorExpression modify, final int flags,
+ final boolean controlFlowEscapes, final LocalVariableConversion conversion, final Symbol iterator) {
super(forNode, test, body, controlFlowEscapes, conversion);
this.init = init;
this.modify = modify;
this.flags = flags;
- // Even if the for node gets cloned in try/finally, the symbol can be shared as only one branch of the finally
- // is executed.
- this.iterator = forNode.iterator;
+ this.iterator = iterator;
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -158,7 +158,7 @@
if (this.init == init) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
/**
@@ -206,10 +206,15 @@
/**
* Assign an iterator symbol to this ForNode. Used for for in and for each constructs
+ * @param lc the current lexical context
* @param iterator the iterator symbol
+ * @return a ForNode with the iterator set
*/
- public void setIterator(final Symbol iterator) {
- this.iterator = iterator;
+ public ForNode setIterator(final LexicalContext lc, final Symbol iterator) {
+ if (this.iterator == iterator) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
/**
@@ -230,7 +235,7 @@
if (this.modify == modify) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -238,7 +243,7 @@
if (this.test == test) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -251,7 +256,7 @@
if (this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
@@ -259,19 +264,19 @@
if (this.controlFlowEscapes == controlFlowEscapes) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
private ForNode setFlags(final LexicalContext lc, final int flags) {
if (this.flags == flags) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
- return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion));
+ return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes, conversion, iterator));
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
index 70f9ebc..02bf160 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -33,10 +33,8 @@
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
import java.util.Collections;
-import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
-import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
@@ -73,40 +71,6 @@
SETTER
}
- /** Compilation states available */
- public enum CompilationState {
- /** compiler is ready */
- INITIALIZED,
- /** method has been parsed */
- PARSED,
- /** method has been parsed */
- PARSE_ERROR,
- /** constant folding pass */
- CONSTANT_FOLDED,
- /** method has been lowered */
- LOWERED,
- /** program points have been assigned to unique locations */
- PROGRAM_POINTS_ASSIGNED,
- /** any transformations of builtins have taken place, e.g. apply=>call */
- BUILTINS_TRANSFORMED,
- /** method has been split */
- SPLIT,
- /** method has had symbols assigned */
- SYMBOLS_ASSIGNED,
- /** computed scope depths for symbols */
- SCOPE_DEPTHS_COMPUTED,
- /** method has had types calculated*/
- OPTIMISTIC_TYPES_ASSIGNED,
- /** method has had types calculated */
- LOCAL_VARIABLE_TYPES_CALCULATED,
- /** compile units reused (optional) */
- COMPILE_UNITS_REUSED,
- /** method has been emitted to bytecode */
- BYTECODE_GENERATED,
- /** method has been installed */
- BYTECODE_INSTALLED
- }
-
/** Source of entity. */
private transient final Source source;
@@ -144,10 +108,6 @@
/** Method's namespace. */
private transient final Namespace namespace;
- /** Current compilation state */
- @Ignore
- private final EnumSet<CompilationState> compilationState;
-
/** Number of properties of "this" object assigned in this function */
@Ignore
private final int thisProperties;
@@ -263,6 +223,11 @@
*/
public static final int NEEDS_CALLEE = 1 << 26;
+ /**
+ * Is the function node cached?
+ */
+ public static final int IS_CACHED = 1 << 27;
+
/** extension callsite flags mask */
public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
@@ -322,7 +287,6 @@
this.firstToken = firstToken;
this.lastToken = token;
this.namespace = namespace;
- this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.flags = flags;
this.compileUnit = null;
this.body = null;
@@ -339,12 +303,11 @@
final String name,
final Type returnType,
final CompileUnit compileUnit,
- final EnumSet<CompilationState> compilationState,
final Block body,
final List<IdentNode> parameters,
final int thisProperties,
final Class<?> rootClass,
- final Source source, Namespace namespace) {
+ final Source source, final Namespace namespace) {
super(functionNode);
this.endParserState = endParserState;
@@ -354,7 +317,6 @@
this.returnType = returnType;
this.compileUnit = compileUnit;
this.lastToken = lastToken;
- this.compilationState = compilationState;
this.body = body;
this.parameters = parameters;
this.thisProperties = thisProperties;
@@ -454,7 +416,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -530,80 +491,6 @@
}
/**
- * Get the compilation state of this function
- * @return the compilation state
- */
- public EnumSet<CompilationState> getState() {
- return compilationState;
- }
-
- /**
- * Check whether this FunctionNode has reached a give CompilationState.
- *
- * @param state the state to check for
- * @return true of the node is in the given state
- */
- public boolean hasState(final EnumSet<CompilationState> state) {
- return !AssertsEnabled.assertsEnabled() || compilationState.containsAll(state);
- }
-
- /**
- * Add a state to the total CompilationState of this node, e.g. if
- * FunctionNode has been lowered, the compiler will add
- * {@code CompilationState#LOWERED} to the state vector
- *
- * @param lc lexical context
- * @param state {@link CompilationState} to add
- * @return function node or a new one if state was changed
- */
- public FunctionNode setState(final LexicalContext lc, final CompilationState state) {
- if (!AssertsEnabled.assertsEnabled() || this.compilationState.contains(state)) {
- return this;
- }
- final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
- newState.add(state);
- return setCompilationState(lc, newState);
- }
-
- /**
- * Copy a compilation state from an original function to this function. Used when creating synthetic
- * function nodes by the splitter.
- *
- * @param lc lexical context
- * @param original the original function node to copy compilation state from
- * @return function node or a new one if state was changed
- */
- public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
- final EnumSet<CompilationState> origState = original.compilationState;
- if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
- return this;
- }
- final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
- newState.addAll(origState);
- return setCompilationState(lc, newState);
- }
-
- private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
- return Node.replaceInLexicalContext(
- lc,
- this,
- new FunctionNode(
- this,
- lastToken,
- endParserState,
- flags,
- name,
- returnType,
- compileUnit,
- compilationState,
- body,
- parameters,
- thisProperties,
- rootClass, source, namespace));
- }
-
-
- /**
* Create a unique name in the namespace of this FunctionNode
* @param base prefix for name
* @return base if no collision exists, otherwise a name prefix with base
@@ -668,7 +555,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -748,7 +634,7 @@
*/
public boolean needsCallee() {
// NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
- return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
+ return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasApplyToCallSpecialization();
}
/**
@@ -765,7 +651,7 @@
* Return true if function contains an apply to call transform
* @return true if this function has transformed apply to call
*/
- public boolean hasOptimisticApplyToCall() {
+ public boolean hasApplyToCallSpecialization() {
return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
}
@@ -809,7 +695,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -905,7 +790,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -966,7 +850,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1002,7 +885,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1040,7 +922,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1077,6 +958,14 @@
}
/**
+ * Return the number of parameters to this function
+ * @return the number of parameters
+ */
+ public int getNumOfParams() {
+ return parameters.size();
+ }
+
+ /**
* Returns the identifier for a named parameter at the specified position in this function's parameter list.
* @param index the parameter's position.
* @return the identifier for the requested named parameter.
@@ -1108,7 +997,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1196,7 +1084,6 @@
name,
type,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1213,6 +1100,24 @@
}
/**
+ * Returns true if this function node has been cached.
+ * @return true if this function node has been cached.
+ */
+ public boolean isCached() {
+ return getFlag(IS_CACHED);
+ }
+
+ /**
+ * Mark this function node as having been cached.
+ * @param lc the current lexical context
+ * @return a function node equivalent to this one, with the flag set.
+ */
+ public FunctionNode setCached(final LexicalContext lc) {
+ return setFlag(lc, IS_CACHED);
+ }
+
+
+ /**
* Get the compile unit used to compile this function
* @see Compiler
* @return the compile unit
@@ -1244,7 +1149,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
@@ -1300,7 +1204,6 @@
name,
returnType,
compileUnit,
- compilationState,
body,
parameters,
thisProperties,
diff --git a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java
index f2a9003..1f77570 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java
@@ -25,11 +25,9 @@
package jdk.nashorn.internal.ir;
-import java.io.Serializable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -430,7 +428,7 @@
*
* @param token token
* @param finish finish
- * @param value undefined value, passed only for polymorphisism discrimination
+ * @param value undefined value, passed only for polymorphism discrimination
*
* @return the new literal node
*/
@@ -561,6 +559,15 @@
return POSTSET_MARKER;
}
+ /**
+ * Test whether {@code object} represents a constant value.
+ * @param object a node or value object
+ * @return true if object is a constant value
+ */
+ public static boolean isConstant(final Object object) {
+ return objectAsConstant(object) != POSTSET_MARKER;
+ }
+
private static final class NullLiteralNode extends PrimitiveLiteralNode<Object> {
private static final long serialVersionUID = 1L;
@@ -592,7 +599,7 @@
* Array literal node class.
*/
@Immutable
- public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode {
+ public static final class ArrayLiteralNode extends LiteralNode<Expression[]> implements LexicalContextNode, Splittable {
private static final long serialVersionUID = 1L;
/** Array element type. */
@@ -604,59 +611,8 @@
/** Indices of array elements requiring computed post sets. */
private final int[] postsets;
- /** Sub units with indexes ranges, in which to split up code generation, for large literals */
- private final List<ArrayUnit> units;
-
- /**
- * An ArrayUnit is a range in an ArrayLiteral. ArrayLiterals can
- * be split if they are too large, for bytecode generation reasons
- */
- public static final class ArrayUnit implements CompileUnitHolder, Serializable {
- private static final long serialVersionUID = 1L;
-
- /** Compile unit associated with the postsets range. */
- private final CompileUnit compileUnit;
-
- /** postsets range associated with the unit (hi not inclusive). */
- private final int lo, hi;
-
- /**
- * Constructor
- * @param compileUnit compile unit
- * @param lo lowest array index in unit
- * @param hi highest array index in unit + 1
- */
- public ArrayUnit(final CompileUnit compileUnit, final int lo, final int hi) {
- this.compileUnit = compileUnit;
- this.lo = lo;
- this.hi = hi;
- }
-
- /**
- * Get the high index position of the ArrayUnit (non inclusive)
- * @return high index position
- */
- public int getHi() {
- return hi;
- }
-
- /**
- * Get the low index position of the ArrayUnit (inclusive)
- * @return low index position
- */
- public int getLo() {
- return lo;
- }
-
- /**
- * The array compile unit
- * @return array compile unit
- */
- @Override
- public CompileUnit getCompileUnit() {
- return compileUnit;
- }
- }
+ /** Ranges for splitting up large literals in code generation */
+ private final List<Splittable.SplitRange> splitRanges;
private static final class ArrayLiteralInitializer {
@@ -664,7 +620,7 @@
final Type elementType = computeElementType(node.value);
final int[] postsets = computePostsets(node.value);
final Object presets = computePresets(node.value, elementType, postsets);
- return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.units);
+ return new ArrayLiteralNode(node, node.value, elementType, postsets, presets, node.splitRanges);
}
private static Type computeElementType(final Expression[] value) {
@@ -697,7 +653,7 @@
for (int i = 0; i < value.length; i++) {
final Expression element = value[i];
- if (element == null || objectAsConstant(element) == POSTSET_MARKER) {
+ if (element == null || !isConstant(element)) {
computed[nComputed++] = i;
}
}
@@ -814,19 +770,19 @@
this.elementType = Type.UNKNOWN;
this.presets = null;
this.postsets = null;
- this.units = null;
+ this.splitRanges = null;
}
/**
* Copy constructor
* @param node source array literal node
*/
- private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<ArrayUnit> units) {
+ private ArrayLiteralNode(final ArrayLiteralNode node, final Expression[] value, final Type elementType, final int[] postsets, final Object presets, final List<Splittable.SplitRange> splitRanges) {
super(node, value);
this.elementType = elementType;
this.postsets = postsets;
this.presets = presets;
- this.units = units;
+ this.splitRanges = splitRanges;
}
/**
@@ -917,26 +873,27 @@
}
/**
- * Get the array units that make up this ArrayLiteral
- * @see ArrayUnit
- * @return list of array units
+ * Get the split ranges for this ArrayLiteral, or null if this array does not have to be split.
+ * @see Splittable.SplitRange
+ * @return list of split ranges
*/
- public List<ArrayUnit> getUnits() {
- return units == null ? null : Collections.unmodifiableList(units);
+ @Override
+ public List<Splittable.SplitRange> getSplitRanges() {
+ return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
}
/**
- * Set the ArrayUnits that make up this ArrayLiteral
+ * Set the SplitRanges that make up this ArrayLiteral
* @param lc lexical context
- * @see ArrayUnit
- * @param units list of array units
- * @return new or changed arrayliteralnode
+ * @see Splittable.SplitRange
+ * @param splitRanges list of split ranges
+ * @return new or changed node
*/
- public ArrayLiteralNode setUnits(final LexicalContext lc, final List<ArrayUnit> units) {
- if (this.units == units) {
+ public ArrayLiteralNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+ if (this.splitRanges == splitRanges) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+ return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
}
@Override
@@ -958,7 +915,7 @@
if (this.value == value) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, units));
+ return Node.replaceInLexicalContext(lc, this, new ArrayLiteralNode(this, value, elementType, postsets, presets, splitRanges));
}
private ArrayLiteralNode setValue(final LexicalContext lc, final List<Expression> value) {
diff --git a/nashorn/src/jdk/nashorn/internal/ir/Node.java b/nashorn/src/jdk/nashorn/internal/ir/Node.java
index 0f96e8d..7762a1f 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/Node.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java
@@ -129,9 +129,17 @@
public abstract Node accept(NodeVisitor<? extends LexicalContext> visitor);
@Override
- public String toString() {
+ public final String toString() {
+ return toString(true);
+ }
+
+ /*
+ * Return String representation of this Node.
+ * @param includeTypeInfo include type information or not
+ */
+ public final String toString(final boolean includeTypeInfo) {
final StringBuilder sb = new StringBuilder();
- toString(sb);
+ toString(sb, includeTypeInfo);
return sb.toString();
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java
index 31ddc1c..81e333c 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java
@@ -27,6 +27,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.RandomAccess;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -35,12 +36,15 @@
* IR representation of an object literal.
*/
@Immutable
-public final class ObjectNode extends Expression {
+public final class ObjectNode extends Expression implements LexicalContextNode, Splittable {
private static final long serialVersionUID = 1L;
/** Literal elements. */
private final List<PropertyNode> elements;
+ /** Ranges for splitting large literals over multiple compile units in codegen. */
+ private final List<Splittable.SplitRange> splitRanges;
+
/**
* Constructor
*
@@ -51,19 +55,27 @@
public ObjectNode(final long token, final int finish, final List<PropertyNode> elements) {
super(token, finish);
this.elements = elements;
+ this.splitRanges = null;
+ assert elements instanceof RandomAccess : "Splitting requires random access lists";
}
- private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements) {
+ private ObjectNode(final ObjectNode objectNode, final List<PropertyNode> elements,
+ final List<Splittable.SplitRange> splitRanges ) {
super(objectNode);
this.elements = elements;
+ this.splitRanges = splitRanges;
}
@Override
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
- if (visitor.enterObjectNode(this)) {
- return visitor.leaveObjectNode(setElements(Node.accept(visitor, elements)));
- }
+ return Acceptor.accept(this, visitor);
+ }
+ @Override
+ public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
+ if (visitor.enterObjectNode(this)) {
+ return visitor.leaveObjectNode(setElements(lc, Node.accept(visitor, elements)));
+ }
return this;
}
@@ -102,10 +114,35 @@
return Collections.unmodifiableList(elements);
}
- private ObjectNode setElements(final List<PropertyNode> elements) {
+ private ObjectNode setElements(final LexicalContext lc, final List<PropertyNode> elements) {
if (this.elements == elements) {
return this;
}
- return new ObjectNode(this, elements);
+ return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, this.splitRanges));
}
+
+ /**
+ * Set the split ranges for this ObjectNode
+ * @see Splittable.SplitRange
+ * @param lc the lexical context
+ * @param splitRanges list of split ranges
+ * @return new or changed object node
+ */
+ public ObjectNode setSplitRanges(final LexicalContext lc, final List<Splittable.SplitRange> splitRanges) {
+ if (this.splitRanges == splitRanges) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new ObjectNode(this, elements, splitRanges));
+ }
+
+ /**
+ * Get the split ranges for this ObjectNode, or null if the object is not split.
+ * @see Splittable.SplitRange
+ * @return list of split ranges
+ */
+ @Override
+ public List<Splittable.SplitRange> getSplitRanges() {
+ return splitRanges == null ? null : Collections.unmodifiableList(splitRanges);
+ }
+
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java
index bcece01..f372b7f 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java
@@ -56,6 +56,8 @@
REFERENCE_ERROR,
/** Delete operator */
DELETE(TokenType.DELETE, Type.BOOLEAN, 1),
+ /** Delete operator for slow scopes */
+ SLOW_DELETE(TokenType.DELETE, Type.BOOLEAN, 1, false),
/** Delete operator that always fails -- see Lower */
FAIL_DELETE(TokenType.DELETE, Type.BOOLEAN, 1, false),
/** === operator with at least one object */
@@ -274,7 +276,7 @@
*
* @param request a request
*
- * @return the inverted rquest, or null if not applicable
+ * @return the inverted request, or null if not applicable
*/
public static Request invert(final Request request) {
switch (request) {
diff --git a/nashorn/src/jdk/nashorn/internal/ir/Splittable.java b/nashorn/src/jdk/nashorn/internal/ir/Splittable.java
new file mode 100644
index 0000000..d331171
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/ir/Splittable.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.io.Serializable;
+import java.util.List;
+import jdk.nashorn.internal.codegen.CompileUnit;
+
+/**
+ * An interface for splittable expressions.
+ */
+public interface Splittable {
+
+ /**
+ * Get a list of split ranges for this splittable expression, or null
+ * if the expression should not be split.
+ *
+ * @return a list of split ranges
+ */
+ List<SplitRange> getSplitRanges();
+
+ /**
+ * A SplitRange is a range in a splittable expression. It defines the
+ * boundaries of the split range and provides a compile unit for code generation.
+ */
+ final class SplitRange implements CompileUnitHolder, Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** Compile unit associated with the postsets range. */
+ private final CompileUnit compileUnit;
+
+ /** postsets range associated with the unit (hi not inclusive). */
+ private final int low, high;
+
+ /**
+ * Constructor
+ * @param compileUnit compile unit
+ * @param low lowest array index in unit
+ * @param high highest array index in unit + 1
+ */
+ public SplitRange(final CompileUnit compileUnit, final int low, final int high) {
+ this.compileUnit = compileUnit;
+ this.low = low;
+ this.high = high;
+ }
+
+ /**
+ * Get the high index position of the ArrayUnit (exclusive)
+ * @return high index position
+ */
+ public int getHigh() {
+ return high;
+ }
+
+ /**
+ * Get the low index position of the ArrayUnit (inclusive)
+ * @return low index position
+ */
+ public int getLow() {
+ return low;
+ }
+
+ /**
+ * The array compile unit
+ * @return array compile unit
+ */
+ @Override
+ public CompileUnit getCompileUnit() {
+ return compileUnit;
+ }
+ }
+}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java
index ca44758..4f25151 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java
@@ -53,7 +53,7 @@
private final boolean uniqueInteger;
/** Tag symbol. */
- private Symbol tag;
+ private final Symbol tag;
/**
* Constructor
@@ -71,15 +71,16 @@
this.cases = cases;
this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase);
this.uniqueInteger = false;
+ this.tag = null;
}
private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases,
- final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) {
+ final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger, final Symbol tag) {
super(switchNode, conversion);
this.expression = expression;
this.cases = cases;
this.defaultCaseIndex = defaultCaseIndex;
- this.tag = switchNode.getTag(); //TODO are symbols inherited as references?
+ this.tag = tag;
this.uniqueInteger = uniqueInteger;
}
@@ -89,7 +90,7 @@
for (final CaseNode caseNode : cases) {
newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion()));
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
@Override
@@ -157,7 +158,7 @@
if (this.cases == cases) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -189,7 +190,7 @@
if (this.expression == expression) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -204,10 +205,15 @@
/**
* Set the tag symbol for this switch. The tag symbol is where
* the switch expression result is stored
+ * @param lc lexical context
* @param tag a symbol
+ * @return a switch node with the symbol set
*/
- public void setTag(final Symbol tag) {
- this.tag = tag;
+ public SwitchNode setTag(final LexicalContext lc, final Symbol tag) {
+ if (this.tag == tag) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
/**
@@ -229,12 +235,12 @@
if(this.uniqueInteger == uniqueInteger) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
@Override
JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) {
- return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger));
+ return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger, tag));
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java
index d4ccd45..c33a4ba 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java
@@ -25,7 +25,10 @@
package jdk.nashorn.internal.ir;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.PrintWriter;
+import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
@@ -47,7 +50,9 @@
* refer to their location.
*/
-public final class Symbol implements Comparable<Symbol> {
+public final class Symbol implements Comparable<Symbol>, Cloneable, Serializable {
+ private static final long serialVersionUID = 1L;
+
/** Is this Global */
public static final int IS_GLOBAL = 1;
/** Is this a variable */
@@ -94,10 +99,10 @@
/** First bytecode method local variable slot for storing the value(s) of this variable. -1 indicates the variable
* is not stored in local variable slots or it is not yet known. */
- private int firstSlot = -1;
+ private transient int firstSlot = -1;
/** Field number in scope or property; array index in varargs when not using arguments object. */
- private int fieldIndex = -1;
+ private transient int fieldIndex = -1;
/** Number of times this symbol is used in code */
private int useCount;
@@ -144,6 +149,15 @@
}
}
+ @Override
+ public Symbol clone() {
+ try {
+ return (Symbol)super.clone();
+ } catch (final CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
+ }
+
private static String align(final String string, final int max) {
final StringBuilder sb = new StringBuilder();
sb.append(string.substring(0, Math.min(string.length(), max)));
@@ -337,7 +351,7 @@
* Flag this symbol as scope as described in {@link Symbol#isScope()}
* @return the symbol
*/
- public Symbol setIsScope() {
+ public Symbol setIsScope() {
if (!isScope()) {
if(shouldTrace()) {
trace("SET IS SCOPE");
@@ -609,11 +623,11 @@
/**
* Increase the symbol's use count by one.
- * @return the symbol
*/
- public Symbol increaseUseCount() {
- useCount++;
- return this;
+ public void increaseUseCount() {
+ if (isScope()) { // Avoid dirtying a cache line; we only need the use count for scoped symbols
+ useCount++;
+ }
}
/**
@@ -669,4 +683,10 @@
new Throwable().printStackTrace(Context.getCurrentErr());
}
}
+
+ private void readObject(final ObjectInputStream in) throws ClassNotFoundException, IOException {
+ in.defaultReadObject();
+ firstSlot = -1;
+ fieldIndex = -1;
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java
index 143428e..661281e 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java
@@ -65,7 +65,7 @@
private final List<Block> inlinedFinallies;
/** Exception symbol. */
- private Symbol exception;
+ private final Symbol exception;
private final LocalVariableConversion conversion;
@@ -86,22 +86,23 @@
this.finallyBody = finallyBody;
this.conversion = null;
this.inlinedFinallies = Collections.emptyList();
+ this.exception = null;
}
- private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies) {
+ private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody, final LocalVariableConversion conversion, final List<Block> inlinedFinallies, final Symbol exception) {
super(tryNode);
this.body = body;
this.catchBlocks = catchBlocks;
this.finallyBody = finallyBody;
this.conversion = conversion;
this.inlinedFinallies = inlinedFinallies;
- this.exception = tryNode.exception;
+ this.exception = exception;
}
@Override
public Node ensureUniqueLabels(final LexicalContext lc) {
//try nodes are never in lex context
- return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
}
@Override
@@ -160,7 +161,7 @@
if (this.body == body) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -197,7 +198,7 @@
if (this.catchBlocks == catchBlocks) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -209,12 +210,15 @@
}
/**
* Set the exception symbol for this try block
+ * @param lc lexical context
* @param exception a symbol for the compiler to store the exception in
* @return new TryNode or same if unchanged
*/
- public TryNode setException(final Symbol exception) {
- this.exception = exception;
- return this;
+ public TryNode setException(final LexicalContext lc, final Symbol exception) {
+ if (this.exception == exception) {
+ return this;
+ }
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -277,7 +281,7 @@
if (this.finallyBody == finallyBody) {
return this;
}
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
/**
@@ -293,7 +297,7 @@
return this;
}
assert checkInlinedFinallies(inlinedFinallies);
- return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies));
+ return Node.replaceInLexicalContext(lc, this, new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception));
}
private static boolean checkInlinedFinallies(final List<Block> inlinedFinallies) {
@@ -314,7 +318,7 @@
if(this.conversion == conversion) {
return this;
}
- return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies);
+ return new TryNode(this, body, catchBlocks, finallyBody, conversion, inlinedFinallies, exception);
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java
index ec91261..17e6467f 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java
@@ -262,12 +262,4 @@
public boolean isFunctionDeclaration() {
return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
}
-
- /**
- * Returns true if this is an anonymous function declaration.
- * @return true if this is an anonymous function declaration.
- */
- public boolean isAnonymousFunctionDeclaration() {
- return isFunctionDeclaration() && ((FunctionNode)init).isAnonymous();
- }
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
index 9cee46f..b72d899 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java
@@ -48,7 +48,6 @@
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
@@ -65,7 +64,7 @@
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.parser.JSONParser;
import jdk.nashorn.internal.parser.Lexer.RegexToken;
import jdk.nashorn.internal.parser.Parser;
@@ -77,7 +76,7 @@
/**
* This IR writer produces a JSON string that represents AST as a JSON string.
*/
-public final class JSONWriter extends NodeVisitor<LexicalContext> {
+public final class JSONWriter extends SimpleNodeVisitor {
/**
* Returns AST as JSON compatible string.
@@ -939,7 +938,6 @@
// Internals below
private JSONWriter(final boolean includeLocation) {
- super(new LexicalContext());
this.buf = new StringBuilder();
this.includeLocation = includeLocation;
}
diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java b/nashorn/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
index 87eb18d..26d4dc9 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
@@ -36,7 +36,7 @@
import jdk.nashorn.internal.ir.debug.NashornTextifier.NashornLabel;
/**
- * Subclass of the ASM classs reader that retains more info, such
+ * Subclass of the ASM class reader that retains more info, such
* as bytecode offsets
*/
public class NashornClassReader extends ClassReader {
diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java b/nashorn/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
index 54fcc59..24ef303 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/ObjectSizeCalculator.java
@@ -193,7 +193,7 @@
}
/**
- * Get the class histograpm
+ * Get the class histogram
* @return class histogram element list
*/
public List<ClassHistogramElement> getClassHistogram() {
diff --git a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index 47fc044..bb8d61a 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -41,7 +41,6 @@
import jdk.nashorn.internal.ir.JoinPredecessor;
import jdk.nashorn.internal.ir.JoinPredecessorExpression;
import jdk.nashorn.internal.ir.LabelNode;
-import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.SplitNode;
@@ -53,7 +52,7 @@
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
/**
* Print out the AST as human readable source code.
@@ -61,7 +60,7 @@
*
* see the flags --print-parse and --print-lower-parse
*/
-public final class PrintVisitor extends NodeVisitor<LexicalContext> {
+public final class PrintVisitor extends SimpleNodeVisitor {
/** Tab width */
private static final int TABWIDTH = 4;
@@ -96,7 +95,6 @@
* @param printTypes should we print optimistic and inferred types?
*/
public PrintVisitor(final boolean printLineNumbers, final boolean printTypes) {
- super(new LexicalContext());
this.EOLN = System.lineSeparator();
this.sb = new StringBuilder();
this.printLineNumbers = printLineNumbers;
diff --git a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 1582f30..9badcf6 100644
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -34,7 +34,7 @@
* Like NodeVisitor but navigating further into operators.
* @param <T> Lexical context class for this NodeOperatorVisitor
*/
-public class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T> {
+public abstract class NodeOperatorVisitor<T extends LexicalContext> extends NodeVisitor<T> {
/**
* Constructor
*
diff --git a/nashorn/src/jdk/nashorn/internal/ir/visitor/SimpleNodeVisitor.java b/nashorn/src/jdk/nashorn/internal/ir/visitor/SimpleNodeVisitor.java
new file mode 100644
index 0000000..015e1fe
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/SimpleNodeVisitor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir.visitor;
+
+import jdk.nashorn.internal.ir.LexicalContext;
+
+/**
+ * Convenience base class for a {@link NodeVisitor} with a plain {@link LexicalContext}.
+ */
+public abstract class SimpleNodeVisitor extends NodeVisitor<LexicalContext> {
+
+ /**
+ * Creates a new simple node visitor.
+ */
+ public SimpleNodeVisitor() {
+ super(new LexicalContext());
+ }
+}
diff --git a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
index 77f41ae..2dcc401 100644
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java
@@ -131,8 +131,8 @@
static Object traceReturn(final DebugLogger logger, final Object value) {
final String str = " return" +
(VOID_TAG.equals(value) ?
- ";" :
- " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
+ ";" :
+ " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
if (logger == null) {
err(str);
} else if (logger.isEnabled()) {
@@ -164,13 +164,13 @@
}
sb.append('\'').
- append(stripName(argString(args[i]))).
- append('\'').
- append(' ').
- append('[').
- append("type=").
- append(args[i] == null ? "null" : stripName(args[i].getClass())).
- append(']');
+ append(stripName(argString(args[i]))).
+ append('\'').
+ append(' ').
+ append('[').
+ append("type=").
+ append(args[i] == null ? "null" : stripName(args[i].getClass())).
+ append(']');
if (i + 1 < args.length) {
sb.append(", ");
@@ -216,8 +216,8 @@
if (arg instanceof ScriptObject) {
return arg.toString() +
- " (map=" + Debug.id(((ScriptObject)arg).getMap()) +
- ')';
+ " (map=" + Debug.id(((ScriptObject)arg).getMap()) +
+ ')';
}
return arg.toString();
@@ -262,7 +262,7 @@
return addDebugPrintout(null, Level.OFF, mh, paramStart, printReturnValue, tag);
}
- /**
+ /**
* Add a debug printout to a method handle, tracing parameters and return values
*
* @param logger a specific logger to which to write the output
@@ -278,7 +278,7 @@
//if there is no logger, or if it's set to log only coarser events
//than the trace level, skip and return
- if (logger != null && logger.levelCoarserThan(level)) {
+ if (logger == null || !logger.isLoggable(level)) {
return mh;
}
@@ -289,9 +289,9 @@
trace = MethodHandles.foldArguments(
mh,
trace.asCollector(
- Object[].class,
- type.parameterCount()).
- asType(type.changeReturnType(void.class)));
+ Object[].class,
+ type.parameterCount()).
+ asType(type.changeReturnType(void.class)));
final Class<?> retType = type.returnType();
if (printReturnValue) {
@@ -299,7 +299,7 @@
final MethodHandle traceReturn = MethodHandles.insertArguments(TRACE_RETURN, 0, logger);
trace = MethodHandles.filterReturnValue(trace,
traceReturn.asType(
- traceReturn.type().changeParameterType(0, retType).changeReturnType(retType)));
+ traceReturn.type().changeParameterType(0, retType).changeReturnType(retType)));
} else {
trace = MethodHandles.filterReturnValue(trace, MethodHandles.insertArguments(TRACE_RETURN_VOID, 0, logger));
}
@@ -355,9 +355,9 @@
sb.append("] ");
} else {
sb.append(d)
- .append('{')
- .append(Integer.toHexString(System.identityHashCode(d)))
- .append('}');
+ .append('{')
+ .append(Integer.toHexString(System.identityHashCode(d)))
+ .append('}');
}
if (i + 1 < data.length) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
index fa3b807..8f75975 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java
@@ -192,7 +192,7 @@
/**
* Factory method for array data
*
- * @param nb underlying nativebuffer
+ * @param nb underlying native buffer
* @param start start element
* @param end end element
*
diff --git a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
deleted file mode 100644
index 333790f..0000000
--- a/nashorn/src/jdk/nashorn/internal/objects/BoundScriptFunctionImpl.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.objects;
-
-import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-
-/**
- * A {@code ScriptFunctionImpl} subclass for functions created using {@code Function.prototype.bind}. Such functions
- * must track their {@code [[TargetFunction]]} property for purposes of correctly implementing {@code [[HasInstance]]};
- * see {@link ScriptFunction#isInstance(ScriptObject)}.
- */
-final class BoundScriptFunctionImpl extends ScriptFunctionImpl {
- private final ScriptFunction targetFunction;
-
- BoundScriptFunctionImpl(final ScriptFunctionData data, final ScriptFunction targetFunction) {
- super(data, Global.instance());
- setPrototype(ScriptRuntime.UNDEFINED);
- this.targetFunction = targetFunction;
- }
-
- @Override
- protected ScriptFunction getTargetFunction() {
- return targetFunction;
- }
-}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java
index 44a42b7..8745ec8 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java
@@ -88,14 +88,14 @@
*/
@ScriptClass("Global")
public final class Global extends Scope {
- // Placeholder value used in place of a location property (__FILE__, __DIR__, __LINE__)
- private static final Object LOCATION_PROPERTY_PLACEHOLDER = new Object();
+ // This special value is used to flag a lazily initialized global property.
+ // This also serves as placeholder value used in place of a location property
+ // (__FILE__, __DIR__, __LINE__)
+ private static final Object LAZY_SENTINEL = new Object();
+
private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class);
- // placeholder value for lazily initialized global objects
- private static final Object LAZY_SENTINEL = new Object();
-
/**
* Optimistic builtin names that require switchpoint invalidation
* upon assignment. Overly conservative, but works for now, to avoid
@@ -182,15 +182,15 @@
/** Value property NaN of the Global Object - ECMA 15.1.1.1 NaN */
@Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final double NaN = Double.NaN;
+ public static final double NaN = Double.NaN;
/** Value property Infinity of the Global Object - ECMA 15.1.1.2 Infinity */
@Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final double Infinity = Double.POSITIVE_INFINITY;
+ public static final double Infinity = Double.POSITIVE_INFINITY;
/** Value property Undefined of the Global Object - ECMA 15.1.1.3 Undefined */
@Property(attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final Object undefined = UNDEFINED;
+ public static final Object undefined = UNDEFINED;
/** ECMA 15.1.2.1 eval(x) */
@Property(attributes = Attribute.NOT_ENUMERABLE)
@@ -830,15 +830,15 @@
/** Nashorn extension: current script's file name */
@Property(name = "__FILE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final Object __FILE__ = LOCATION_PROPERTY_PLACEHOLDER;
+ public static final Object __FILE__ = LAZY_SENTINEL;
/** Nashorn extension: current script's directory */
@Property(name = "__DIR__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final Object __DIR__ = LOCATION_PROPERTY_PLACEHOLDER;
+ public static final Object __DIR__ = LAZY_SENTINEL;
/** Nashorn extension: current source line number being executed */
@Property(name = "__LINE__", attributes = Attribute.NON_ENUMERABLE_CONSTANT)
- public final Object __LINE__ = LOCATION_PROPERTY_PLACEHOLDER;
+ public static final Object __LINE__ = LAZY_SENTINEL;
private volatile NativeDate DEFAULT_DATE;
@@ -928,8 +928,6 @@
private ThreadLocal<ScriptContext> scontext;
// current ScriptEngine associated - can be null.
private ScriptEngine engine;
- // initial ScriptContext - can be null
- private volatile ScriptContext initscontext;
// ES6 global lexical scope.
private final LexicalScope lexicalScope;
@@ -957,7 +955,7 @@
private ScriptContext currentContext() {
final ScriptContext sc = scontext != null? scontext.get() : null;
- return sc == null? initscontext : sc;
+ return (sc != null)? sc : (engine != null? engine.getContext() : null);
}
@Override
@@ -1067,16 +1065,14 @@
* of the global scope object.
*
* @param eng ScriptEngine to initialize
- * @param ctxt ScriptContext to initialize
*/
- public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
+ public void initBuiltinObjects(final ScriptEngine eng) {
if (this.builtinObject != null) {
// already initialized, just return
return;
}
this.engine = eng;
- this.initscontext = ctxt;
if (this.engine != null) {
this.scontext = new ThreadLocal<>();
}
@@ -1583,7 +1579,11 @@
return ScriptFunction.getPrototype(builtinObject);
}
- ScriptObject getFunctionPrototype() {
+ /**
+ * Get the builtin Function prototype.
+ * @return the Function.prototype.
+ */
+ public ScriptObject getFunctionPrototype() {
return ScriptFunction.getPrototype(builtinFunction);
}
@@ -1768,38 +1768,15 @@
return ScriptFunction.getPrototype(getBuiltinFloat64Array());
}
- private ScriptFunction getBuiltinArray() {
- return builtinArray;
- }
-
- ScriptFunction getTypeErrorThrower() {
+ /**
+ * Return the function that throws TypeError unconditionally. Used as "poison" methods for certain Function properties.
+ *
+ * @return the TypeError throwing function
+ */
+ public ScriptFunction getTypeErrorThrower() {
return typeErrorThrower;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin array has not been overridden
- */
- public static boolean isBuiltinArray() {
- final Global instance = Global.instance();
- return instance.array == instance.getBuiltinArray();
- }
-
- private ScriptFunction getBuiltinBoolean() {
- return builtinBoolean;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin boolean has not been overridden
- */
- public static boolean isBuiltinBoolean() {
- final Global instance = Global.instance();
- return instance._boolean == instance.getBuiltinBoolean();
- }
-
private synchronized ScriptFunction getBuiltinDate() {
if (this.builtinDate == null) {
this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
@@ -1810,30 +1787,6 @@
return this.builtinDate;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin date has not been overridden
- */
- public static boolean isBuiltinDate() {
- final Global instance = Global.instance();
- return instance.date == LAZY_SENTINEL || instance.date == instance.getBuiltinDate();
- }
-
- private ScriptFunction getBuiltinError() {
- return builtinError;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin error has not been overridden
- */
- public static boolean isBuiltinError() {
- final Global instance = Global.instance();
- return instance.error == instance.getBuiltinError();
- }
-
private synchronized ScriptFunction getBuiltinEvalError() {
if (this.builtinEvalError == null) {
this.builtinEvalError = initErrorSubtype("EvalError", getErrorPrototype());
@@ -1841,31 +1794,11 @@
return this.builtinEvalError;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin eval error has not been overridden
- */
- public static boolean isBuiltinEvalError() {
- final Global instance = Global.instance();
- return instance.evalError == LAZY_SENTINEL || instance.evalError == instance.getBuiltinEvalError();
- }
-
private ScriptFunction getBuiltinFunction() {
return builtinFunction;
}
/**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin function has not been overridden
- */
- public static boolean isBuiltinFunction() {
- final Global instance = Global.instance();
- return instance.function == instance.getBuiltinFunction();
- }
-
- /**
* Get the switchpoint used to check property changes for Function.prototype.apply
* @return the switchpoint guarding apply (same as guarding call, and everything else in function)
*/
@@ -1906,16 +1839,6 @@
return builtinJSAdapter;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin JSAdapter has not been overridden
- */
- public static boolean isBuiltinJSAdapter() {
- final Global instance = Global.instance();
- return instance.jsadapter == LAZY_SENTINEL || instance.jsadapter == instance.getBuiltinJSAdapter();
- }
-
private synchronized ScriptObject getBuiltinJSON() {
if (this.builtinJSON == null) {
this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
@@ -1923,44 +1846,6 @@
return this.builtinJSON;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin JSON has has not been overridden
- */
- public static boolean isBuiltinJSON() {
- final Global instance = Global.instance();
- return instance.json == LAZY_SENTINEL || instance.json == instance.getBuiltinJSON();
- }
-
- private ScriptObject getBuiltinJava() {
- return builtinJava;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin Java has not been overridden
- */
- public static boolean isBuiltinJava() {
- final Global instance = Global.instance();
- return instance.java == instance.getBuiltinJava();
- }
-
- private ScriptObject getBuiltinJavax() {
- return builtinJavax;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin Javax has not been overridden
- */
- public static boolean isBuiltinJavax() {
- final Global instance = Global.instance();
- return instance.javax == instance.getBuiltinJavax();
- }
-
private synchronized ScriptFunction getBuiltinJavaImporter() {
if (this.builtinJavaImporter == null) {
this.builtinJavaImporter = initConstructor("JavaImporter", ScriptFunction.class);
@@ -1975,68 +1860,6 @@
return this.builtinJavaApi;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin Java importer has not been overridden
- */
- public static boolean isBuiltinJavaImporter() {
- final Global instance = Global.instance();
- return instance.javaImporter == LAZY_SENTINEL || instance.javaImporter == instance.getBuiltinJavaImporter();
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin math has not been overridden
- */
- public static boolean isBuiltinMath() {
- final Global instance = Global.instance();
- return instance.math == instance.builtinMath;
- }
-
- private ScriptFunction getBuiltinNumber() {
- return builtinNumber;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin number has not been overridden
- */
- public static boolean isBuiltinNumber() {
- final Global instance = Global.instance();
- return instance.number == instance.getBuiltinNumber();
- }
-
- private ScriptFunction getBuiltinObject() {
- return builtinObject;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin object has not been overridden
- */
- public static boolean isBuiltinObject() {
- final Global instance = Global.instance();
- return instance.object == instance.getBuiltinObject();
- }
-
- private ScriptObject getBuiltinPackages() {
- return builtinPackages;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin package has not been overridden
- */
- public static boolean isBuiltinPackages() {
- final Global instance = Global.instance();
- return instance.packages == instance.getBuiltinPackages();
- }
-
private synchronized ScriptFunction getBuiltinRangeError() {
if (this.builtinRangeError == null) {
this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype());
@@ -2044,30 +1867,6 @@
return builtinRangeError;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin range error has not been overridden
- */
- public static boolean isBuiltinRangeError() {
- final Global instance = Global.instance();
- return instance.rangeError == LAZY_SENTINEL || instance.rangeError == instance.getBuiltinRangeError();
- }
-
- private synchronized ScriptFunction getBuiltinReferenceError() {
- return builtinReferenceError;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin reference error has not been overridden
- */
- public static boolean isBuiltinReferenceError() {
- final Global instance = Global.instance();
- return instance.referenceError == instance.getBuiltinReferenceError();
- }
-
private synchronized ScriptFunction getBuiltinRegExp() {
if (this.builtinRegExp == null) {
this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
@@ -2081,58 +1880,6 @@
return builtinRegExp;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin regexp has not been overridden
- */
- public static boolean isBuiltinRegExp() {
- final Global instance = Global.instance();
- return instance.regexp == LAZY_SENTINEL || instance.regexp == instance.getBuiltinRegExp();
- }
-
- private ScriptFunction getBuiltinString() {
- return builtinString;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin Java has not been overridden
- */
- public static boolean isBuiltinString() {
- final Global instance = Global.instance();
- return instance.string == instance.getBuiltinString();
- }
-
- private ScriptFunction getBuiltinSyntaxError() {
- return builtinSyntaxError;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin syntax error has not been overridden
- */
- public static boolean isBuiltinSyntaxError() {
- final Global instance = Global.instance();
- return instance.syntaxError == instance.getBuiltinSyntaxError();
- }
-
- private ScriptFunction getBuiltinTypeError() {
- return builtinTypeError;
- }
-
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin type error has not been overridden
- */
- public static boolean isBuiltinTypeError() {
- final Global instance = Global.instance();
- return instance.typeError == instance.getBuiltinTypeError();
- }
-
private synchronized ScriptFunction getBuiltinURIError() {
if (this.builtinURIError == null) {
this.builtinURIError = initErrorSubtype("URIError", getErrorPrototype());
@@ -2140,16 +1887,6 @@
return this.builtinURIError;
}
- /**
- * Called from compiled script code to test if builtin has been overridden
- *
- * @return true if builtin URI error has not been overridden
- */
- public static boolean isBuiltinURIError() {
- final Global instance = Global.instance();
- return instance.uriError == LAZY_SENTINEL || instance.uriError == instance.getBuiltinURIError();
- }
-
@Override
public String getClassName() {
return "global";
@@ -2288,7 +2025,7 @@
* @return true if the value is a placeholder, false otherwise.
*/
public static boolean isLocationPropertyPlaceholder(final Object placeholder) {
- return placeholder == LOCATION_PROPERTY_PLACEHOLDER;
+ return placeholder == LAZY_SENTINEL;
}
/**
@@ -2386,17 +2123,18 @@
}
}
+ final boolean extensible = isExtensible();
for (final jdk.nashorn.internal.runtime.Property property : properties) {
if (property.isLexicalBinding()) {
assert lexScope != null;
- lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property);
+ lexicalMap = lexScope.addBoundProperty(lexicalMap, source, property, true);
if (ownMap.findProperty(property.getKey()) != null) {
// If property exists in the global object invalidate any global constant call sites.
invalidateGlobalConstant(property.getKey());
}
} else {
- ownMap = addBoundProperty(ownMap, source, property);
+ ownMap = addBoundProperty(ownMap, source, property, extensible);
}
}
@@ -2424,7 +2162,7 @@
// We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
// because those are invalidated per-key in the addBoundProperties method above.
- // We therefor check if the invocation does already have a switchpoint and the property is non-inherited,
+ // We therefore check if the invocation does already have a switchpoint and the property is non-inherited,
// assuming this only applies to global constants. If other non-inherited properties will
// start using switchpoints some time in the future we'll have to revisit this.
if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) {
@@ -2469,10 +2207,10 @@
* Adds jjs shell interactive mode builtin functions to global scope.
*/
public void addShellBuiltins() {
- Object value = ScriptFunctionImpl.makeFunction("input", ShellFunctions.INPUT);
+ Object value = ScriptFunction.createBuiltin("input", ShellFunctions.INPUT);
addOwnProperty("input", Attribute.NOT_ENUMERABLE, value);
- value = ScriptFunctionImpl.makeFunction("evalinput", ShellFunctions.EVALINPUT);
+ value = ScriptFunction.createBuiltin("evalinput", ShellFunctions.EVALINPUT);
addOwnProperty("evalinput", Attribute.NOT_ENUMERABLE, value);
}
@@ -2519,35 +2257,35 @@
this.setInitialProto(getObjectPrototype());
// initialize global function properties
- this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
+ this.eval = this.builtinEval = ScriptFunction.createBuiltin("eval", EVAL);
- this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
+ this.parseInt = ScriptFunction.createBuiltin("parseInt", GlobalFunctions.PARSEINT,
new Specialization[] {
new Specialization(GlobalFunctions.PARSEINT_Z),
new Specialization(GlobalFunctions.PARSEINT_I),
new Specialization(GlobalFunctions.PARSEINT_J),
new Specialization(GlobalFunctions.PARSEINT_OI),
new Specialization(GlobalFunctions.PARSEINT_O) });
- this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
- this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN,
+ this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
+ this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN,
new Specialization[] {
new Specialization(GlobalFunctions.IS_NAN_I),
new Specialization(GlobalFunctions.IS_NAN_J),
new Specialization(GlobalFunctions.IS_NAN_D) });
- this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
- this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN);
- this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE);
- this.encodeURI = ScriptFunctionImpl.makeFunction("encodeURI", GlobalFunctions.ENCODE_URI);
- this.encodeURIComponent = ScriptFunctionImpl.makeFunction("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT);
- this.decodeURI = ScriptFunctionImpl.makeFunction("decodeURI", GlobalFunctions.DECODE_URI);
- this.decodeURIComponent = ScriptFunctionImpl.makeFunction("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT);
- this.escape = ScriptFunctionImpl.makeFunction("escape", GlobalFunctions.ESCAPE);
- this.unescape = ScriptFunctionImpl.makeFunction("unescape", GlobalFunctions.UNESCAPE);
- this.print = ScriptFunctionImpl.makeFunction("print", env._print_no_newline ? PRINT : PRINTLN);
- this.load = ScriptFunctionImpl.makeFunction("load", LOAD);
- this.loadWithNewGlobal = ScriptFunctionImpl.makeFunction("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL);
- this.exit = ScriptFunctionImpl.makeFunction("exit", EXIT);
- this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT);
+ this.parseFloat = ScriptFunction.createBuiltin("parseFloat", GlobalFunctions.PARSEFLOAT);
+ this.isNaN = ScriptFunction.createBuiltin("isNaN", GlobalFunctions.IS_NAN);
+ this.isFinite = ScriptFunction.createBuiltin("isFinite", GlobalFunctions.IS_FINITE);
+ this.encodeURI = ScriptFunction.createBuiltin("encodeURI", GlobalFunctions.ENCODE_URI);
+ this.encodeURIComponent = ScriptFunction.createBuiltin("encodeURIComponent", GlobalFunctions.ENCODE_URICOMPONENT);
+ this.decodeURI = ScriptFunction.createBuiltin("decodeURI", GlobalFunctions.DECODE_URI);
+ this.decodeURIComponent = ScriptFunction.createBuiltin("decodeURIComponent", GlobalFunctions.DECODE_URICOMPONENT);
+ this.escape = ScriptFunction.createBuiltin("escape", GlobalFunctions.ESCAPE);
+ this.unescape = ScriptFunction.createBuiltin("unescape", GlobalFunctions.UNESCAPE);
+ this.print = ScriptFunction.createBuiltin("print", env._print_no_newline ? PRINT : PRINTLN);
+ this.load = ScriptFunction.createBuiltin("load", LOAD);
+ this.loadWithNewGlobal = ScriptFunction.createBuiltin("loadWithNewGlobal", LOAD_WITH_NEW_GLOBAL);
+ this.exit = ScriptFunction.createBuiltin("exit", EXIT);
+ this.quit = ScriptFunction.createBuiltin("quit", EXIT);
// built-in constructors
this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
@@ -2627,7 +2365,7 @@
// default file name
addOwnProperty(ScriptEngine.FILENAME, Attribute.NOT_ENUMERABLE, null);
// __noSuchProperty__ hook for ScriptContext search of missing variables
- final ScriptFunction noSuchProp = ScriptFunctionImpl.makeStrictFunction(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
+ final ScriptFunction noSuchProp = ScriptFunction.createStrictBuiltin(NO_SUCH_PROPERTY_NAME, NO_SUCH_PROPERTY);
addOwnProperty(NO_SUCH_PROPERTY_NAME, Attribute.NOT_ENUMERABLE, noSuchProp);
}
}
@@ -2638,17 +2376,17 @@
final ScriptObject errorProto = getErrorPrototype();
// Nashorn specific accessors on Error.prototype - stack, lineNumber, columnNumber and fileName
- final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", NativeError.GET_STACK);
- final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", NativeError.SET_STACK);
+ final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", NativeError.GET_STACK);
+ final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", NativeError.SET_STACK);
errorProto.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
- final ScriptFunction getLineNumber = ScriptFunctionImpl.makeFunction("getLineNumber", NativeError.GET_LINENUMBER);
- final ScriptFunction setLineNumber = ScriptFunctionImpl.makeFunction("setLineNumber", NativeError.SET_LINENUMBER);
+ final ScriptFunction getLineNumber = ScriptFunction.createBuiltin("getLineNumber", NativeError.GET_LINENUMBER);
+ final ScriptFunction setLineNumber = ScriptFunction.createBuiltin("setLineNumber", NativeError.SET_LINENUMBER);
errorProto.addOwnProperty("lineNumber", Attribute.NOT_ENUMERABLE, getLineNumber, setLineNumber);
- final ScriptFunction getColumnNumber = ScriptFunctionImpl.makeFunction("getColumnNumber", NativeError.GET_COLUMNNUMBER);
- final ScriptFunction setColumnNumber = ScriptFunctionImpl.makeFunction("setColumnNumber", NativeError.SET_COLUMNNUMBER);
+ final ScriptFunction getColumnNumber = ScriptFunction.createBuiltin("getColumnNumber", NativeError.GET_COLUMNNUMBER);
+ final ScriptFunction setColumnNumber = ScriptFunction.createBuiltin("setColumnNumber", NativeError.SET_COLUMNNUMBER);
errorProto.addOwnProperty("columnNumber", Attribute.NOT_ENUMERABLE, getColumnNumber, setColumnNumber);
- final ScriptFunction getFileName = ScriptFunctionImpl.makeFunction("getFileName", NativeError.GET_FILENAME);
- final ScriptFunction setFileName = ScriptFunctionImpl.makeFunction("setFileName", NativeError.SET_FILENAME);
+ final ScriptFunction getFileName = ScriptFunction.createBuiltin("getFileName", NativeError.GET_FILENAME);
+ final ScriptFunction setFileName = ScriptFunction.createBuiltin("setFileName", NativeError.SET_FILENAME);
errorProto.addOwnProperty("fileName", Attribute.NOT_ENUMERABLE, getFileName, setFileName);
// ECMA 15.11.4.2 Error.prototype.name
@@ -2687,20 +2425,22 @@
}
private void initScripting(final ScriptEnvironment scriptEnv) {
- Object value;
- value = ScriptFunctionImpl.makeFunction("readLine", ScriptingFunctions.READLINE);
+ ScriptObject value;
+ value = ScriptFunction.createBuiltin("readLine", ScriptingFunctions.READLINE);
addOwnProperty("readLine", Attribute.NOT_ENUMERABLE, value);
- value = ScriptFunctionImpl.makeFunction("readFully", ScriptingFunctions.READFULLY);
+ value = ScriptFunction.createBuiltin("readFully", ScriptingFunctions.READFULLY);
addOwnProperty("readFully", Attribute.NOT_ENUMERABLE, value);
final String execName = ScriptingFunctions.EXEC_NAME;
- value = ScriptFunctionImpl.makeFunction(execName, ScriptingFunctions.EXEC);
+ value = ScriptFunction.createBuiltin(execName, ScriptingFunctions.EXEC);
+ value.addOwnProperty(ScriptingFunctions.THROW_ON_ERROR_NAME, Attribute.NOT_ENUMERABLE, false);
+
addOwnProperty(execName, Attribute.NOT_ENUMERABLE, value);
// Nashorn extension: global.echo (scripting-mode-only)
// alias for "print"
- value = get("print");
+ value = (ScriptObject)get("print");
addOwnProperty("echo", Attribute.NOT_ENUMERABLE, value);
// Nashorn extension: global.$OPTIONS (scripting-mode-only)
@@ -2876,7 +2616,7 @@
this.builtinFunction = initConstructor("Function", ScriptFunction.class);
// create global anonymous function
- final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
+ final ScriptFunction anon = ScriptFunction.createAnonymous();
// need to copy over members of Function.prototype to anon function
anon.addBoundProperties(getFunctionPrototype());
@@ -2888,10 +2628,7 @@
anon.deleteOwnProperty(anon.getMap().findProperty("prototype"));
// use "getter" so that [[ThrowTypeError]] function's arity is 0 - as specified in step 10 of section 13.2.3
- this.typeErrorThrower = new ScriptFunctionImpl("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER, null, null, 0);
- typeErrorThrower.setPrototype(UNDEFINED);
- // Non-constructor built-in functions do not have "prototype" property
- typeErrorThrower.deleteOwnProperty(typeErrorThrower.getMap().findProperty("prototype"));
+ this.typeErrorThrower = ScriptFunction.createBuiltin("TypeErrorThrower", Lookup.TYPE_ERROR_THROWER_GETTER);
typeErrorThrower.preventExtensions();
// now initialize Object
@@ -2902,8 +2639,8 @@
// ES6 draft compliant __proto__ property of Object.prototype
// accessors on Object.prototype for "__proto__"
- final ScriptFunction getProto = ScriptFunctionImpl.makeFunction("getProto", NativeObject.GET__PROTO__);
- final ScriptFunction setProto = ScriptFunctionImpl.makeFunction("setProto", NativeObject.SET__PROTO__);
+ final ScriptFunction getProto = ScriptFunction.createBuiltin("getProto", NativeObject.GET__PROTO__);
+ final ScriptFunction setProto = ScriptFunction.createBuiltin("setProto", NativeObject.SET__PROTO__);
ObjectPrototype.addOwnProperty("__proto__", Attribute.NOT_ENUMERABLE, getProto, setProto);
// Function valued properties of Function.prototype were not properly
@@ -2999,9 +2736,9 @@
}
@Override
- protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property) {
+ protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final jdk.nashorn.internal.runtime.Property property, final boolean extensible) {
// We override this method just to make it callable by Global
- return super.addBoundProperty(propMap, source, property);
+ return super.addBoundProperty(propMap, source, property, extensible);
}
private static GuardedInvocation filterInvocation(final GuardedInvocation invocation) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
index 14c11f6..44d0606 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDataView.java
@@ -22,6 +22,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
index 9f0c14d..d517d39 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Objects;
@@ -246,7 +247,7 @@
final PrintWriter out = Context.getCurrentErr();
out.println("ScriptObject count " + ScriptObject.getCount());
- out.println("Scope count " + Scope.getCount());
+ out.println("Scope count " + Scope.getScopeCount());
out.println("ScriptObject listeners added " + PropertyListeners.getListenersAdded());
out.println("ScriptObject listeners removed " + PropertyListeners.getListenersRemoved());
out.println("ScriptFunction constructor calls " + ScriptFunction.getConstructorCount());
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
index e1d95ce..036c8d8 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java
@@ -150,8 +150,8 @@
initException(sobj);
sobj.delete(STACK, false);
if (! sobj.has("stack")) {
- final ScriptFunction getStack = ScriptFunctionImpl.makeFunction("getStack", GET_STACK);
- final ScriptFunction setStack = ScriptFunctionImpl.makeFunction("setStack", SET_STACK);
+ final ScriptFunction getStack = ScriptFunction.createBuiltin("getStack", GET_STACK);
+ final ScriptFunction setStack = ScriptFunction.createBuiltin("setStack", SET_STACK);
sobj.addOwnProperty("stack", Attribute.NOT_ENUMERABLE, getStack, setStack);
}
return UNDEFINED;
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java
index d336ca1..4b8029c 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFunction.java
@@ -108,7 +108,7 @@
throw new AssertionError("Should not reach here");
}
- /**
+ /**
* Given an array-like object, converts it into a Java object array suitable for invocation of ScriptRuntime.apply
* or for direct invocation of the applied function.
* @param array the array-like object. Can be null in which case a zero-length array is created.
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
index c5ece8c..32e41da 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -621,13 +621,13 @@
if (find != null) {
final Object value = find.getObjectValue();
if (value instanceof ScriptFunction) {
- final ScriptFunctionImpl func = (ScriptFunctionImpl)value;
+ final ScriptFunction func = (ScriptFunction)value;
// TODO: It's a shame we need to produce a function bound to this and name, when we'd only need it bound
// to name. Probably not a big deal, but if we can ever make it leaner, it'd be nice.
return new GuardedInvocation(MH.dropArguments(MH.constant(Object.class,
- func.makeBoundFunction(this, new Object[] { name })), 0, Object.class),
+ func.createBound(this, new Object[] { name })), 0, Object.class),
testJSAdaptor(adaptee, null, null, null),
- adaptee.getProtoSwitchPoint(__call__, find.getOwner()));
+ adaptee.getProtoSwitchPoints(__call__, find.getOwner()), null);
}
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
@@ -698,7 +698,7 @@
return new GuardedInvocation(
methodHandle,
testJSAdaptor(adaptee, findData.getGetter(Object.class, INVALID_PROGRAM_POINT, null), findData.getOwner(), func),
- adaptee.getProtoSwitchPoint(hook, findData.getOwner()));
+ adaptee.getProtoSwitchPoints(hook, findData.getOwner()), null);
}
}
}
@@ -710,7 +710,7 @@
final MethodHandle methodHandle = hook.equals(__put__) ?
MH.asType(Lookup.EMPTY_SETTER, type) :
Lookup.emptyGetter(type.returnType());
- return new GuardedInvocation(methodHandle, testJSAdaptor(adaptee, null, null, null), adaptee.getProtoSwitchPoint(hook, null));
+ return new GuardedInvocation(methodHandle, testJSAdaptor(adaptee, null, null, null), adaptee.getProtoSwitchPoints(hook, null), null);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
index 743f055..79a190f 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java
@@ -93,7 +93,7 @@
@Function(name="synchronized", attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object synchronizedFunc(final Object self, final Object func, final Object obj) {
if (func instanceof ScriptFunction) {
- return ((ScriptFunction)func).makeSynchronizedFunction(obj);
+ return ((ScriptFunction)func).createSynchronized(obj);
}
throw typeError("not.a.function", ScriptRuntime.safeToString(func));
@@ -342,7 +342,8 @@
/**
* Given a script object and a Java type, converts the script object into the desired Java type. Currently it
* performs shallow creation of Java arrays, as well as wrapping of objects in Lists, Dequeues, Queues,
- * and Collections. Example:
+ * and Collections. If conversion is not possible or fails for some reason, TypeError is thrown.
+ * Example:
* <pre>
* var anArray = [1, "13", false]
* var javaIntArray = Java.to(anArray, "int[]")
@@ -386,7 +387,11 @@
}
if(targetClass.isArray()) {
- return JSType.toJavaArray(obj, targetClass.getComponentType());
+ try {
+ return JSType.toJavaArray(obj, targetClass.getComponentType());
+ } catch (final Exception exp) {
+ throw typeError(exp, "java.array.conversion.failed", targetClass.getName());
+ }
}
if (targetClass == List.class || targetClass == Deque.class || targetClass == Queue.class || targetClass == Collection.class) {
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
index 498c263..67494b2 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJavaImporter.java
@@ -134,7 +134,7 @@
}
@Override
- protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+ protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
final Object retval = createProperty(name);
if (isValid(programPoint)) {
throw new UnwarrantedOptimismException(retval, programPoint);
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
index 7ea2783..3cbe5eb 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java
@@ -33,6 +33,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.Locale;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -187,6 +188,7 @@
format.setMinimumFractionDigits(fractionDigits);
format.setMaximumFractionDigits(fractionDigits);
format.setGroupingUsed(false);
+ format.setRoundingMode(RoundingMode.HALF_UP);
return format.format(x);
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
index 62ef483..da64372 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -728,7 +728,7 @@
*
* $$ -> $
* $& -> the matched substring
- * $` -> the portion of string that preceeds matched substring
+ * $` -> the portion of string that precedes matched substring
* $' -> the portion of string that follows the matched substring
* $n -> the nth capture, where n is [1-9] and $n is NOT followed by a decimal digit
* $nn -> the nnth capture, where nn is a two digit decimal number [01-99].
diff --git a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java b/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
deleted file mode 100644
index ecf3c2e..0000000
--- a/nashorn/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.objects;
-
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
-import java.lang.invoke.MethodHandle;
-import java.util.ArrayList;
-import jdk.nashorn.internal.runtime.AccessorProperty;
-import jdk.nashorn.internal.runtime.GlobalFunctions;
-import jdk.nashorn.internal.runtime.Property;
-import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.Specialization;
-
-/**
- * Concrete implementation of ScriptFunction. This sets correct map for the
- * function objects -- to expose properties like "prototype", "length" etc.
- */
-public class ScriptFunctionImpl extends ScriptFunction {
-
- /** Reference to constructor prototype. */
- private Object prototype;
-
- // property map for strict mode functions
- private static final PropertyMap strictmodemap$;
- // property map for bound functions
- private static final PropertyMap boundfunctionmap$;
- // property map for non-strict, non-bound functions.
- private static final PropertyMap map$;
-
- // Marker object for lazily initialized prototype object
- private static final Object LAZY_PROTOTYPE = new Object();
-
- private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs, final Global global) {
- super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
- init(global);
- }
-
- /**
- * Constructor called by Nasgen generated code, no membercount, use the default map.
- * Creates builtin functions only.
- *
- * @param name name of function
- * @param invokeHandle handle for invocation
- * @param specs specialized versions of this method, if available, null otherwise
- */
- ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
- this(name, invokeHandle, specs, Global.instance());
- }
-
- private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs, final Global global) {
- super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
- init(global);
- }
-
- /**
- * Constructor called by Nasgen generated code, no membercount, use the map passed as argument.
- * Creates builtin functions only.
- *
- * @param name name of function
- * @param invokeHandle handle for invocation
- * @param map initial property map
- * @param specs specialized versions of this method, if available, null otherwise
- */
- ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
- this(name, invokeHandle, map, specs, Global.instance());
- }
-
- private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags, final Global global) {
- super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags);
- init(global);
- }
-
- /**
- * Constructor called by Global.newScriptFunction (runtime).
- *
- * @param name name of function
- * @param methodHandle handle for invocation
- * @param scope scope object
- * @param specs specialized versions of this method, if available, null otherwise
- * @param flags {@link ScriptFunctionData} flags
- */
- ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags) {
- this(name, methodHandle, scope, specs, flags, Global.instance());
- }
-
- private ScriptFunctionImpl(final RecompilableScriptFunctionData data, final ScriptObject scope, final Global global) {
- super(data, getMap(data.isStrict()), scope);
- init(global);
- }
-
- /**
- * Factory method called by compiler generated code for functions that need parent scope.
- *
- * @param constants the generated class' constant array
- * @param index the index of the {@code RecompilableScriptFunctionData} object in the constants array.
- * @param scope the parent scope object
- * @return a newly created function object
- */
- public static ScriptFunction create(final Object[] constants, final int index, final ScriptObject scope) {
- return new ScriptFunctionImpl((RecompilableScriptFunctionData)constants[index], scope, Global.instance());
- }
-
- /**
- * Factory method called by compiler generated code for functions that don't need parent scope.
- *
- * @param constants the generated class' constant array
- * @param index the index of the {@code RecompilableScriptFunctionData} object in the constants array.
- * @return a newly created function object
- */
- public static ScriptFunction create(final Object[] constants, final int index) {
- return create(constants, index, null);
- }
-
- /**
- * Only invoked internally from {@link BoundScriptFunctionImpl} constructor.
- * @param data the script function data for the bound function.
- * @param global the global object
- */
- ScriptFunctionImpl(final ScriptFunctionData data, final Global global) {
- super(data, boundfunctionmap$, null);
- init(global);
- }
-
- static {
- final ArrayList<Property> properties = new ArrayList<>(3);
- properties.add(AccessorProperty.create("prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE));
- properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null));
- properties.add(AccessorProperty.create("name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null));
- map$ = PropertyMap.newMap(properties);
- strictmodemap$ = createStrictModeMap(map$);
- boundfunctionmap$ = createBoundFunctionMap(strictmodemap$);
- }
-
- private static PropertyMap createStrictModeMap(final PropertyMap map) {
- final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
- PropertyMap newMap = map;
- // Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
- newMap = newMap.addPropertyNoHistory(map.newUserAccessors("arguments", flags));
- newMap = newMap.addPropertyNoHistory(map.newUserAccessors("caller", flags));
- return newMap;
- }
-
- private static boolean isStrict(final int flags) {
- return (flags & ScriptFunctionData.IS_STRICT) != 0;
- }
-
- // Choose the map based on strict mode!
- private static PropertyMap getMap(final boolean strict) {
- return strict ? strictmodemap$ : map$;
- }
-
- private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
- // Bound function map is same as strict function map, but additionally lacks the "prototype" property, see
- // ECMAScript 5.1 section 15.3.4.5
- return strictModeMap.deleteProperty(strictModeMap.findProperty("prototype"));
- }
-
- // Instance of this class is used as global anonymous function which
- // serves as Function.prototype object.
- private static class AnonymousFunction extends ScriptFunctionImpl {
- private static final PropertyMap anonmap$ = PropertyMap.newMap();
-
- AnonymousFunction() {
- super("", GlobalFunctions.ANONYMOUS, anonmap$, null);
- }
- }
-
- static ScriptFunctionImpl newAnonymousFunction() {
- return new AnonymousFunction();
- }
-
- private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
- final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, flags);
- func.setPrototype(UNDEFINED);
- // Non-constructor built-in functions do not have "prototype" property
- func.deleteOwnProperty(func.getMap().findProperty("prototype"));
-
- return func;
- }
-
- /**
- * Factory method for non-constructor built-in functions
- *
- * @param name function name
- * @param methodHandle handle for invocation
- * @param specs specialized versions of function if available, null otherwise
- * @return new ScriptFunction
- */
- static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
- return makeFunction(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
- }
-
- /**
- * Factory method for non-constructor built-in, strict functions
- *
- * @param name function name
- * @param methodHandle handle for invocation
- * @return new ScriptFunction
- */
- static ScriptFunction makeStrictFunction(final String name, final MethodHandle methodHandle) {
- return makeFunction(name, methodHandle, null, ScriptFunctionData.IS_BUILTIN | ScriptFunctionData.IS_STRICT );
- }
-
- /**
- * Factory method for non-constructor built-in functions
- *
- * @param name function name
- * @param methodHandle handle for invocation
- * @return new ScriptFunction
- */
- static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle) {
- return makeFunction(name, methodHandle, null);
- }
-
- @Override
- public ScriptFunction makeSynchronizedFunction(final Object sync) {
- final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
- return makeFunction(getName(), mh);
- }
-
- /**
- * Same as {@link ScriptFunction#makeBoundFunction(Object, Object[])}. The only reason we override it is so that we
- * can expose it.
- * @param self the self to bind to this function. Can be null (in which case, null is bound as this).
- * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
- * @return a function with the specified self and parameters bound.
- */
- @Override
- public ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
- return super.makeBoundFunction(self, args);
- }
-
- /**
- * This method is used to create a bound function based on this function.
- *
- * @param data the {@code ScriptFunctionData} specifying the functions immutable portion.
- * @return a function initialized from the specified data. Its parent scope will be set to null, therefore the
- * passed in data should not expect a callee.
- */
- @Override
- protected ScriptFunction makeBoundFunction(final ScriptFunctionData data) {
- return new BoundScriptFunctionImpl(data, getTargetFunction());
- }
-
- // return Object.prototype - used by "allocate"
- @Override
- protected final ScriptObject getObjectPrototype() {
- return Global.objectPrototype();
- }
-
- @Override
- public final Object getPrototype() {
- if (prototype == LAZY_PROTOTYPE) {
- prototype = new PrototypeObject(this);
- }
- return prototype;
- }
-
- @Override
- public final void setPrototype(final Object newProto) {
- if (newProto instanceof ScriptObject && newProto != this.prototype && allocatorMap != null) {
- // Replace our current allocator map with one that is associated with the new prototype.
- allocatorMap = allocatorMap.changeProto((ScriptObject)newProto);
- }
- this.prototype = newProto;
- }
-
- // Internals below..
- private void init(final Global global) {
- this.setInitialProto(global.getFunctionPrototype());
- this.prototype = LAZY_PROTOTYPE;
-
- // We have to fill user accessor functions late as these are stored
- // in this object rather than in the PropertyMap of this object.
- assert objectSpill == null;
- final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
- if (findProperty("arguments", true) != null) {
- initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
- }
- if (findProperty("caller", true) != null) {
- initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
- }
- }
-}
diff --git a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java
index 5fe6ee8..d1dde2e 100644
--- a/nashorn/src/jdk/nashorn/internal/parser/Lexer.java
+++ b/nashorn/src/jdk/nashorn/internal/parser/Lexer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -1451,9 +1451,22 @@
skip(3);
}
- // Scan identifier.
+ // Scan identifier. It might be quoted, indicating that no string editing should take place.
+ final char quoteChar = ch0;
+ final boolean noStringEditing = quoteChar == '"' || quoteChar == '\'';
+ if (noStringEditing) {
+ skip(1);
+ }
final int identStart = position;
final int identLength = scanIdentifier();
+ if (noStringEditing) {
+ if (ch0 != quoteChar) {
+ error(Lexer.message("here.non.matching.delimiter"), last, position, position);
+ restoreState(saved);
+ return false;
+ }
+ skip(1);
+ }
// Check for identifier.
if (identLength == 0) {
@@ -1523,7 +1536,7 @@
}
// Edit string if appropriate.
- if (scripting && !stringState.isEmpty()) {
+ if (!noStringEditing && !stringState.isEmpty()) {
editString(STRING, stringState);
} else {
// Add here string.
@@ -1640,9 +1653,9 @@
//and new Color(float, float, float) will get ambiguous for cases like
//new Color(1.0, 1.5, 1.5) if we don't respect the decimal point.
//yet we don't want e.g. 1e6 to be a double unnecessarily
- if (JSType.isRepresentableAsInt(value) && !JSType.isNegativeZero(value)) {
+ if (JSType.isStrictlyRepresentableAsInt(value)) {
return (int)value;
- } else if (JSType.isRepresentableAsLong(value) && !JSType.isNegativeZero(value)) {
+ } else if (JSType.isStrictlyRepresentableAsLong(value)) {
return (long)value;
}
return value;
diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java
index 167c8c4..cfdd599 100644
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java
@@ -84,7 +84,6 @@
import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
@@ -513,8 +512,7 @@
return lc.pop(functionNode).
setBody(lc, newBody).
- setLastToken(lc, lastToken).
- setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+ setLastToken(lc, lastToken);
}
/**
@@ -805,7 +803,7 @@
if (!oldStrictMode && directiveStmts != null) {
// check that directives preceding this one do not violate strictness
for (final Node statement : directiveStmts) {
- // the get value will force unescape of preceeding
+ // the get value will force unescape of preceding
// escaped string directives
getValue(statement.getToken());
}
@@ -2469,7 +2467,7 @@
// run: function() { println("run"); }
// };
//
- // The object literal following the "new Constructor()" expresssion
+ // The object literal following the "new Constructor()" expression
// is passed as an additional (last) argument to the constructor.
if (!env._no_syntax_extensions && type == LBRACE) {
arguments.add(objectLiteral());
@@ -2720,6 +2718,11 @@
}
if (isStatement) {
+ if (isAnonymous) {
+ appendStatement(new ExpressionStatement(functionLine, functionToken, finish, functionNode));
+ return functionNode;
+ }
+
final int varFlags = (topLevel || !useBlockScope()) ? 0 : VarNode.IS_LET;
final VarNode varNode = new VarNode(functionLine, functionToken, finish, name, functionNode, varFlags);
if (topLevel) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/AllocationStrategy.java b/nashorn/src/jdk/nashorn/internal/runtime/AllocationStrategy.java
index f25b588..5c4c03f 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/AllocationStrategy.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AllocationStrategy.java
@@ -29,6 +29,7 @@
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.ref.WeakReference;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@@ -53,6 +54,9 @@
/** lazily generated allocator */
private transient MethodHandle allocator;
+ /** Last used allocator map */
+ private transient AllocatorMap lastMap;
+
/**
* Construct an allocation strategy with the given map and class name.
* @param fieldCount number of fields in the allocated object
@@ -71,11 +75,49 @@
return allocatorClassName;
}
- PropertyMap getAllocatorMap() {
- // Create a new map for each function instance
- return PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+ /**
+ * Get the property map for the allocated object.
+ * @param prototype the prototype object
+ * @return the property map
+ */
+ synchronized PropertyMap getAllocatorMap(final ScriptObject prototype) {
+ assert prototype != null;
+ final PropertyMap protoMap = prototype.getMap();
+
+ if (lastMap != null) {
+ if (!lastMap.hasSharedProtoMap()) {
+ if (lastMap.hasSamePrototype(prototype)) {
+ return lastMap.allocatorMap;
+ }
+ if (lastMap.hasSameProtoMap(protoMap) && lastMap.hasUnchangedProtoMap()) {
+ // Convert to shared prototype map. Allocated objects will use the same property map
+ // that can be used as long as none of the prototypes modify the shared proto map.
+ final PropertyMap allocatorMap = PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+ final SharedPropertyMap sharedProtoMap = new SharedPropertyMap(protoMap);
+ allocatorMap.setSharedProtoMap(sharedProtoMap);
+ prototype.setMap(sharedProtoMap);
+ lastMap = new AllocatorMap(prototype, protoMap, allocatorMap);
+ return allocatorMap;
+ }
+ }
+
+ if (lastMap.hasValidSharedProtoMap() && lastMap.hasSameProtoMap(protoMap)) {
+ prototype.setMap(lastMap.getSharedProtoMap());
+ return lastMap.allocatorMap;
+ }
+ }
+
+ final PropertyMap allocatorMap = PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
+ lastMap = new AllocatorMap(prototype, protoMap, allocatorMap);
+
+ return allocatorMap;
}
+ /**
+ * Allocate an object with the given property map
+ * @param map the property map
+ * @return the allocated object
+ */
ScriptObject allocate(final PropertyMap map) {
try {
if (allocator == null) {
@@ -94,4 +136,43 @@
public String toString() {
return "AllocationStrategy[fieldCount=" + fieldCount + "]";
}
+
+ static class AllocatorMap {
+ final private WeakReference<ScriptObject> prototype;
+ final private WeakReference<PropertyMap> prototypeMap;
+
+ private PropertyMap allocatorMap;
+
+ AllocatorMap(final ScriptObject prototype, final PropertyMap protoMap, final PropertyMap allocMap) {
+ this.prototype = new WeakReference<>(prototype);
+ this.prototypeMap = new WeakReference<>(protoMap);
+ this.allocatorMap = allocMap;
+ }
+
+ boolean hasSamePrototype(final ScriptObject proto) {
+ return prototype.get() == proto;
+ }
+
+ boolean hasSameProtoMap(final PropertyMap protoMap) {
+ return prototypeMap.get() == protoMap || allocatorMap.getSharedProtoMap() == protoMap;
+ }
+
+ boolean hasUnchangedProtoMap() {
+ final ScriptObject proto = prototype.get();
+ return proto != null && proto.getMap() == prototypeMap.get();
+ }
+
+ boolean hasSharedProtoMap() {
+ return getSharedProtoMap() != null;
+ }
+
+ boolean hasValidSharedProtoMap() {
+ return hasSharedProtoMap() && getSharedProtoMap().isValidSharedProtoMap();
+ }
+
+ PropertyMap getSharedProtoMap() {
+ return allocatorMap.getSharedProtoMap();
+ }
+
+ }
}
diff --git a/nashorn/src/jdk/nashorn/internal/codegen/AstSerializer.java b/nashorn/src/jdk/nashorn/internal/runtime/AstSerializer.java
similarity index 73%
rename from nashorn/src/jdk/nashorn/internal/codegen/AstSerializer.java
rename to nashorn/src/jdk/nashorn/internal/runtime/AstSerializer.java
index dc35f96..35036d8 100644
--- a/nashorn/src/jdk/nashorn/internal/codegen/AstSerializer.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AstSerializer.java
@@ -22,20 +22,14 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-package jdk.nashorn.internal.codegen;
+package jdk.nashorn.internal.runtime;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
-import java.util.Collections;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
-import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.FunctionNode;
-import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.Statement;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.options.Options;
/**
@@ -50,7 +44,7 @@
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Deflater deflater = new Deflater(COMPRESSION_LEVEL);
try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) {
- oout.writeObject(removeInnerFunctionBodies(fn));
+ oout.writeObject(fn);
} catch (final IOException e) {
throw new AssertionError("Unexpected exception serializing function", e);
} finally {
@@ -58,16 +52,4 @@
}
return out.toByteArray();
}
-
- private static FunctionNode removeInnerFunctionBodies(final FunctionNode fn) {
- return (FunctionNode)fn.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
- @Override
- public Node leaveBlock(final Block block) {
- if (lc.isFunctionBody() && lc.getFunction(block) != lc.getOutermostFunction()) {
- return block.setStatements(lc, Collections.<Statement>emptyList());
- }
- return super.leaveBlock(block);
- }
- });
- }
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java
index 49b5b0e..dc6ed09 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/CodeInstaller.java
@@ -38,15 +38,14 @@
* The compiler still retains most of the state around code emission
* and management internally, so this is to avoid passing around any
* logic that isn't directly related to installing a class
- * @param <T> owner class type for this code installer
*
*/
-public interface CodeInstaller<T> {
+public interface CodeInstaller {
/**
- * Return the owner for the CodeInstaller, e.g. a {@link Context}
- * @return owner
+ * Return the {@link Context} associated with this code installer.
+ * @return the context.
*/
- public T getOwner();
+ public Context getContext();
/**
* Install a class.
@@ -106,7 +105,7 @@
* new, independent class loader.
* @return a new code installer with a new independent class loader.
*/
- public CodeInstaller<T> withNewLoader();
+ public CodeInstaller withNewLoader();
/**
* Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
@@ -115,6 +114,6 @@
* @param other the other code installer tested for compatibility with this code installer.
* @return true if this code installer is compatible with the other code installer.
*/
- public boolean isCompatibleWith(CodeInstaller<T> other);
+ public boolean isCompatibleWith(CodeInstaller other);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java
index 371ecac..63889cc 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -27,6 +27,7 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
+
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -101,7 +102,7 @@
/*
* An optimistic builtin with isOptimistic=true works like any optimistic generated function, i.e. it
* can throw unwarranted optimism exceptions. As native functions trivially can't have parts of them
- * regenerated as restof methods, this only works if the methods are atomic/functional in their behavior
+ * regenerated as "restOf" methods, this only works if the methods are atomic/functional in their behavior
* and doesn't modify state before an UOE can be thrown. If they aren't, we can reexecute a wider version
* of the same builtin in a recompilation handler for FinalScriptFunctionData. There are several
* candidate methods in Native* that would benefit from this, but I haven't had time to implement any
@@ -566,7 +567,7 @@
return handle;
}
- // Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itslef
+ // Otherwise, we need a new level of indirection; need to introduce a mutable call site that can relink itself
// to the compiled function's changed target whenever the optimistic assumptions are invalidated.
final CallSite cs = new MutableCallSite(handle.type());
relinkComposableInvoker(cs, this, isConstructor);
@@ -820,7 +821,7 @@
// isn't available, we'll use the old one bound into the call site.
final OptimismInfo effectiveOptInfo = currentOptInfo != null ? currentOptInfo : oldOptInfo;
FunctionNode fn = effectiveOptInfo.reparse();
- final boolean serialized = effectiveOptInfo.isSerialized();
+ final boolean cached = fn.isCached();
final Compiler compiler = effectiveOptInfo.getCompiler(fn, ct, re); //set to non rest-of
if (!shouldRecompile) {
@@ -828,11 +829,11 @@
// recompiled a deoptimized version for an inner invocation.
// We still need to do the rest of from the beginning
logRecompile("Rest-of compilation [STANDALONE] ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
- return restOfHandle(effectiveOptInfo, compiler.compile(fn, serialized ? CompilationPhases.COMPILE_SERIALIZED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
+ return restOfHandle(effectiveOptInfo, compiler.compile(fn, cached ? CompilationPhases.COMPILE_CACHED_RESTOF : CompilationPhases.COMPILE_ALL_RESTOF), currentOptInfo != null);
}
logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
- fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
+ fn = compiler.compile(fn, cached ? CompilationPhases.RECOMPILE_CACHED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
log.fine("Reusable IR generated");
// compile the rest of the function, and install it
@@ -956,10 +957,6 @@
FunctionNode reparse() {
return data.reparse();
}
-
- boolean isSerialized() {
- return data.isSerialized();
- }
}
@SuppressWarnings("unused")
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
index f4e4272..0d82136 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java
@@ -153,7 +153,7 @@
* Currently we are conservative and associate the name of a builtin class with all
* its properties, so it's enough to invalidate a property to break all assumptions
* about a prototype. This can be changed to a more fine grained approach, but no one
- * ever needs this, given the very rare occurance of swapping out only parts of
+ * ever needs this, given the very rare occurrence of swapping out only parts of
* a builtin v.s. the entire builtin object
*/
private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
@@ -167,7 +167,7 @@
* ContextCodeInstaller that has the privilege of installing classes in the Context.
* Can only be instantiated from inside the context and is opaque to other classes
*/
- public static class ContextCodeInstaller implements CodeInstaller<ScriptEnvironment> {
+ public static class ContextCodeInstaller implements CodeInstaller {
private final Context context;
private final ScriptLoader loader;
private final CodeSource codeSource;
@@ -185,13 +185,9 @@
this.codeSource = codeSource;
}
- /**
- * Return the script environment for this installer
- * @return ScriptEnvironment
- */
@Override
- public ScriptEnvironment getOwner() {
- return context.env;
+ public Context getContext() {
+ return context;
}
@Override
@@ -254,7 +250,7 @@
}
@Override
- public CodeInstaller<ScriptEnvironment> withNewLoader() {
+ public CodeInstaller withNewLoader() {
// Reuse this installer if we're within our limits.
if (usageCount < MAX_USAGES && bytesDefined < MAX_BYTES_DEFINED) {
return this;
@@ -263,7 +259,7 @@
}
@Override
- public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
+ public boolean isCompatibleWith(final CodeInstaller other) {
if (other instanceof ContextCodeInstaller) {
final ContextCodeInstaller cci = (ContextCodeInstaller)other;
return cci.context == context && cci.codeSource == codeSource;
@@ -987,6 +983,16 @@
}
/**
+ * Is {@code className} the name of a structure class?
+ *
+ * @param className a class name
+ * @return true if className is a structure class name
+ */
+ public static boolean isStructureClass(final String className) {
+ return StructureLoader.isStructureClass(className);
+ }
+
+ /**
* Checks that the given Class can be accessed from no permissions context.
*
* @param clazz Class object
@@ -1129,17 +1135,16 @@
*
* @param global the global
* @param engine the associated ScriptEngine instance, can be null
- * @param ctxt the initial ScriptContext, can be null
* @return the initialized global scope object.
*/
- public Global initGlobal(final Global global, final ScriptEngine engine, final ScriptContext ctxt) {
+ public Global initGlobal(final Global global, final ScriptEngine engine) {
// Need only minimal global object, if we are just compiling.
if (!env._compile_only) {
final Global oldGlobal = Context.getGlobal();
try {
Context.setGlobal(global);
// initialize global scope with builtin global objects
- global.initBuiltinObjects(engine, ctxt);
+ global.initBuiltinObjects(engine);
} finally {
Context.setGlobal(oldGlobal);
}
@@ -1155,7 +1160,7 @@
* @return the initialized global scope object.
*/
public Global initGlobal(final Global global) {
- return initGlobal(global, null, null);
+ return initGlobal(global, null);
}
/**
@@ -1300,14 +1305,12 @@
final URL url = source.getURL();
final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader;
final CodeSource cs = new CodeSource(url, (CodeSigner[])null);
- final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs);
+ final CodeInstaller installer = new ContextCodeInstaller(this, loader, cs);
if (storedScript == null) {
final CompilationPhases phases = Compiler.CompilationPhases.COMPILE_ALL;
- final Compiler compiler = new Compiler(
- this,
- env,
+ final Compiler compiler = Compiler.forInitialCompilation(
installer,
source,
errMan,
@@ -1456,7 +1459,7 @@
* @param level log level
* @param mh method handle
* @param paramStart first parameter to print
- * @param printReturnValue should we print the return vaulue?
+ * @param printReturnValue should we print the return value?
* @param text debug printout to add
*
* @return instrumented method handle, or null if logger not enabled
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Debug.java b/nashorn/src/jdk/nashorn/internal/runtime/Debug.java
index a2d136f..7010319 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Debug.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Debug.java
@@ -26,6 +26,8 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.parser.TokenType.EOF;
+
+import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenStream;
@@ -63,6 +65,15 @@
}
/**
+ * Return a formatted script stack trace string with frames information separated by '\n'.
+ * This is a shortcut for {@code NashornException.getScriptStackString(new Throwable())}.
+ * @return formatted stack trace string
+ */
+ public static String scriptStack() {
+ return NashornException.getScriptStackString(new Throwable());
+ }
+
+ /**
* Return the system identity hashcode for an object as a human readable
* string
*
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
index c868aab..4ea286e 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -27,6 +27,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
+import java.util.Collection;
import java.util.List;
/**
@@ -72,11 +73,6 @@
}
@Override
- boolean isRecompilable() {
- return false;
- }
-
- @Override
protected boolean needsCallee() {
final boolean needsCallee = code.getFirst().needsCallee();
assert allNeedCallee(needsCallee);
@@ -93,6 +89,20 @@
}
@Override
+ CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ assert isValidCallSite(callSiteType) : callSiteType;
+
+ CompiledFunction best = null;
+ for (final CompiledFunction candidate: code) {
+ if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
+ best = candidate;
+ }
+ }
+
+ return best;
+ }
+
+ @Override
MethodType getGenericType() {
// We need to ask the code for its generic type. We can't just rely on this function data's arity, as it's not
// actually correct for lots of built-ins. E.g. ECMAScript 5.1 section 15.5.3.2 prescribes that
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java
index 3b153c5..98ddf24 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/FindProperty.java
@@ -297,4 +297,3 @@
}
}
-
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java
index cd1061c..7f93e70 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalConstants.java
@@ -67,7 +67,7 @@
*
* Thus everything registered as a global constant gets an extra chance. Set once,
* reregister the switchpoint. Set twice or more - don't try again forever, or we'd
- * just end up relinking our way into megamorphisism.
+ * just end up relinking our way into megamorphism.
*
* Also it has to be noted that this kind of linking creates a coupling between a Global
* and the call sites in compiled code belonging to the Context. For this reason, the
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
index c7094ad..eec1fae 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
@@ -187,14 +187,14 @@
double result = 0.0;
int digit;
- // we should see atleast one valid digit
+ // we should see at least one valid digit
boolean entered = false;
while (idx < length) {
digit = fastDigit(str.charAt(idx++), radix);
if (digit < 0) {
break;
}
- // we have seen atleast one valid digit in the specified radix
+ // we have seen at least one valid digit in the specified radix
entered = true;
result *= radix;
result += digit;
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
index d5f3af7..d265e6d 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime;
import java.lang.invoke.MethodHandle;
-import java.util.Iterator;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.JSONParser;
@@ -104,16 +103,28 @@
final Object val = holder.get(name);
if (val instanceof ScriptObject) {
final ScriptObject valueObj = (ScriptObject)val;
- final Iterator<String> iter = valueObj.propertyIterator();
+ if (valueObj.isArray()) {
+ final int length = JSType.toInteger(valueObj.getLength());
+ for (int i = 0; i < length; i++) {
+ final String key = Integer.toString(i);
+ final Object newElement = walk(valueObj, key, reviver);
- while (iter.hasNext()) {
- final String key = iter.next();
- final Object newElement = walk(valueObj, key, reviver);
+ if (newElement == ScriptRuntime.UNDEFINED) {
+ valueObj.delete(i, false);
+ } else {
+ setPropertyValue(valueObj, key, newElement);
+ }
+ }
+ } else {
+ final String[] keys = valueObj.getOwnKeys(false);
+ for (final String key : keys) {
+ final Object newElement = walk(valueObj, key, reviver);
- if (newElement == ScriptRuntime.UNDEFINED) {
- valueObj.delete(key, false);
- } else {
- setPropertyValue(valueObj, key, newElement);
+ if (newElement == ScriptRuntime.UNDEFINED) {
+ valueObj.delete(key, false);
+ } else {
+ setPropertyValue(valueObj, key, newElement);
+ }
}
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
index f80ddc3..0c81eeb 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java
@@ -377,8 +377,8 @@
}
/**
- * Returns true if double number can be represented as an int. Note that it returns true for negative zero. If you
- * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}.
+ * Returns true if double number can be represented as an int. Note that it returns true for negative
+ * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsInt(double)}.
*
* @param number a double to inspect
*
@@ -389,6 +389,18 @@
}
/**
+ * Returns true if double number can be represented as an int. Note that it returns false for negative
+ * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsInt(double)}.
+ *
+ * @param number a double to inspect
+ *
+ * @return true for int representable doubles
+ */
+ public static boolean isStrictlyRepresentableAsInt(final double number) {
+ return isRepresentableAsInt(number) && isNotNegativeZero(number);
+ }
+
+ /**
* Returns true if Object can be represented as an int
*
* @param obj an object to inspect
@@ -403,8 +415,8 @@
}
/**
- * Returns true if double number can be represented as a long. Note that it returns true for negative zero. If you
- * need to exclude negative zero, combine this check with {@link #isNegativeZero(double)}.
+ * Returns true if double number can be represented as a long. Note that it returns true for negative
+ * zero. If you need to exclude negative zero, use {@link #isStrictlyRepresentableAsLong(double)}.
*
* @param number a double to inspect
* @return true for long representable doubles
@@ -414,6 +426,18 @@
}
/**
+ * Returns true if double number can be represented as a long. Note that it returns false for negative
+ * zero. If you don't need to distinguish negative zero, use {@link #isRepresentableAsLong(double)}.
+ *
+ * @param number a double to inspect
+ *
+ * @return true for long representable doubles
+ */
+ public static boolean isStrictlyRepresentableAsLong(final double number) {
+ return isRepresentableAsLong(number) && isNotNegativeZero(number);
+ }
+
+ /**
* Returns true if Object can be represented as a long
*
* @param obj an object to inspect
@@ -428,12 +452,12 @@
}
/**
- * Returns true if the number is the negative zero ({@code -0.0d}).
+ * Returns true if the number is not the negative zero ({@code -0.0d}).
* @param number the number to test
- * @return true if it is the negative zero, false otherwise.
+ * @return true if it is not the negative zero, false otherwise.
*/
- public static boolean isNegativeZero(final double number) {
- return number == 0.0d && Double.doubleToRawLongBits(number) == 0x8000000000000000L;
+ private static boolean isNotNegativeZero(final double number) {
+ return Double.doubleToRawLongBits(number) != 0x8000000000000000L;
}
/**
@@ -1944,7 +1968,7 @@
/**
* Get the unboxed (primitive) type for an object
* @param o object
- * @return primive type or Object.class if not primitive
+ * @return primitive type or Object.class if not primitive
*/
public static Class<?> unboxedFieldType(final Object o) {
if (o == null) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
index 2d110e0..5153a27 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java
@@ -206,7 +206,7 @@
}
@Override
- protected Object invokeNoSuchProperty(final String key, final int programPoint) {
+ protected Object invokeNoSuchProperty(final String key, final boolean isScope, final int programPoint) {
final Object retval = createProperty(key);
if (isValid(programPoint)) {
throw new UnwarrantedOptimismException(retval, programPoint);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java b/nashorn/src/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java
index e93fe60..9b53863 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/OptimisticReturnFilters.java
@@ -184,7 +184,7 @@
@SuppressWarnings("unused")
private static int ensureInt(final double arg, final int programPoint) {
- if (JSType.isRepresentableAsInt(arg) && !JSType.isNegativeZero(arg)) {
+ if (JSType.isStrictlyRepresentableAsInt(arg)) {
return (int)arg;
}
throw new UnwarrantedOptimismException(arg, programPoint);
@@ -206,7 +206,7 @@
// Long into the exception.
if (isPrimitiveNumberWrapper(arg)) {
final double d = ((Number)arg).doubleValue();
- if (JSType.isRepresentableAsInt(d) && !JSType.isNegativeZero(d)) {
+ if (JSType.isStrictlyRepresentableAsInt(d)) {
return (int)d;
}
}
@@ -239,7 +239,7 @@
}
private static long ensureLong(final double arg, final int programPoint) {
- if (JSType.isRepresentableAsLong(arg) && !JSType.isNegativeZero(arg)) {
+ if (JSType.isStrictlyRepresentableAsLong(arg)) {
return (long)arg;
}
throw new UnwarrantedOptimismException(arg, programPoint);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
index 5137d59..696e1d7 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ParserException.java
@@ -38,7 +38,7 @@
private final Source source;
// token responsible for this exception
private final long token;
- // if this is traslated as ECMA error, which type should be used?
+ // if this is translated as ECMA error, which type should be used?
private final JSErrorType errorType;
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Property.java b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
index 7d54420..71372be 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java
@@ -562,8 +562,8 @@
@Override
public int hashCode() {
- final Class<?> type = getLocalType();
- return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode());
+ final Class<?> t = getLocalType();
+ return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (t == null ? 0 : t.hashCode());
}
@Override
@@ -588,7 +588,7 @@
getKey().equals(otherProperty.getKey());
}
- private static final String type(final Class<?> type) {
+ private static String type(final Class<?> type) {
if (type == null) {
return "undef";
} else if (type == int.class) {
@@ -608,8 +608,8 @@
*/
public final String toStringShort() {
final StringBuilder sb = new StringBuilder();
- final Class<?> type = getLocalType();
- sb.append(getKey()).append(" (").append(type(type)).append(')');
+ final Class<?> t = getLocalType();
+ sb.append(getKey()).append(" (").append(type(t)).append(')');
return sb.toString();
}
@@ -625,7 +625,7 @@
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- final Class<?> type = getLocalType();
+ final Class<?> t = getLocalType();
sb.append(indent(getKey(), 20)).
append(" id=").
@@ -635,7 +635,7 @@
append(") ").
append(getClass().getSimpleName()).
append(" {").
- append(indent(type(type), 5)).
+ append(indent(type(t), 5)).
append('}');
if (slot != -1) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java
index 03b2c93..e4ecad7 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListeners.java
@@ -28,6 +28,7 @@
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.LongAdder;
/**
* Helper class to manage property listeners and notification.
@@ -37,8 +38,15 @@
private Map<String, WeakPropertyMapSet> listeners;
// These counters are updated in debug mode
- private static int listenersAdded;
- private static int listenersRemoved;
+ private static LongAdder listenersAdded;
+ private static LongAdder listenersRemoved;
+
+ static {
+ if (Context.DEBUG) {
+ listenersAdded = new LongAdder();
+ listenersRemoved = new LongAdder();
+ }
+ }
/**
* Copy constructor
@@ -54,29 +62,33 @@
* Return aggregate listeners added to all PropertyListenerManagers
* @return the listenersAdded
*/
- public static int getListenersAdded() {
- return listenersAdded;
+ public static long getListenersAdded() {
+ return listenersAdded.longValue();
}
/**
* Return aggregate listeners removed from all PropertyListenerManagers
* @return the listenersRemoved
*/
- public static int getListenersRemoved() {
- return listenersRemoved;
+ public static long getListenersRemoved() {
+ return listenersRemoved.longValue();
}
/**
- * Return listeners added to this ScriptObject.
+ * Return number of listeners added to a ScriptObject.
* @param obj the object
* @return the listener count
*/
public static int getListenerCount(final ScriptObject obj) {
- final PropertyListeners propertyListeners = obj.getMap().getListeners();
- if (propertyListeners != null) {
- return propertyListeners.listeners == null ? 0 : propertyListeners.listeners.size();
- }
- return 0;
+ return obj.getMap().getListenerCount();
+ }
+
+ /**
+ * Return the number of listeners added to this PropertyListeners instance.
+ * @return the listener count;
+ */
+ public int getListenerCount() {
+ return listeners == null ? 0 : listeners.size();
}
// Property listener management methods
@@ -122,7 +134,7 @@
*/
synchronized final void addListener(final String key, final PropertyMap propertyMap) {
if (Context.DEBUG) {
- listenersAdded++;
+ listenersAdded.increment();
}
if (listeners == null) {
listeners = new WeakHashMap<>();
@@ -148,9 +160,12 @@
final WeakPropertyMapSet set = listeners.get(prop.getKey());
if (set != null) {
for (final PropertyMap propertyMap : set.elements()) {
- propertyMap.propertyAdded(prop);
+ propertyMap.propertyAdded(prop, false);
}
listeners.remove(prop.getKey());
+ if (Context.DEBUG) {
+ listenersRemoved.increment();
+ }
}
}
}
@@ -165,9 +180,12 @@
final WeakPropertyMapSet set = listeners.get(prop.getKey());
if (set != null) {
for (final PropertyMap propertyMap : set.elements()) {
- propertyMap.propertyDeleted(prop);
+ propertyMap.propertyDeleted(prop, false);
}
listeners.remove(prop.getKey());
+ if (Context.DEBUG) {
+ listenersRemoved.increment();
+ }
}
}
}
@@ -184,9 +202,12 @@
final WeakPropertyMapSet set = listeners.get(oldProp.getKey());
if (set != null) {
for (final PropertyMap propertyMap : set.elements()) {
- propertyMap.propertyModified(oldProp, newProp);
+ propertyMap.propertyModified(oldProp, newProp, false);
}
listeners.remove(oldProp.getKey());
+ if (Context.DEBUG) {
+ listenersRemoved.increment();
+ }
}
}
}
@@ -198,7 +219,7 @@
if (listeners != null) {
for (final WeakPropertyMapSet set : listeners.values()) {
for (final PropertyMap propertyMap : set.elements()) {
- propertyMap.protoChanged();
+ propertyMap.protoChanged(false);
}
}
listeners.clear();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java
index fbc0dbb..cb791b0 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java
@@ -34,7 +34,9 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.invoke.SwitchPoint;
+import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
@@ -42,6 +44,8 @@
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.LongAdder;
+import jdk.nashorn.internal.runtime.options.Options;
import jdk.nashorn.internal.scripts.JO;
/**
@@ -53,35 +57,49 @@
* All property maps are immutable. If a property is added, modified or removed, the mutator
* will return a new map.
*/
-public final class PropertyMap implements Iterable<Object>, Serializable {
+public class PropertyMap implements Iterable<Object>, Serializable {
+ private static final int INITIAL_SOFT_REFERENCE_DERIVATION_LIMIT =
+ Math.max(0, Options.getIntProperty("nashorn.propertyMap.softReferenceDerivationLimit", 32));
+
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
- public static final int NOT_EXTENSIBLE = 0b0000_0001;
+ private static final int NOT_EXTENSIBLE = 0b0000_0001;
/** Does this map contain valid array keys? */
- public static final int CONTAINS_ARRAY_KEYS = 0b0000_0010;
+ private static final int CONTAINS_ARRAY_KEYS = 0b0000_0010;
/** Map status flags. */
- private int flags;
+ private final int flags;
/** Map of properties. */
private transient PropertyHashMap properties;
/** Number of fields in use. */
- private int fieldCount;
+ private final int fieldCount;
/** Number of fields available. */
private final int fieldMaximum;
/** Length of spill in use. */
- private int spillLength;
+ private final int spillLength;
/** Structure class name */
- private String className;
+ private final String className;
+
+ /**
+ * Countdown of number of times this property map has been derived from another property map. When it
+ * reaches zero, the property map will start using weak references instead of soft references to hold on
+ * to its history elements.
+ */
+ private final int softReferenceDerivationLimit;
+
+ /** A reference to the expected shared prototype property map. If this is set this
+ * property map should only be used if it the same as the actual prototype map. */
+ private transient SharedPropertyMap sharedProtoMap;
/** {@link SwitchPoint}s for gets on inherited properties. */
- private transient HashMap<String, SwitchPoint> protoGetSwitches;
+ private transient HashMap<String, SwitchPoint> protoSwitches;
/** History of maps, used to limit map duplication. */
- private transient WeakHashMap<Property, SoftReference<PropertyMap>> history;
+ private transient WeakHashMap<Property, Reference<PropertyMap>> history;
/** History of prototypes, used to limit map duplication. */
private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory;
@@ -94,59 +112,60 @@
private static final long serialVersionUID = -7041836752008732533L;
/**
- * Constructor.
+ * Constructs a new property map.
*
* @param properties A {@link PropertyHashMap} with initial contents.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
* @param spillLength Number of spill slots used.
- * @param containsArrayKeys True if properties contain numeric keys
*/
- private PropertyMap(final PropertyHashMap properties, final String className, final int fieldCount,
- final int fieldMaximum, final int spillLength, final boolean containsArrayKeys) {
+ private PropertyMap(final PropertyHashMap properties, final int flags, final String className,
+ final int fieldCount, final int fieldMaximum, final int spillLength) {
this.properties = properties;
this.className = className;
this.fieldCount = fieldCount;
this.fieldMaximum = fieldMaximum;
this.spillLength = spillLength;
- if (containsArrayKeys) {
- setContainsArrayKeys();
- }
+ this.flags = flags;
+ this.softReferenceDerivationLimit = INITIAL_SOFT_REFERENCE_DERIVATION_LIMIT;
if (Context.DEBUG) {
- count++;
+ count.increment();
}
}
/**
- * Cloning constructor.
+ * Constructs a clone of {@code propertyMap} with changed properties, flags, or boundaries.
*
* @param propertyMap Existing property map.
* @param properties A {@link PropertyHashMap} with a new set of properties.
*/
- private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties) {
+ private PropertyMap(final PropertyMap propertyMap, final PropertyHashMap properties, final int flags, final int fieldCount, final int spillLength, final int softReferenceDerivationLimit) {
this.properties = properties;
- this.flags = propertyMap.flags;
- this.spillLength = propertyMap.spillLength;
- this.fieldCount = propertyMap.fieldCount;
+ this.flags = flags;
+ this.spillLength = spillLength;
+ this.fieldCount = fieldCount;
this.fieldMaximum = propertyMap.fieldMaximum;
+ this.className = propertyMap.className;
// We inherit the parent property listeners instance. It will be cloned when a new listener is added.
this.listeners = propertyMap.listeners;
this.freeSlots = propertyMap.freeSlots;
+ this.sharedProtoMap = propertyMap.sharedProtoMap;
+ this.softReferenceDerivationLimit = softReferenceDerivationLimit;
if (Context.DEBUG) {
- count++;
- clonedCount++;
+ count.increment();
+ clonedCount.increment();
}
}
/**
- * Cloning constructor.
+ * Constructs an exact clone of {@code propertyMap}.
*
* @param propertyMap Existing property map.
*/
- private PropertyMap(final PropertyMap propertyMap) {
- this(propertyMap, propertyMap.properties);
+ protected PropertyMap(final PropertyMap propertyMap) {
+ this(propertyMap, propertyMap.properties, propertyMap.flags, propertyMap.fieldCount, propertyMap.spillLength, propertyMap.softReferenceDerivationLimit);
}
private void writeObject(final ObjectOutputStream out) throws IOException {
@@ -182,7 +201,7 @@
*/
public static PropertyMap newMap(final Collection<Property> properties, final String className, final int fieldCount, final int fieldMaximum, final int spillLength) {
final PropertyHashMap newProperties = EMPTY_HASHMAP.immutableAdd(properties);
- return new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength, false);
+ return new PropertyMap(newProperties, 0, className, fieldCount, fieldMaximum, spillLength);
}
/**
@@ -204,7 +223,7 @@
* @return New empty {@link PropertyMap}.
*/
public static PropertyMap newMap(final Class<? extends ScriptObject> clazz) {
- return new PropertyMap(EMPTY_HASHMAP, clazz.getName(), 0, 0, 0, false);
+ return new PropertyMap(EMPTY_HASHMAP, 0, clazz.getName(), 0, 0, 0);
}
/**
@@ -226,12 +245,12 @@
}
/**
- * Get the listeners of this map, or null if none exists
+ * Get the number of listeners of this map
*
- * @return the listeners
+ * @return the number of listeners
*/
- public PropertyListeners getListeners() {
- return listeners;
+ public int getListenerCount() {
+ return listeners == null ? 0 : listeners.getListenerCount();
}
/**
@@ -252,9 +271,12 @@
* A new property is being added.
*
* @param property The new Property added.
+ * @param isSelf was the property added to this map?
*/
- public void propertyAdded(final Property property) {
- invalidateProtoGetSwitchPoint(property);
+ public void propertyAdded(final Property property, final boolean isSelf) {
+ if (!isSelf) {
+ invalidateProtoSwitchPoint(property.getKey());
+ }
if (listeners != null) {
listeners.propertyAdded(property);
}
@@ -264,9 +286,12 @@
* An existing property is being deleted.
*
* @param property The property being deleted.
+ * @param isSelf was the property deleted from this map?
*/
- public void propertyDeleted(final Property property) {
- invalidateProtoGetSwitchPoint(property);
+ public void propertyDeleted(final Property property, final boolean isSelf) {
+ if (!isSelf) {
+ invalidateProtoSwitchPoint(property.getKey());
+ }
if (listeners != null) {
listeners.propertyDeleted(property);
}
@@ -277,9 +302,12 @@
*
* @param oldProperty The old property
* @param newProperty The new property
+ * @param isSelf was the property modified on this map?
*/
- public void propertyModified(final Property oldProperty, final Property newProperty) {
- invalidateProtoGetSwitchPoint(oldProperty);
+ public void propertyModified(final Property oldProperty, final Property newProperty, final boolean isSelf) {
+ if (!isSelf) {
+ invalidateProtoSwitchPoint(oldProperty.getKey());
+ }
if (listeners != null) {
listeners.propertyModified(oldProperty, newProperty);
}
@@ -287,9 +315,15 @@
/**
* The prototype of an object associated with this {@link PropertyMap} is changed.
+ *
+ * @param isSelf was the prototype changed on the object using this map?
*/
- public void protoChanged() {
- invalidateAllProtoGetSwitchPoints();
+ public void protoChanged(final boolean isSelf) {
+ if (!isSelf) {
+ invalidateAllProtoSwitchPoints();
+ } else if (sharedProtoMap != null) {
+ sharedProtoMap.invalidateSwitchPoint();
+ }
if (listeners != null) {
listeners.protoChanged();
}
@@ -302,14 +336,14 @@
* @return A shared {@link SwitchPoint} for the property.
*/
public synchronized SwitchPoint getSwitchPoint(final String key) {
- if (protoGetSwitches == null) {
- protoGetSwitches = new HashMap<>();
+ if (protoSwitches == null) {
+ protoSwitches = new HashMap<>();
}
- SwitchPoint switchPoint = protoGetSwitches.get(key);
+ SwitchPoint switchPoint = protoSwitches.get(key);
if (switchPoint == null) {
switchPoint = new SwitchPoint();
- protoGetSwitches.put(key, switchPoint);
+ protoSwitches.put(key, switchPoint);
}
return switchPoint;
@@ -318,19 +352,17 @@
/**
* Indicate that a prototype property has changed.
*
- * @param property {@link Property} to invalidate.
+ * @param key {@link Property} key to invalidate.
*/
- synchronized void invalidateProtoGetSwitchPoint(final Property property) {
- if (protoGetSwitches != null) {
-
- final String key = property.getKey();
- final SwitchPoint sp = protoGetSwitches.get(key);
+ synchronized void invalidateProtoSwitchPoint(final String key) {
+ if (protoSwitches != null) {
+ final SwitchPoint sp = protoSwitches.get(key);
if (sp != null) {
- protoGetSwitches.remove(key);
+ protoSwitches.remove(key);
if (Context.DEBUG) {
- protoInvalidations++;
+ protoInvalidations.increment();
}
- SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+ SwitchPoint.invalidateAll(new SwitchPoint[]{sp});
}
}
}
@@ -338,15 +370,15 @@
/**
* Indicate that proto itself has changed in hierarchy somewhere.
*/
- synchronized void invalidateAllProtoGetSwitchPoints() {
- if (protoGetSwitches != null) {
- final int size = protoGetSwitches.size();
+ synchronized void invalidateAllProtoSwitchPoints() {
+ if (protoSwitches != null) {
+ final int size = protoSwitches.size();
if (size > 0) {
if (Context.DEBUG) {
- protoInvalidations += size;
+ protoInvalidations.add(size);
}
- SwitchPoint.invalidateAll(protoGetSwitches.values().toArray(new SwitchPoint[size]));
- protoGetSwitches.clear();
+ SwitchPoint.invalidateAll(protoSwitches.values().toArray(new SwitchPoint[size]));
+ protoSwitches.clear();
}
}
}
@@ -362,7 +394,7 @@
* @return New {@link PropertyMap} with {@link Property} added.
*/
PropertyMap addPropertyBind(final AccessorProperty property, final Object bindTo) {
- // No need to store bound property in the history as bound properties can't be reused.
+ // We must not store bound property in the history as bound properties can't be reused.
return addPropertyNoHistory(new AccessorProperty(property, bindTo));
}
@@ -375,16 +407,16 @@
return property.isSpill() ? slot + fieldMaximum : slot;
}
- // Update boundaries and flags after a property has been added
- private void updateFlagsAndBoundaries(final Property newProperty) {
- if(newProperty.isSpill()) {
- spillLength = Math.max(spillLength, newProperty.getSlot() + 1);
- } else {
- fieldCount = Math.max(fieldCount, newProperty.getSlot() + 1);
- }
- if (isValidArrayIndex(getArrayIndex(newProperty.getKey()))) {
- setContainsArrayKeys();
- }
+ private int newSpillLength(final Property newProperty) {
+ return newProperty.isSpill() ? Math.max(spillLength, newProperty.getSlot() + 1) : spillLength;
+ }
+
+ private int newFieldCount(final Property newProperty) {
+ return !newProperty.isSpill() ? Math.max(fieldCount, newProperty.getSlot() + 1) : fieldCount;
+ }
+
+ private int newFlags(final Property newProperty) {
+ return isValidArrayIndex(getArrayIndex(newProperty.getKey())) ? flags | CONTAINS_ARRAY_KEYS : flags;
}
// Update the free slots bitmap for a property that has been deleted and/or added. This method is not synchronized
@@ -419,16 +451,9 @@
* @param property {@link Property} being added.
* @return New {@link PropertyMap} with {@link Property} added.
*/
- public PropertyMap addPropertyNoHistory(final Property property) {
- if (listeners != null) {
- listeners.propertyAdded(property);
- }
- final PropertyHashMap newProperties = properties.immutableAdd(property);
- final PropertyMap newMap = new PropertyMap(this, newProperties);
- newMap.updateFlagsAndBoundaries(property);
- newMap.updateFreeSlots(null, property);
-
- return newMap;
+ public final PropertyMap addPropertyNoHistory(final Property property) {
+ propertyAdded(property, true);
+ return addPropertyInternal(property);
}
/**
@@ -438,23 +463,29 @@
*
* @return New {@link PropertyMap} with {@link Property} added.
*/
- public synchronized PropertyMap addProperty(final Property property) {
- if (listeners != null) {
- listeners.propertyAdded(property);
- }
+ public final synchronized PropertyMap addProperty(final Property property) {
+ propertyAdded(property, true);
PropertyMap newMap = checkHistory(property);
if (newMap == null) {
- final PropertyHashMap newProperties = properties.immutableAdd(property);
- newMap = new PropertyMap(this, newProperties);
- newMap.updateFlagsAndBoundaries(property);
- newMap.updateFreeSlots(null, property);
+ newMap = addPropertyInternal(property);
addToHistory(property, newMap);
}
return newMap;
}
+ private PropertyMap deriveMap(final PropertyHashMap newProperties, final int newFlags, final int newFieldCount, final int newSpillLength) {
+ return new PropertyMap(this, newProperties, newFlags, newFieldCount, newSpillLength, softReferenceDerivationLimit == 0 ? 0 : softReferenceDerivationLimit - 1);
+ }
+
+ private PropertyMap addPropertyInternal(final Property property) {
+ final PropertyHashMap newProperties = properties.immutableAdd(property);
+ final PropertyMap newMap = deriveMap(newProperties, newFlags(property), newFieldCount(property), newSpillLength(property));
+ newMap.updateFreeSlots(null, property);
+ return newMap;
+ }
+
/**
* Remove a property from a map. Cloning or using an existing map if available.
*
@@ -462,10 +493,8 @@
*
* @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found.
*/
- public synchronized PropertyMap deleteProperty(final Property property) {
- if (listeners != null) {
- listeners.propertyDeleted(property);
- }
+ public final synchronized PropertyMap deleteProperty(final Property property) {
+ propertyDeleted(property, true);
PropertyMap newMap = checkHistory(property);
final String key = property.getKey();
@@ -476,13 +505,13 @@
// If deleted property was last field or spill slot we can make it reusable by reducing field/slot count.
// Otherwise mark it as free in free slots bitset.
if (isSpill && slot >= 0 && slot == spillLength - 1) {
- newMap = new PropertyMap(newProperties, className, fieldCount, fieldMaximum, spillLength - 1, containsArrayKeys());
+ newMap = deriveMap(newProperties, flags, fieldCount, spillLength - 1);
newMap.freeSlots = freeSlots;
} else if (!isSpill && slot >= 0 && slot == fieldCount - 1) {
- newMap = new PropertyMap(newProperties, className, fieldCount - 1, fieldMaximum, spillLength, containsArrayKeys());
+ newMap = deriveMap(newProperties, flags, fieldCount - 1, spillLength);
newMap.freeSlots = freeSlots;
} else {
- newMap = new PropertyMap(this, newProperties);
+ newMap = deriveMap(newProperties, flags, fieldCount, spillLength);
newMap.updateFreeSlots(property, null);
}
addToHistory(property, newMap);
@@ -499,13 +528,8 @@
*
* @return New {@link PropertyMap} with {@link Property} replaced.
*/
- public PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) {
- if (listeners != null) {
- listeners.propertyModified(oldProperty, newProperty);
- }
- // Add replaces existing property.
- final PropertyHashMap newProperties = properties.immutableReplace(oldProperty, newProperty);
- final PropertyMap newMap = new PropertyMap(this, newProperties);
+ public final PropertyMap replaceProperty(final Property oldProperty, final Property newProperty) {
+ propertyModified(oldProperty, newProperty, true);
/*
* See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods.
*
@@ -527,14 +551,17 @@
newProperty instanceof UserAccessorProperty :
"arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getLocalType() + " => " + newProperty.getLocalType() + "]";
- newMap.flags = flags;
-
/*
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
* to add spill count of the newly added UserAccessorProperty property.
*/
+ final int newSpillLength = sameType ? spillLength : Math.max(spillLength, newProperty.getSlot() + 1);
+
+ // Add replaces existing property.
+ final PropertyHashMap newProperties = properties.immutableReplace(oldProperty, newProperty);
+ final PropertyMap newMap = deriveMap(newProperties, flags, fieldCount, newSpillLength);
+
if (!sameType) {
- newMap.spillLength = Math.max(spillLength, newProperty.getSlot() + 1);
newMap.updateFreeSlots(oldProperty, newProperty);
}
return newMap;
@@ -550,7 +577,7 @@
* @param propertyFlags attribute flags of the property
* @return the newly created UserAccessorProperty
*/
- public UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
+ public final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
return new UserAccessorProperty(key, propertyFlags, getFreeSpillSlot());
}
@@ -561,7 +588,7 @@
*
* @return {@link Property} matching key.
*/
- public Property findProperty(final String key) {
+ public final Property findProperty(final String key) {
return properties.find(key);
}
@@ -572,12 +599,12 @@
*
* @return New {@link PropertyMap} with added properties.
*/
- public PropertyMap addAll(final PropertyMap other) {
+ public final PropertyMap addAll(final PropertyMap other) {
assert this != other : "adding property map to itself";
final Property[] otherProperties = other.properties.getProperties();
final PropertyHashMap newProperties = properties.immutableAdd(otherProperties);
- final PropertyMap newMap = new PropertyMap(this, newProperties);
+ final PropertyMap newMap = deriveMap(newProperties, flags, fieldCount, spillLength);
for (final Property property : otherProperties) {
// This method is only safe to use with non-slotted, native getter/setter properties
assert property.getSlot() == -1;
@@ -592,19 +619,26 @@
*
* @return Properties as an array.
*/
- public Property[] getProperties() {
+ public final Property[] getProperties() {
return properties.getProperties();
}
/**
+ * Return the name of the class of objects using this property map.
+ *
+ * @return class name of owner objects.
+ */
+ public final String getClassName() {
+ return className;
+ }
+
+ /**
* Prevents the map from having additional properties.
*
* @return New map with {@link #NOT_EXTENSIBLE} flag set.
*/
PropertyMap preventExtensions() {
- final PropertyMap newMap = new PropertyMap(this);
- newMap.flags |= NOT_EXTENSIBLE;
- return newMap;
+ return deriveMap(properties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
}
/**
@@ -620,10 +654,7 @@
newProperties = newProperties.immutableAdd(oldProperty.addFlags(Property.NOT_CONFIGURABLE));
}
- final PropertyMap newMap = new PropertyMap(this, newProperties);
- newMap.flags |= NOT_EXTENSIBLE;
-
- return newMap;
+ return deriveMap(newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
}
/**
@@ -645,10 +676,7 @@
newProperties = newProperties.immutableAdd(oldProperty.addFlags(propertyFlags));
}
- final PropertyMap newMap = new PropertyMap(this, newProperties);
- newMap.flags |= NOT_EXTENSIBLE;
-
- return newMap;
+ return deriveMap(newProperties, flags | NOT_EXTENSIBLE, fieldCount, spillLength);
}
/**
@@ -704,7 +732,7 @@
}
if (Context.DEBUG && cachedMap != null) {
- protoHistoryHit++;
+ protoHistoryHit.increment();
}
return cachedMap;
@@ -735,7 +763,7 @@
history = new WeakHashMap<>();
}
- history.put(property, new SoftReference<>(newMap));
+ history.put(property, softReferenceDerivationLimit == 0 ? new WeakReference<>(newMap) : new SoftReference<>(newMap));
}
/**
@@ -748,12 +776,12 @@
private PropertyMap checkHistory(final Property property) {
if (history != null) {
- final SoftReference<PropertyMap> ref = history.get(property);
+ final Reference<PropertyMap> ref = history.get(property);
final PropertyMap historicMap = ref == null ? null : ref.get();
if (historicMap != null) {
if (Context.DEBUG) {
- historyHit++;
+ historyHit.increment();
}
return historicMap;
@@ -820,13 +848,6 @@
}
/**
- * Flag this object as having array keys in defined properties
- */
- private void setContainsArrayKeys() {
- flags |= CONTAINS_ARRAY_KEYS;
- }
-
- /**
* Test to see if {@link PropertyMap} is extensible.
*
* @return {@code true} if {@link PropertyMap} can be added to.
@@ -901,15 +922,75 @@
}
if (Context.DEBUG) {
- setProtoNewMapCount++;
+ setProtoNewMapCount.increment();
}
- final PropertyMap newMap = new PropertyMap(this);
+ final PropertyMap newMap = makeUnsharedCopy();
addToProtoHistory(newProto, newMap);
return newMap;
}
+ /**
+ * Make a copy of this property map with the shared prototype field set to null. Note that this is
+ * only necessary for shared maps of top-level objects. Shared prototype maps represented by
+ * {@link SharedPropertyMap} are automatically converted to plain property maps when they evolve.
+ *
+ * @return a copy with the shared proto map unset
+ */
+ PropertyMap makeUnsharedCopy() {
+ final PropertyMap newMap = new PropertyMap(this);
+ newMap.sharedProtoMap = null;
+ return newMap;
+ }
+
+ /**
+ * Set a reference to the expected parent prototype map. This is used for class-like
+ * structures where we only want to use a top-level property map if all of the
+ * prototype property maps have not been modified.
+ *
+ * @param protoMap weak reference to the prototype property map
+ */
+ void setSharedProtoMap(final SharedPropertyMap protoMap) {
+ sharedProtoMap = protoMap;
+ }
+
+ /**
+ * Get the expected prototype property map if it is known, or null.
+ *
+ * @return parent map or null
+ */
+ public PropertyMap getSharedProtoMap() {
+ return sharedProtoMap;
+ }
+
+ /**
+ * Returns {@code true} if this map has been used as a shared prototype map (i.e. as a prototype
+ * for a JavaScript constructor function) and has not had properties added, deleted or replaced since then.
+ * @return true if this is a valid shared prototype map
+ */
+ boolean isValidSharedProtoMap() {
+ return false;
+ }
+
+ /**
+ * Returns the shared prototype switch point, or null if this is not a shared prototype map.
+ * @return the shared prototype switch point, or null
+ */
+ SwitchPoint getSharedProtoSwitchPoint() {
+ return null;
+ }
+
+ /**
+ * Return true if this map has a shared prototype map which has either been invalidated or does
+ * not match the map of {@code proto}.
+ * @param prototype the prototype object
+ * @return true if this is an invalid shared map for {@code prototype}
+ */
+ boolean isInvalidSharedMapFor(final ScriptObject prototype) {
+ return sharedProtoMap != null
+ && (!sharedProtoMap.isValidSharedProtoMap() || prototype == null || sharedProtoMap != prototype.getMap());
+ }
/**
* {@link PropertyMap} iterator.
@@ -990,10 +1071,10 @@
for (final Property p : map0.getProperties()) {
final Property p2 = map1.findProperty(p.getKey());
if (p2 == null) {
- sb.append("FIRST ONLY : [" + p + "]");
+ sb.append("FIRST ONLY : [").append(p).append("]");
found = true;
} else if (p2 != p) {
- sb.append("DIFFERENT : [" + p + "] != [" + p2 + "]");
+ sb.append("DIFFERENT : [").append(p).append("] != [").append(p2).append("]");
found = true;
}
}
@@ -1001,7 +1082,7 @@
for (final Property p2 : map1.getProperties()) {
final Property p1 = map0.findProperty(p2.getKey());
if (p1 == null) {
- sb.append("SECOND ONLY: [" + p2 + "]");
+ sb.append("SECOND ONLY: [").append(p2).append("]");
found = true;
}
}
@@ -1021,52 +1102,62 @@
}
// counters updated only in debug mode
- private static int count;
- private static int clonedCount;
- private static int historyHit;
- private static int protoInvalidations;
- private static int protoHistoryHit;
- private static int setProtoNewMapCount;
+ private static LongAdder count;
+ private static LongAdder clonedCount;
+ private static LongAdder historyHit;
+ private static LongAdder protoInvalidations;
+ private static LongAdder protoHistoryHit;
+ private static LongAdder setProtoNewMapCount;
+ static {
+ if (Context.DEBUG) {
+ count = new LongAdder();
+ clonedCount = new LongAdder();
+ historyHit = new LongAdder();
+ protoInvalidations = new LongAdder();
+ protoHistoryHit = new LongAdder();
+ setProtoNewMapCount = new LongAdder();
+ }
+ }
/**
* @return Total number of maps.
*/
- public static int getCount() {
- return count;
+ public static long getCount() {
+ return count.longValue();
}
/**
* @return The number of maps that were cloned.
*/
- public static int getClonedCount() {
- return clonedCount;
+ public static long getClonedCount() {
+ return clonedCount.longValue();
}
/**
* @return The number of times history was successfully used.
*/
- public static int getHistoryHit() {
- return historyHit;
+ public static long getHistoryHit() {
+ return historyHit.longValue();
}
/**
* @return The number of times prototype changes caused invalidation.
*/
- public static int getProtoInvalidations() {
- return protoInvalidations;
+ public static long getProtoInvalidations() {
+ return protoInvalidations.longValue();
}
/**
* @return The number of times proto history was successfully used.
*/
- public static int getProtoHistoryHit() {
- return protoHistoryHit;
+ public static long getProtoHistoryHit() {
+ return protoHistoryHit.longValue();
}
/**
* @return The number of times prototypes were modified.
*/
- public static int getSetProtoNewMapCount() {
- return setProtoNewMapCount;
+ public static long getSetProtoNewMapCount() {
+ return setProtoNewMapCount.longValue();
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java b/nashorn/src/jdk/nashorn/internal/runtime/PrototypeObject.java
similarity index 87%
rename from nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java
rename to nashorn/src/jdk/nashorn/internal/runtime/PrototypeObject.java
index b119dad..f4c1b5f 100644
--- a/nashorn/src/jdk/nashorn/internal/objects/PrototypeObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PrototypeObject.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.internal.objects;
+package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -31,17 +31,12 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
-import jdk.nashorn.internal.runtime.AccessorProperty;
-import jdk.nashorn.internal.runtime.Property;
-import jdk.nashorn.internal.runtime.PropertyMap;
-import jdk.nashorn.internal.runtime.ScriptFunction;
-import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.objects.Global;
/**
* Instances of this class serve as "prototype" object for script functions.
* The purpose is to expose "constructor" property from "prototype". Also, nasgen
* generated prototype classes extend from this class.
- *
*/
public class PrototypeObject extends ScriptObject {
private static final PropertyMap map$;
@@ -61,7 +56,10 @@
super(global.getObjectPrototype(), map != map$? map.addAll(map$) : map$);
}
- PrototypeObject() {
+ /**
+ * Prototype constructor
+ */
+ protected PrototypeObject() {
this(Global.instance(), map$);
}
@@ -70,11 +68,16 @@
*
* @param map property map
*/
- PrototypeObject(final PropertyMap map) {
+ protected PrototypeObject(final PropertyMap map) {
this(Global.instance(), map);
}
- PrototypeObject(final ScriptFunction func) {
+ /**
+ * PropertyObject constructor
+ *
+ * @param func constructor function
+ */
+ protected PrototypeObject(final ScriptFunction func) {
this(Global.instance(), map$);
this.constructor = func;
}
@@ -84,7 +87,7 @@
* @param self self reference
* @return constructor, probably, but not necessarily, a {@link ScriptFunction}
*/
- static Object getConstructor(final Object self) {
+ public static Object getConstructor(final Object self) {
return (self instanceof PrototypeObject) ?
((PrototypeObject)self).getConstructor() :
UNDEFINED;
@@ -95,7 +98,7 @@
* @param self self reference
* @param constructor constructor, probably, but not necessarily, a {@link ScriptFunction}
*/
- static void setConstructor(final Object self, final Object constructor) {
+ public static void setConstructor(final Object self, final Object constructor) {
if (self instanceof PrototypeObject) {
((PrototypeObject)self).setConstructor(constructor);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index b06b9b9..5c85787 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -26,16 +26,25 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -45,9 +54,16 @@
import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
import jdk.nashorn.internal.codegen.TypeMap;
import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.LexicalContext;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.SwitchNode;
+import jdk.nashorn.internal.ir.Symbol;
+import jdk.nashorn.internal.ir.TryNode;
+import jdk.nashorn.internal.ir.visitor.SimpleNodeVisitor;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.parser.Parser;
import jdk.nashorn.internal.parser.Token;
@@ -55,6 +71,7 @@
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
import jdk.nashorn.internal.runtime.logging.Logger;
+import jdk.nashorn.internal.runtime.options.Options;
/**
* This is a subclass that represents a script function that may be regenerated,
* for example with specialization based on call site types, or lazily generated.
@@ -66,6 +83,8 @@
/** Prefix used for all recompiled script classes */
public static final String RECOMPILATION_PREFIX = "Recompilation$";
+ private static final ExecutorService astSerializerExecutorService = createAstSerializerExecutorService();
+
/** Unique function node id for this function node */
private final int functionNodeId;
@@ -77,8 +96,12 @@
/** Source from which FunctionNode was parsed. */
private transient Source source;
- /** Serialized, compressed form of the AST. Used by split functions as they can't be reparsed from source. */
- private final byte[] serializedAst;
+ /**
+ * Cached form of the AST. Either a {@code SerializedAst} object used by split functions as they can't be
+ * reparsed from source, or a soft reference to a {@code FunctionNode} for other functions (it is safe
+ * to be cleared as they can be reparsed).
+ */
+ private volatile Object cachedAst;
/** Token of this function within the source. */
private final long token;
@@ -97,7 +120,7 @@
private final Object endParserState;
/** Code installer used for all further recompilation/specialization of this ScriptFunction */
- private transient CodeInstaller<ScriptEnvironment> installer;
+ private transient CodeInstaller installer;
private final Map<Integer, RecompilableScriptFunctionData> nestedFunctions;
@@ -128,16 +151,14 @@
* @param nestedFunctions nested function map
* @param externalScopeDepths external scope depths
* @param internalSymbols internal symbols to method, defined in its scope
- * @param serializedAst a serialized AST representation. Normally only used for split functions.
*/
public RecompilableScriptFunctionData(
final FunctionNode functionNode,
- final CodeInstaller<ScriptEnvironment> installer,
+ final CodeInstaller installer,
final AllocationStrategy allocationStrategy,
final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
final Map<String, Integer> externalScopeDepths,
- final Set<String> internalSymbols,
- final byte[] serializedAst) {
+ final Set<String> internalSymbols) {
super(functionName(functionNode),
Math.min(functionNode.getParameters().size(), MAX_ARITY),
@@ -161,7 +182,6 @@
nfn.setParent(this);
}
- this.serializedAst = serializedAst;
createLogger();
}
@@ -244,7 +264,7 @@
* @return parent data, or null if non exists and also null IF UNKNOWN.
*/
public RecompilableScriptFunctionData getParent() {
- return parent;
+ return parent;
}
void setParent(final RecompilableScriptFunctionData parent) {
@@ -266,7 +286,7 @@
* @param src source
* @param inst code installer
*/
- public void initTransients(final Source src, final CodeInstaller<ScriptEnvironment> inst) {
+ public void initTransients(final Source src, final CodeInstaller inst) {
if (this.source == null && this.installer == null) {
this.source = src;
this.installer = inst;
@@ -349,8 +369,8 @@
}
@Override
- PropertyMap getAllocatorMap() {
- return allocationStrategy.getAllocatorMap();
+ PropertyMap getAllocatorMap(final ScriptObject prototype) {
+ return allocationStrategy.getAllocatorMap(prototype);
}
@Override
@@ -358,13 +378,11 @@
return allocationStrategy.allocate(map);
}
- boolean isSerialized() {
- return serializedAst != null;
- }
-
FunctionNode reparse() {
- if (isSerialized()) {
- return deserialize();
+ final FunctionNode cachedFunction = getCachedAst();
+ if (cachedFunction != null) {
+ assert cachedFunction.isCached();
+ return cachedFunction;
}
final int descPosition = Token.descPosition(token);
@@ -391,8 +409,105 @@
return (isProgram() ? program : extractFunctionFromScript(program)).setName(null, functionName);
}
- private FunctionNode deserialize() {
- final ScriptEnvironment env = installer.getOwner();
+ private FunctionNode getCachedAst() {
+ final Object lCachedAst = cachedAst;
+ // Are we softly caching the AST?
+ if (lCachedAst instanceof Reference<?>) {
+ final FunctionNode fn = (FunctionNode)((Reference<?>)lCachedAst).get();
+ if (fn != null) {
+ // Yes we are - this is fast
+ return cloneSymbols(fn);
+ }
+ // Are we strongly caching a serialized AST (for split functions only)?
+ } else if (lCachedAst instanceof SerializedAst) {
+ final SerializedAst serializedAst = (SerializedAst)lCachedAst;
+ // Even so, are we also softly caching the AST?
+ final FunctionNode cachedFn = serializedAst.cachedAst.get();
+ if (cachedFn != null) {
+ // Yes we are - this is fast
+ return cloneSymbols(cachedFn);
+ }
+ final FunctionNode deserializedFn = deserialize(serializedAst.serializedAst);
+ // Softly cache after deserialization, maybe next time we won't need to deserialize
+ serializedAst.cachedAst = new SoftReference<>(deserializedFn);
+ return deserializedFn;
+ }
+ // No cached representation; return null for reparsing
+ return null;
+ }
+
+ /**
+ * Sets the AST to cache in this function
+ * @param astToCache the new AST to cache
+ */
+ public void setCachedAst(final FunctionNode astToCache) {
+ assert astToCache.getId() == functionNodeId; // same function
+ assert !(cachedAst instanceof SerializedAst); // Can't overwrite serialized AST
+
+ final boolean isSplit = astToCache.isSplit();
+ // If we're caching a split function, we're doing it in the eager pass, hence there can be no other
+ // cached representation already. In other words, isSplit implies cachedAst == null.
+ assert !isSplit || cachedAst == null; //
+
+ final FunctionNode symbolClonedAst = cloneSymbols(astToCache);
+ final Reference<FunctionNode> ref = new SoftReference<>(symbolClonedAst);
+ cachedAst = ref;
+
+ // Asynchronously serialize split functions.
+ if (isSplit) {
+ astSerializerExecutorService.execute(new Runnable() {
+ @Override
+ public void run() {
+ cachedAst = new SerializedAst(symbolClonedAst, ref);
+ }
+ });
+ }
+ }
+
+ /**
+ * Creates the AST serializer executor service used for in-memory serialization of split functions' ASTs.
+ * It is created with an unbounded queue (so it can queue any number of pending tasks). Its core and max
+ * threads is the same, but they are all allowed to time out so when there's no work, they can all go
+ * away. The threads will be daemons, and they will time out if idle for a minute. Their priority is also
+ * slightly lower than normal priority as we'd prefer the CPU to keep running the program; serializing
+ * split function is a memory conservation measure (it allows us to release the AST), it can wait a bit.
+ * @return an executor service with above described characteristics.
+ */
+ private static ExecutorService createAstSerializerExecutorService() {
+ final int threads = Math.max(1, Options.getIntProperty("nashorn.serialize.threads", Runtime.getRuntime().availableProcessors() / 2));
+ final ThreadPoolExecutor service = new ThreadPoolExecutor(threads, threads, 1L, TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>(),
+ new ThreadFactory() {
+ @Override
+ public Thread newThread(final Runnable r) {
+ final Thread t = new Thread(r, "Nashorn AST Serializer");
+ t.setDaemon(true);
+ t.setPriority(Thread.NORM_PRIORITY - 1);
+ return t;
+ }
+ });
+ service.allowCoreThreadTimeOut(true);
+ return service;
+ }
+
+ /**
+ * A tuple of a serialized AST and a soft reference to a deserialized AST. This is used to cache split
+ * functions. Since split functions are altered from their source form, they can't be reparsed from
+ * source. While we could just use the {@code byte[]} representation in {@link RecompilableScriptFunctionData#cachedAst}
+ * we're using this tuple instead to also keep a deserialized AST around in memory to cut down on
+ * deserialization costs.
+ */
+ private static class SerializedAst {
+ private final byte[] serializedAst;
+ private volatile Reference<FunctionNode> cachedAst;
+
+ SerializedAst(final FunctionNode fn, final Reference<FunctionNode> cachedAst) {
+ this.serializedAst = AstSerializer.serialize(fn);
+ this.cachedAst = cachedAst;
+ }
+ }
+
+ private FunctionNode deserialize(final byte[] serializedAst) {
+ final ScriptEnvironment env = installer.getContext().getEnv();
final Timing timing = env._timing;
final long t1 = System.nanoTime();
try {
@@ -402,6 +517,107 @@
}
}
+ private FunctionNode cloneSymbols(final FunctionNode fn) {
+ final IdentityHashMap<Symbol, Symbol> symbolReplacements = new IdentityHashMap<>();
+ final boolean cached = fn.isCached();
+ // blockDefinedSymbols is used to re-mark symbols defined outside the function as global. We only
+ // need to do this when we cache an eagerly parsed function (which currently means a split one, as we
+ // don't cache non-split functions from the eager pass); those already cached, or those not split
+ // don't need this step.
+ final Set<Symbol> blockDefinedSymbols = fn.isSplit() && !cached ? Collections.newSetFromMap(new IdentityHashMap<Symbol, Boolean>()) : null;
+ FunctionNode newFn = (FunctionNode)fn.accept(new SimpleNodeVisitor() {
+
+ private Symbol getReplacement(final Symbol original) {
+ if (original == null) {
+ return null;
+ }
+ final Symbol existingReplacement = symbolReplacements.get(original);
+ if (existingReplacement != null) {
+ return existingReplacement;
+ }
+ final Symbol newReplacement = original.clone();
+ symbolReplacements.put(original, newReplacement);
+ return newReplacement;
+ }
+
+ @Override
+ public Node leaveIdentNode(final IdentNode identNode) {
+ final Symbol oldSymbol = identNode.getSymbol();
+ if (oldSymbol != null) {
+ final Symbol replacement = getReplacement(oldSymbol);
+ return identNode.setSymbol(replacement);
+ }
+ return identNode;
+ }
+
+ @Override
+ public Node leaveForNode(final ForNode forNode) {
+ return ensureUniqueLabels(forNode.setIterator(lc, getReplacement(forNode.getIterator())));
+ }
+
+ @Override
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
+ return ensureUniqueLabels(switchNode.setTag(lc, getReplacement(switchNode.getTag())));
+ }
+
+ @Override
+ public Node leaveTryNode(final TryNode tryNode) {
+ return ensureUniqueLabels(tryNode.setException(lc, getReplacement(tryNode.getException())));
+ }
+
+ @Override
+ public boolean enterBlock(final Block block) {
+ for(final Symbol symbol: block.getSymbols()) {
+ final Symbol replacement = getReplacement(symbol);
+ if (blockDefinedSymbols != null) {
+ blockDefinedSymbols.add(replacement);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Node leaveBlock(final Block block) {
+ return ensureUniqueLabels(block.replaceSymbols(lc, symbolReplacements));
+ }
+
+ @Override
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
+ return functionNode.setParameters(lc, functionNode.visitParameters(this));
+ }
+
+ @Override
+ protected Node leaveDefault(final Node node) {
+ return ensureUniqueLabels(node);
+ };
+
+ private Node ensureUniqueLabels(final Node node) {
+ // If we're returning a cached AST, we must also ensure unique labels
+ return cached ? node.ensureUniqueLabels(lc) : node;
+ }
+ });
+
+ if (blockDefinedSymbols != null) {
+ // Mark all symbols not defined in blocks as globals
+ Block newBody = null;
+ for(final Symbol symbol: symbolReplacements.values()) {
+ if(!blockDefinedSymbols.contains(symbol)) {
+ assert symbol.isScope(); // must be scope
+ assert externalScopeDepths.containsKey(symbol.getName()); // must be known to us as an external
+ // Register it in the function body symbol table as a new global symbol
+ symbol.setFlags((symbol.getFlags() & ~Symbol.KINDMASK) | Symbol.IS_GLOBAL);
+ if (newBody == null) {
+ newBody = newFn.getBody().copyWithNewSymbols();
+ newFn = newFn.setBody(null, newBody);
+ }
+ assert newBody.getExistingSymbol(symbol.getName()) == null; // must not be defined in the body already
+ newBody.putSymbol(symbol);
+ }
+ }
+ }
+ return newFn.setCached(null);
+ }
+
private boolean getFunctionFlag(final int flag) {
return (functionFlags & flag) != 0;
}
@@ -438,8 +654,8 @@
* a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC.
* @return a code installer for installing new code.
*/
- private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() {
- final ScriptEnvironment env = installer.getOwner();
+ private CodeInstaller getInstallerForNewCode() {
+ final ScriptEnvironment env = installer.getContext().getEnv();
return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
}
@@ -449,15 +665,10 @@
final TypeMap typeMap = typeMap(actualCallSiteType);
final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
final Object typeInformationFile = OptimisticTypesPersistence.getLocationDescriptor(source, functionNodeId, paramTypes);
- final Context context = Context.getContextTrusted();
- return new Compiler(
- context,
- context.getEnv(),
+ return Compiler.forOnDemandCompilation(
getInstallerForNewCode(),
functionNode.getSource(), // source
- context.getErrorManager(),
isStrict() | functionNode.isStrict(), // is strict
- true, // is on demand
this, // compiledFunction, i.e. this RecompilableScriptFunctionData
typeMap, // type map
getEffectiveInvalidatedProgramPoints(invalidatedProgramPoints, typeInformationFile), // invalidated program points
@@ -500,7 +711,7 @@
final TypeMap typeMap = typeMap(actualCallSiteType);
final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
- final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
+ final CodeInstaller newInstaller = getInstallerForNewCode();
final StoredScript script = newInstaller.loadScript(source, cacheKey);
if (script != null) {
@@ -512,16 +723,16 @@
final FunctionNode fn = reparse();
final Compiler compiler = getCompiler(fn, actualCallSiteType, runtimeScope);
final FunctionNode compiledFn = compiler.compile(fn,
- isSerialized() ? CompilationPhases.COMPILE_ALL_SERIALIZED : CompilationPhases.COMPILE_ALL);
+ fn.isCached() ? CompilationPhases.COMPILE_ALL_CACHED : CompilationPhases.COMPILE_ALL);
- if (persist && !compiledFn.getFlag(FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION)) {
+ if (persist && !compiledFn.hasApplyToCallSpecialization()) {
compiler.persistClassInfo(cacheKey, compiledFn);
}
return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
}
boolean usePersistentCodeCache() {
- return installer != null && installer.getOwner()._persistent_cache;
+ return installer != null && installer.getContext().getEnv()._persistent_cache;
}
private MethodType explicitParams(final MethodType callSiteType) {
@@ -553,7 +764,7 @@
private FunctionNode extractFunctionFromScript(final FunctionNode script) {
final Set<FunctionNode> fns = new HashSet<>();
- script.getBody().accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+ script.getBody().accept(new SimpleNodeVisitor() {
@Override
public boolean enterFunctionNode(final FunctionNode fn) {
fns.add(fn);
@@ -617,6 +828,7 @@
private CompiledFunction addCode(final MethodHandle target, final Map<Integer, Type> invalidatedProgramPoints,
final MethodType callSiteType, final int fnFlags) {
final CompiledFunction cfn = new CompiledFunction(target, this, invalidatedProgramPoints, callSiteType, fnFlags);
+ assert noDuplicateCode(cfn) : "duplicate code";
code.add(cfn);
return cfn;
}
@@ -683,14 +895,17 @@
@Override
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
- CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
+ assert isValidCallSite(callSiteType) : callSiteType;
+
+ CompiledFunction existingBest = pickFunction(callSiteType, false);
+ if (existingBest == null) {
+ existingBest = pickFunction(callSiteType, true); // try vararg last
+ }
if (existingBest == null) {
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
}
assert existingBest != null;
- //we are calling a vararg method with real args
- boolean varArgWithRealArgs = existingBest.isVarArg() && !CompiledFunction.isVarArgsType(callSiteType);
//if the best one is an apply to call, it has to match the callsite exactly
//or we need to regenerate
@@ -699,27 +914,18 @@
if (best != null) {
return best;
}
- varArgWithRealArgs = true;
- }
- if (varArgWithRealArgs) {
// special case: we had an apply to call, but we failed to make it fit.
// Try to generate a specialized one for this callsite. It may
// be another apply to call specialization, or it may not, but whatever
// it is, it is a specialization that is guaranteed to fit
- final FunctionInitializer fnInit = compileTypeSpecialization(callSiteType, runtimeScope, false);
- existingBest = addCode(fnInit, callSiteType);
+ existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, false), callSiteType);
}
return existingBest;
}
@Override
- boolean isRecompilable() {
- return true;
- }
-
- @Override
public boolean needsCallee() {
return getFunctionFlag(FunctionNode.NEEDS_CALLEE);
}
@@ -827,6 +1033,16 @@
return newFn;
}
+ // Make sure code does not contain a compiled function with the same signature as compiledFunction
+ private boolean noDuplicateCode(final CompiledFunction compiledFunction) {
+ for (final CompiledFunction cf : code) {
+ if (cf.type().equals(compiledFunction.type())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private void readObject(final java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
createLogger();
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Scope.java b/nashorn/src/jdk/nashorn/internal/runtime/Scope.java
index 07717be..9650f9c 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Scope.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Scope.java
@@ -27,6 +27,7 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
+import java.util.concurrent.atomic.LongAdder;
import jdk.nashorn.internal.codegen.CompilerConstants;
/**
@@ -38,7 +39,7 @@
private int splitState = -1;
/** This is updated only in debug mode - counts number of {@code ScriptObject} instances created that are scope */
- private static int count;
+ private static final LongAdder count = Context.DEBUG ? new LongAdder() : null;
/** Method handle that points to {@link Scope#getSplitState}. */
public static final CompilerConstants.Call GET_SPLIT_STATE = virtualCallNoLookup(Scope.class, "getSplitState", int.class);
@@ -52,9 +53,7 @@
*/
public Scope(final PropertyMap map) {
super(map);
- if (Context.DEBUG) {
- count++;
- }
+ incrementCount();
}
/**
@@ -65,9 +64,7 @@
*/
public Scope(final ScriptObject proto, final PropertyMap map) {
super(proto, map);
- if (Context.DEBUG) {
- count++;
- }
+ incrementCount();
}
/**
@@ -79,9 +76,7 @@
*/
public Scope(final PropertyMap map, final long[] primitiveSpill, final Object[] objectSpill) {
super(map, primitiveSpill, objectSpill);
- if (Context.DEBUG) {
- count++;
- }
+ incrementCount();
}
@Override
@@ -123,7 +118,13 @@
*
* @return number of scope ScriptObjects created
*/
- public static int getScopeCount() {
- return count;
+ public static long getScopeCount() {
+ return count != null ? count.sum() : 0;
+ }
+
+ private static void incrementCount() {
+ if (Context.DEBUG) {
+ count.increment();
+ }
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
index 99cef12..b426480 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@@ -46,6 +46,11 @@
* and output and error writers, top level Namespace etc.
*/
public final class ScriptEnvironment {
+ // Primarily intended to be used in test environments so that eager compilation tests work without an
+ // error when tested with optimistic compilation.
+ private static final boolean ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE = Options.getBooleanProperty(
+ "nashorn.options.allowEagerCompilationSilentOverride", false);
+
/** Output writer for this environment */
private final PrintWriter out;
@@ -237,8 +242,20 @@
}
_fx = options.getBoolean("fx");
_global_per_engine = options.getBoolean("global.per.engine");
- _lazy_compilation = options.getBoolean("lazy.compilation");
_optimistic_types = options.getBoolean("optimistic.types");
+ final boolean lazy_compilation = options.getBoolean("lazy.compilation");
+ if (!lazy_compilation && _optimistic_types) {
+ if (!ALLOW_EAGER_COMPILATION_SILENT_OVERRIDE) {
+ throw new IllegalStateException(
+ ECMAErrors.getMessage(
+ "config.error.eagerCompilationConflictsWithOptimisticTypes",
+ options.getOptionTemplateByKey("lazy.compilation").getName(),
+ options.getOptionTemplateByKey("optimistic.types").getName()));
+ }
+ _lazy_compilation = true;
+ } else {
+ _lazy_compilation = lazy_compilation;
+ }
_loader_per_compile = options.getBoolean("loader.per.compile");
_no_java = options.getBoolean("no.java");
_no_syntax_extensions = options.getBoolean("no.syntax.extensions");
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index c3e6a4a..edd8aeb 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -22,7 +22,6 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
@@ -40,6 +39,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
+import java.util.concurrent.atomic.LongAdder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -55,38 +55,54 @@
import jdk.nashorn.internal.runtime.logging.DebugLogger;
/**
- * Runtime representation of a JavaScript function.
+ * Runtime representation of a JavaScript function. This class has only private
+ * and protected constructors. There are no *public* constructors - but only
+ * factory methods that follow the naming pattern "createXYZ".
*/
-public abstract class ScriptFunction extends ScriptObject {
+public class ScriptFunction extends ScriptObject {
- /** Method handle for prototype getter for this ScriptFunction */
+ /**
+ * Method handle for prototype getter for this ScriptFunction
+ */
public static final MethodHandle G$PROTOTYPE = findOwnMH_S("G$prototype", Object.class, Object.class);
- /** Method handle for prototype setter for this ScriptFunction */
+ /**
+ * Method handle for prototype setter for this ScriptFunction
+ */
public static final MethodHandle S$PROTOTYPE = findOwnMH_S("S$prototype", void.class, Object.class, Object.class);
- /** Method handle for length getter for this ScriptFunction */
+ /**
+ * Method handle for length getter for this ScriptFunction
+ */
public static final MethodHandle G$LENGTH = findOwnMH_S("G$length", int.class, Object.class);
- /** Method handle for name getter for this ScriptFunction */
+ /**
+ * Method handle for name getter for this ScriptFunction
+ */
public static final MethodHandle G$NAME = findOwnMH_S("G$name", Object.class, Object.class);
- /** Method handle used for implementing sync() in mozilla_compat */
+ /**
+ * Method handle used for implementing sync() in mozilla_compat
+ */
public static final MethodHandle INVOKE_SYNC = findOwnMH_S("invokeSync", Object.class, ScriptFunction.class, Object.class, Object.class, Object[].class);
- /** Method handle for allocate function for this ScriptFunction */
+ /**
+ * Method handle for allocate function for this ScriptFunction
+ */
static final MethodHandle ALLOCATE = findOwnMH_V("allocate", Object.class);
private static final MethodHandle WRAPFILTER = findOwnMH_S("wrapFilter", Object.class, Object.class);
private static final MethodHandle SCRIPTFUNCTION_GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
- /** method handle to scope getter for this ScriptFunction */
+ /**
+ * method handle to scope getter for this ScriptFunction
+ */
public static final Call GET_SCOPE = virtualCallNoLookup(ScriptFunction.class, "getScope", ScriptObject.class);
- private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
+ private static final MethodHandle IS_FUNCTION_MH = findOwnMH_S("isFunctionMH", boolean.class, Object.class, ScriptFunctionData.class);
- private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
+ private static final MethodHandle IS_APPLY_FUNCTION = findOwnMH_S("isApplyFunction", boolean.class, boolean.class, Object.class, Object.class);
private static final MethodHandle IS_NONSTRICT_FUNCTION = findOwnMH_S("isNonStrictFunction", boolean.class, Object.class, Object.class, ScriptFunctionData.class);
@@ -94,55 +110,298 @@
private static final MethodHandle WRAP_THIS = MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, "wrapThis", MH.type(Object.class, Object.class));
- /** The parent scope. */
+ // various property maps used for different kinds of functions
+ // property map for anonymous function that serves as Function.prototype
+ private static final PropertyMap anonmap$;
+ // property map for strict mode functions
+ private static final PropertyMap strictmodemap$;
+ // property map for bound functions
+ private static final PropertyMap boundfunctionmap$;
+ // property map for non-strict, non-bound functions.
+ private static final PropertyMap map$;
+
+ // Marker object for lazily initialized prototype object
+ private static final Object LAZY_PROTOTYPE = new Object();
+
+ private static PropertyMap createStrictModeMap(final PropertyMap map) {
+ final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
+ PropertyMap newMap = map;
+ // Need to add properties directly to map since slots are assigned speculatively by newUserAccessors.
+ newMap = newMap.addPropertyNoHistory(map.newUserAccessors("arguments", flags));
+ newMap = newMap.addPropertyNoHistory(map.newUserAccessors("caller", flags));
+ return newMap;
+ }
+
+ private static PropertyMap createBoundFunctionMap(final PropertyMap strictModeMap) {
+ // Bound function map is same as strict function map, but additionally lacks the "prototype" property, see
+ // ECMAScript 5.1 section 15.3.4.5
+ return strictModeMap.deleteProperty(strictModeMap.findProperty("prototype"));
+ }
+
+ static {
+ anonmap$ = PropertyMap.newMap();
+ final ArrayList<Property> properties = new ArrayList<>(3);
+ properties.add(AccessorProperty.create("prototype", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE, G$PROTOTYPE, S$PROTOTYPE));
+ properties.add(AccessorProperty.create("length", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$LENGTH, null));
+ properties.add(AccessorProperty.create("name", Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE | Property.NOT_WRITABLE, G$NAME, null));
+ map$ = PropertyMap.newMap(properties);
+ strictmodemap$ = createStrictModeMap(map$);
+ boundfunctionmap$ = createBoundFunctionMap(strictmodemap$);
+ }
+
+ private static boolean isStrict(final int flags) {
+ return (flags & ScriptFunctionData.IS_STRICT) != 0;
+ }
+
+ // Choose the map based on strict mode!
+ private static PropertyMap getMap(final boolean strict) {
+ return strict ? strictmodemap$ : map$;
+ }
+
+ /**
+ * The parent scope.
+ */
private final ScriptObject scope;
private final ScriptFunctionData data;
- /** The property map used for newly allocated object when function is used as constructor. */
+ /**
+ * The property map used for newly allocated object when function is used as
+ * constructor.
+ */
protected PropertyMap allocatorMap;
/**
+ * Reference to constructor prototype.
+ */
+ protected Object prototype;
+
+ /**
* Constructor
*
- * @param name function name
- * @param methodHandle method handle to function (if specializations are present, assumed to be most generic)
- * @param map property map
- * @param scope scope
- * @param specs specialized version of this function - other method handles
- * @param flags {@link ScriptFunctionData} flags
+ * @param data static function data
+ * @param map property map
+ * @param scope scope
*/
- protected ScriptFunction(
- final String name,
- final MethodHandle methodHandle,
+ private ScriptFunction(
+ final ScriptFunctionData data,
final PropertyMap map,
final ScriptObject scope,
- final Specialization[] specs,
- final int flags) {
+ final Global global) {
- this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
+ super(map);
+
+ if (Context.DEBUG) {
+ constructorCount.increment();
+ }
+
+ this.data = data;
+ this.scope = scope;
+ this.setInitialProto(global.getFunctionPrototype());
+ this.prototype = LAZY_PROTOTYPE;
+
+ // We have to fill user accessor functions late as these are stored
+ // in this object rather than in the PropertyMap of this object.
+ assert objectSpill == null;
+ if (isStrict() || isBoundFunction()) {
+ final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
+ initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
+ initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
+ }
}
/**
* Constructor
*
- * @param data static function data
- * @param map property map
- * @param scope scope
+ * @param name function name
+ * @param methodHandle method handle to function (if specializations are
+ * present, assumed to be most generic)
+ * @param map property map
+ * @param scope scope
+ * @param specs specialized version of this function - other method handles
+ * @param flags {@link ScriptFunctionData} flags
*/
- protected ScriptFunction(
- final ScriptFunctionData data,
+ private ScriptFunction(
+ final String name,
+ final MethodHandle methodHandle,
final PropertyMap map,
- final ScriptObject scope) {
+ final ScriptObject scope,
+ final Specialization[] specs,
+ final int flags,
+ final Global global) {
+ this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope, global);
+ }
- super(map);
+ /**
+ * Constructor
+ *
+ * @param name name of function
+ * @param methodHandle handle for invocation
+ * @param scope scope object
+ * @param specs specialized versions of this method, if available, null
+ * otherwise
+ * @param flags {@link ScriptFunctionData} flags
+ */
+ private ScriptFunction(
+ final String name,
+ final MethodHandle methodHandle,
+ final ScriptObject scope,
+ final Specialization[] specs,
+ final int flags) {
+ this(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags, Global.instance());
+ }
- if (Context.DEBUG) {
- constructorCount++;
+ /**
+ * Constructor called by Nasgen generated code, zero added members, use the
+ * default map. Creates builtin functions only.
+ *
+ * @param name name of function
+ * @param invokeHandle handle for invocation
+ * @param specs specialized versions of this method, if available, null
+ * otherwise
+ */
+ protected ScriptFunction(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
+ this(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
+ }
+
+ /**
+ * Constructor called by Nasgen generated code, non zero member count, use
+ * the map passed as argument. Creates builtin functions only.
+ *
+ * @param name name of function
+ * @param invokeHandle handle for invocation
+ * @param map initial property map
+ * @param specs specialized versions of this method, if available, null
+ * otherwise
+ */
+ protected ScriptFunction(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
+ this(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR, Global.instance());
+ }
+
+ // Factory methods to create various functions
+ /**
+ * Factory method called by compiler generated code for functions that need
+ * parent scope.
+ *
+ * @param constants the generated class' constant array
+ * @param index the index of the {@code RecompilableScriptFunctionData}
+ * object in the constants array.
+ * @param scope the parent scope object
+ * @return a newly created function object
+ */
+ public static ScriptFunction create(final Object[] constants, final int index, final ScriptObject scope) {
+ final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constants[index];
+ return new ScriptFunction(data, getMap(data.isStrict()), scope, Global.instance());
+ }
+
+ /**
+ * Factory method called by compiler generated code for functions that don't
+ * need parent scope.
+ *
+ * @param constants the generated class' constant array
+ * @param index the index of the {@code RecompilableScriptFunctionData}
+ * object in the constants array.
+ * @return a newly created function object
+ */
+ public static ScriptFunction create(final Object[] constants, final int index) {
+ return create(constants, index, null);
+ }
+
+ /**
+ * Create anonymous function that serves as Function.prototype
+ *
+ * @return anonymous function object
+ */
+ public static ScriptFunction createAnonymous() {
+ return new ScriptFunction("", GlobalFunctions.ANONYMOUS, anonmap$, null);
+ }
+
+ // builtin function create helper factory
+ private static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
+ final ScriptFunction func = new ScriptFunction(name, methodHandle, null, specs, flags);
+ func.setPrototype(UNDEFINED);
+ // Non-constructor built-in functions do not have "prototype" property
+ func.deleteOwnProperty(func.getMap().findProperty("prototype"));
+
+ return func;
+ }
+
+ /**
+ * Factory method for non-constructor built-in functions
+ *
+ * @param name function name
+ * @param methodHandle handle for invocation
+ * @param specs specialized versions of function if available, null
+ * otherwise
+ * @return new ScriptFunction
+ */
+ public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
+ return ScriptFunction.createBuiltin(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
+ }
+
+ /**
+ * Factory method for non-constructor built-in functions
+ *
+ * @param name function name
+ * @param methodHandle handle for invocation
+ * @return new ScriptFunction
+ */
+ public static ScriptFunction createBuiltin(final String name, final MethodHandle methodHandle) {
+ return ScriptFunction.createBuiltin(name, methodHandle, null);
+ }
+
+ /**
+ * Factory method for non-constructor built-in, strict functions
+ *
+ * @param name function name
+ * @param methodHandle handle for invocation
+ * @return new ScriptFunction
+ */
+ public static ScriptFunction createStrictBuiltin(final String name, final MethodHandle methodHandle) {
+ return ScriptFunction.createBuiltin(name, methodHandle, null, ScriptFunctionData.IS_BUILTIN | ScriptFunctionData.IS_STRICT);
+ }
+
+ // Subclass to represent bound functions
+ private static class Bound extends ScriptFunction {
+ private final ScriptFunction target;
+
+ Bound(final ScriptFunctionData boundData, final ScriptFunction target) {
+ super(boundData, boundfunctionmap$, null, Global.instance());
+ setPrototype(ScriptRuntime.UNDEFINED);
+ this.target = target;
}
- this.data = data;
- this.scope = scope;
+ @Override
+ protected ScriptFunction getTargetFunction() {
+ return target;
+ }
+ }
+
+ /**
+ * Creates a version of this function bound to a specific "self" and other
+ * arguments, as per {@code Function.prototype.bind} functionality in
+ * ECMAScript 5.1 section 15.3.4.5.
+ *
+ * @param self the self to bind to this function. Can be null (in which
+ * case, null is bound as this).
+ * @param args additional arguments to bind to this function. Can be null or
+ * empty to not bind additional arguments.
+ * @return a function with the specified self and parameters bound.
+ */
+ public final ScriptFunction createBound(final Object self, final Object[] args) {
+ return new Bound(data.makeBoundFunctionData(this, self, args), getTargetFunction());
+ }
+
+ /**
+ * Create a function that invokes this function synchronized on {@code sync}
+ * or the self object of the invocation.
+ *
+ * @param sync the Object to synchronize on, or undefined
+ * @return synchronized function
+ */
+ public final ScriptFunction createSynchronized(final Object sync) {
+ final MethodHandle mh = MH.insertArguments(ScriptFunction.INVOKE_SYNC, 0, this, sync);
+ return createBuiltin(getName(), mh);
}
@Override
@@ -151,8 +410,8 @@
}
/**
- * ECMA 15.3.5.3 [[HasInstance]] (V)
- * Step 3 if "prototype" value is not an Object, throw TypeError
+ * ECMA 15.3.5.3 [[HasInstance]] (V) Step 3 if "prototype" value is not an
+ * Object, throw TypeError
*/
@Override
public boolean isInstance(final ScriptObject instance) {
@@ -171,22 +430,25 @@
}
/**
- * Returns the target function for this function. If the function was not created using
- * {@link #makeBoundFunction(Object, Object[])}, its target function is itself. If it is bound, its target function
- * is the target function of the function it was made from (therefore, the target function is always the final,
- * unbound recipient of the calls).
+ * Returns the target function for this function. If the function was not
+ * created using {@link #createBound(Object, Object[])}, its target
+ * function is itself. If it is bound, its target function is the target
+ * function of the function it was made from (therefore, the target function
+ * is always the final, unbound recipient of the calls).
+ *
* @return the target function for this function.
*/
protected ScriptFunction getTargetFunction() {
return this;
}
- boolean isBoundFunction() {
+ final boolean isBoundFunction() {
return getTargetFunction() != this;
}
/**
* Set the arity of this ScriptFunction
+ *
* @param arity arity
*/
public final void setArity(final int arity) {
@@ -195,125 +457,121 @@
/**
* Is this a ECMAScript 'use strict' function?
+ *
* @return true if function is in strict mode
*/
- public boolean isStrict() {
+ public final boolean isStrict() {
return data.isStrict();
}
/**
- * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument
- * according to ECMA 10.4.3.
+ * Returns true if this is a non-strict, non-built-in function that requires
+ * non-primitive this argument according to ECMA 10.4.3.
+ *
* @return true if this argument must be an object
*/
- public boolean needsWrappedThis() {
+ public final boolean needsWrappedThis() {
return data.needsWrappedThis();
}
private static boolean needsWrappedThis(final Object fn) {
- return fn instanceof ScriptFunction ? ((ScriptFunction)fn).needsWrappedThis() : false;
+ return fn instanceof ScriptFunction ? ((ScriptFunction) fn).needsWrappedThis() : false;
}
/**
* Execute this script function.
- * @param self Target object.
- * @param arguments Call arguments.
+ *
+ * @param self Target object.
+ * @param arguments Call arguments.
* @return ScriptFunction result.
- * @throws Throwable if there is an exception/error with the invocation or thrown from it
+ * @throws Throwable if there is an exception/error with the invocation or
+ * thrown from it
*/
- Object invoke(final Object self, final Object... arguments) throws Throwable {
+ final Object invoke(final Object self, final Object... arguments) throws Throwable {
if (Context.DEBUG) {
- invokes++;
+ invokes.increment();
}
return data.invoke(this, self, arguments);
}
/**
* Execute this script function as a constructor.
- * @param arguments Call arguments.
+ *
+ * @param arguments Call arguments.
* @return Newly constructed result.
- * @throws Throwable if there is an exception/error with the invocation or thrown from it
+ * @throws Throwable if there is an exception/error with the invocation or
+ * thrown from it
*/
- Object construct(final Object... arguments) throws Throwable {
+ final Object construct(final Object... arguments) throws Throwable {
return data.construct(this, arguments);
}
/**
- * Allocate function. Called from generated {@link ScriptObject} code
- * for allocation as a factory method
+ * Allocate function. Called from generated {@link ScriptObject} code for
+ * allocation as a factory method
*
- * @return a new instance of the {@link ScriptObject} whose allocator this is
+ * @return a new instance of the {@link ScriptObject} whose allocator this
+ * is
*/
@SuppressWarnings("unused")
private Object allocate() {
if (Context.DEBUG) {
- allocations++;
+ allocations.increment();
}
assert !isBoundFunction(); // allocate never invoked on bound functions
- final ScriptObject object = data.allocate(getAllocatorMap());
+ final ScriptObject prototype = getAllocatorPrototype();
+ final ScriptObject object = data.allocate(getAllocatorMap(prototype));
if (object != null) {
- final Object prototype = getPrototype();
- if (prototype instanceof ScriptObject) {
- object.setInitialProto((ScriptObject)prototype);
- }
-
- if (object.getProto() == null) {
- object.setInitialProto(getObjectPrototype());
- }
+ object.setInitialProto(prototype);
}
return object;
}
- private PropertyMap getAllocatorMap() {
- if (allocatorMap == null) {
- allocatorMap = data.getAllocatorMap();
+ /**
+ * Get the property map used by "allocate"
+ * @param prototype actual prototype object
+ * @return property map
+ */
+ private synchronized PropertyMap getAllocatorMap(final ScriptObject prototype) {
+ if (allocatorMap == null || allocatorMap.isInvalidSharedMapFor(prototype)) {
+ // The prototype map has changed since this function was last used as constructor.
+ // Get a new allocator map.
+ allocatorMap = data.getAllocatorMap(prototype);
}
return allocatorMap;
}
/**
- * Return Object.prototype - used by "allocate"
- * @return Object.prototype
+ * Return the actual prototype used by "allocate"
+ * @return allocator prototype
*/
- protected abstract ScriptObject getObjectPrototype();
-
- /**
- * Creates a version of this function bound to a specific "self" and other arguments, as per
- * {@code Function.prototype.bind} functionality in ECMAScript 5.1 section 15.3.4.5.
- * @param self the self to bind to this function. Can be null (in which case, null is bound as this).
- * @param args additional arguments to bind to this function. Can be null or empty to not bind additional arguments.
- * @return a function with the specified self and parameters bound.
- */
- protected ScriptFunction makeBoundFunction(final Object self, final Object[] args) {
- return makeBoundFunction(data.makeBoundFunctionData(this, self, args));
+ private ScriptObject getAllocatorPrototype() {
+ final Object prototype = getPrototype();
+ if (prototype instanceof ScriptObject) {
+ return (ScriptObject) prototype;
+ }
+ return Global.objectPrototype();
}
- /**
- * Create a version of this function as in {@link ScriptFunction#makeBoundFunction(Object, Object[])},
- * but using a {@link ScriptFunctionData} for the bound data.
- *
- * @param boundData ScriptFuntionData for the bound function
- * @return a function with the bindings performed according to the given data
- */
- protected abstract ScriptFunction makeBoundFunction(ScriptFunctionData boundData);
-
@Override
public final String safeToString() {
return toSource();
}
@Override
- public String toString() {
+ public final String toString() {
return data.toString();
}
/**
- * Get this function as a String containing its source code. If no source code
- * exists in this ScriptFunction, its contents will be displayed as {@code [native code]}
+ * Get this function as a String containing its source code. If no source
+ * code exists in this ScriptFunction, its contents will be displayed as
+ * {@code [native code]}
+ *
* @return string representation of this function's source
*/
public final String toSource() {
@@ -322,27 +580,32 @@
/**
* Get the prototype object for this function
+ *
* @return prototype
*/
- public abstract Object getPrototype();
+ public final Object getPrototype() {
+ if (prototype == LAZY_PROTOTYPE) {
+ prototype = new PrototypeObject(this);
+ }
+ return prototype;
+ }
/**
* Set the prototype object for this function
- * @param prototype new prototype object
+ *
+ * @param newPrototype new prototype object
*/
- public abstract void setPrototype(Object prototype);
+ public synchronized final void setPrototype(final Object newPrototype) {
+ if (newPrototype instanceof ScriptObject && newPrototype != this.prototype && allocatorMap != null) {
+ // Unset allocator map to be replaced with one matching the new prototype.
+ allocatorMap = null;
+ }
+ this.prototype = newPrototype;
+ }
/**
- * Create a function that invokes this function synchronized on {@code sync} or the self object
- * of the invocation.
- * @param sync the Object to synchronize on, or undefined
- * @return synchronized function
- */
- public abstract ScriptFunction makeSynchronizedFunction(Object sync);
-
- /**
- * Return the invoke handle bound to a given ScriptObject self reference.
- * If callee parameter is required result is rebound to this.
+ * Return the invoke handle bound to a given ScriptObject self reference. If
+ * callee parameter is required result is rebound to this.
*
* @param self self reference
* @return bound invoke handle
@@ -352,9 +615,12 @@
}
/**
- * Bind the method handle to this {@code ScriptFunction} instance if it needs a callee parameter. If this function's
- * method handles don't have a callee parameter, the handle is returned unchanged.
- * @param methodHandle the method handle to potentially bind to this function instance.
+ * Bind the method handle to this {@code ScriptFunction} instance if it
+ * needs a callee parameter. If this function's method handles don't have a
+ * callee parameter, the handle is returned unchanged.
+ *
+ * @param methodHandle the method handle to potentially bind to this
+ * function instance.
* @return the potentially bound method handle
*/
private MethodHandle bindToCalleeIfNeeded(final MethodHandle methodHandle) {
@@ -364,15 +630,16 @@
/**
* Get the name for this function
+ *
* @return the name
*/
public final String getName() {
return data.getName();
}
-
/**
* Get the scope for this function
+ *
* @return the scope
*/
public final ScriptObject getScope() {
@@ -383,36 +650,37 @@
* Prototype getter for this ScriptFunction - follows the naming convention
* used by Nasgen and the code generator
*
- * @param self self reference
+ * @param self self reference
* @return self's prototype
*/
public static Object G$prototype(final Object self) {
- return self instanceof ScriptFunction ?
- ((ScriptFunction)self).getPrototype() :
- UNDEFINED;
+ return self instanceof ScriptFunction
+ ? ((ScriptFunction) self).getPrototype()
+ : UNDEFINED;
}
/**
* Prototype setter for this ScriptFunction - follows the naming convention
* used by Nasgen and the code generator
*
- * @param self self reference
+ * @param self self reference
* @param prototype prototype to set
*/
public static void S$prototype(final Object self, final Object prototype) {
if (self instanceof ScriptFunction) {
- ((ScriptFunction)self).setPrototype(prototype);
+ ((ScriptFunction) self).setPrototype(prototype);
}
}
/**
* Length getter - ECMA 15.3.3.2: Function.length
+ *
* @param self self reference
* @return length
*/
public static int G$length(final Object self) {
if (self instanceof ScriptFunction) {
- return ((ScriptFunction)self).data.getArity();
+ return ((ScriptFunction) self).data.getArity();
}
return 0;
@@ -420,12 +688,13 @@
/**
* Name getter - ECMA Function.name
+ *
* @param self self refence
* @return the name, or undefined if none
*/
public static Object G$name(final Object self) {
if (self instanceof ScriptFunction) {
- return ((ScriptFunction)self).getName();
+ return ((ScriptFunction) self).getName();
}
return UNDEFINED;
@@ -433,6 +702,7 @@
/**
* Get the prototype for this ScriptFunction
+ *
* @param constructor constructor
* @return prototype, or null if given constructor is not a ScriptFunction
*/
@@ -440,7 +710,7 @@
if (constructor != null) {
final Object proto = constructor.getPrototype();
if (proto instanceof ScriptObject) {
- return (ScriptObject)proto;
+ return (ScriptObject) proto;
}
}
@@ -448,29 +718,37 @@
}
// These counters are updated only in debug mode.
- private static int constructorCount;
- private static int invokes;
- private static int allocations;
+ private static LongAdder constructorCount;
+ private static LongAdder invokes;
+ private static LongAdder allocations;
+
+ static {
+ if (Context.DEBUG) {
+ constructorCount = new LongAdder();
+ invokes = new LongAdder();
+ allocations = new LongAdder();
+ }
+ }
/**
* @return the constructorCount
*/
- public static int getConstructorCount() {
- return constructorCount;
+ public static long getConstructorCount() {
+ return constructorCount.longValue();
}
/**
* @return the invokes
*/
- public static int getInvokes() {
- return invokes;
+ public static long getInvokes() {
+ return invokes.longValue();
}
/**
* @return the allocations
*/
- public static int getAllocations() {
- return allocations;
+ public static long getAllocations() {
+ return allocations.longValue();
}
@Override
@@ -490,7 +768,6 @@
return Context.getGlobal().wrapAsObject(obj);
}
-
@SuppressWarnings("unused")
private static Object globalFilter(final Object object) {
// replace whatever we get with the current global object
@@ -498,14 +775,16 @@
}
/**
- * Some receivers are primitive, in that case, according to the Spec we create a new
- * native object per callsite with the wrap filter. We can only apply optimistic builtins
- * if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings),
- * otherwise we can't create optimistic versions
+ * Some receivers are primitive, in that case, according to the Spec we
+ * create a new native object per callsite with the wrap filter. We can only
+ * apply optimistic builtins if there is no per instance state saved for
+ * these wrapped objects (e.g. currently NativeStrings), otherwise we can't
+ * create optimistic versions
*
- * @param self receiver
- * @param linkLogicClass linkLogicClass, or null if no link logic exists
- * @return link logic instance, or null if one could not be constructed for this receiver
+ * @param self receiver
+ * @param linkLogicClass linkLogicClass, or null if no link logic exists
+ * @return link logic instance, or null if one could not be constructed for
+ * this receiver
*/
private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
if (linkLogicClass == null) {
@@ -518,25 +797,25 @@
final Object wrappedSelf = wrapFilter(self);
if (wrappedSelf instanceof OptimisticBuiltins) {
- if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) {
+ if (wrappedSelf != self && ((OptimisticBuiltins) wrappedSelf).hasPerInstanceAssumptions()) {
return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
}
- return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass);
+ return ((OptimisticBuiltins) wrappedSelf).getLinkLogic(linkLogicClass);
}
return null;
}
/**
- * dyn:call call site signature: (callee, thiz, [args...])
- * generated method signature: (callee, thiz, [args...])
+ * dyn:call call site signature: (callee, thiz, [args...]) generated method
+ * signature: (callee, thiz, [args...])
*
* cases:
* (a) method has callee parameter
- * (1) for local/scope calls, we just bind thiz and drop the second argument.
- * (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
+ * (1) for local/scope calls, we just bind thiz and drop the second argument.
+ * (2) for normal this-calls, we have to swap thiz and callee to get matching signatures.
* (b) method doesn't have callee parameter (builtin functions)
- * (3) for local/scope calls, bind thiz and drop both callee and thiz.
- * (4) for normal this-calls, drop callee.
+ * (3) for local/scope calls, bind thiz and drop both callee and thiz.
+ * (4) for normal this-calls, drop callee.
*
* @return guarded invocation for call
*/
@@ -544,11 +823,11 @@
protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType type = desc.getMethodType();
- final String name = getName();
+ final String name = getName();
final boolean isUnstable = request.isCallSiteUnstable();
- final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
- final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name);
- final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name);
+ final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc);
+ final boolean isCall = !scopeCall && data.isBuiltin() && "call".equals(name);
+ final boolean isApply = !scopeCall && data.isBuiltin() && "apply".equals(name);
final boolean isApplyOrCall = isCall | isApply;
@@ -569,7 +848,7 @@
return new GuardedInvocation(
handle,
null,
- (SwitchPoint)null,
+ (SwitchPoint) null,
ClassCastException.class);
}
@@ -672,14 +951,14 @@
this,
cf.getFlags()) :
guard,
- spsArray,
+ spsArray,
exceptionGuard);
}
private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
final MethodType descType = desc.getMethodType();
final int paramCount = descType.parameterCount();
- if(descType.parameterType(paramCount - 1).isArray()) {
+ if (descType.parameterType(paramCount - 1).isArray()) {
// This is vararg invocation of apply or call. This can normally only happen when we do a recursive
// invocation of createApplyOrCallCall (because we're doing apply-of-apply). In this case, create delegate
// linkage by unpacking the vararg invocation and use pairArguments to introduce the necessary spreader.
@@ -786,7 +1065,7 @@
inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
} else {
// If the original call site doesn't pass argArray, pass in an empty array
- inv = MH.insertArguments(inv, 2, (Object)ScriptRuntime.EMPTY_ARRAY);
+ inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
}
}
@@ -851,7 +1130,7 @@
final LinkRequest request, final Object[] args) {
final MethodType descType = desc.getMethodType();
final int paramCount = descType.parameterCount();
- final Object[] varArgs = (Object[])args[paramCount - 1];
+ final Object[] varArgs = (Object[]) args[paramCount - 1];
// -1 'cause we're not passing the vararg array itself
final int copiedArgCount = args.length - 1;
final int varArgCount = varArgs.length;
@@ -893,7 +1172,7 @@
// If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
// invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
// with ClassCastException of NativeArray to Object[].
- if(guardType.parameterType(guardParamCount - 1).isArray()) {
+ if (guardType.parameterType(guardParamCount - 1).isArray()) {
arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
} else {
arrayConvertingGuard = guard;
@@ -903,19 +1182,20 @@
}
private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
- final MethodHandle bound;
- if(fn instanceof ScriptFunction && ((ScriptFunction)fn).needsWrappedThis()) {
- bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
- } else {
- bound = mh;
- }
- return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
- }
+ final MethodHandle bound;
+ if (fn instanceof ScriptFunction && ((ScriptFunction) fn).needsWrappedThis()) {
+ bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
+ } else {
+ bound = mh;
+ }
+ return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
+ }
/**
* Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
*
- * These don't want a callee parameter, so bind that. Name binding is optional.
+ * These don't want a callee parameter, so bind that. Name binding is
+ * optional.
*/
MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
@@ -939,10 +1219,11 @@
}
/**
- * Get the guard that checks if a {@link ScriptFunction} is equal to
- * a known ScriptFunction, using reference comparison
+ * Get the guard that checks if a {@link ScriptFunction} is equal to a known
+ * ScriptFunction, using reference comparison
*
- * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+ * @param function The ScriptFunction to check against. This will be bound
+ * to the guard method handle
*
* @return method handle for guard
*/
@@ -957,11 +1238,12 @@
}
/**
- * Get a guard that checks if a {@link ScriptFunction} is equal to
- * a known ScriptFunction using reference comparison, and whether the type of
- * the second argument (this-object) is not a JavaScript primitive type.
+ * Get a guard that checks if a {@link ScriptFunction} is equal to a known
+ * ScriptFunction using reference comparison, and whether the type of the
+ * second argument (this-object) is not a JavaScript primitive type.
*
- * @param function The ScriptFunction to check against. This will be bound to the guard method handle
+ * @param function The ScriptFunction to check against. This will be bound
+ * to the guard method handle
*
* @return method handle for guard
*/
@@ -972,12 +1254,12 @@
@SuppressWarnings("unused")
private static boolean isFunctionMH(final Object self, final ScriptFunctionData data) {
- return self instanceof ScriptFunction && ((ScriptFunction)self).data == data;
+ return self instanceof ScriptFunction && ((ScriptFunction) self).data == data;
}
@SuppressWarnings("unused")
private static boolean isNonStrictFunction(final Object self, final Object arg, final ScriptFunctionData data) {
- return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
+ return self instanceof ScriptFunction && ((ScriptFunction) self).data == data && arg instanceof ScriptObject;
}
//TODO this can probably be removed given that we have builtin switchpoints in the context
@@ -990,7 +1272,7 @@
@SuppressWarnings("unused")
private static Object[] addZerothElement(final Object[] args, final Object value) {
// extends input array with by adding new zeroth element
- final Object[] src = args == null? ScriptRuntime.EMPTY_ARRAY : args;
+ final Object[] src = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
final Object[] result = new Object[src.length + 1];
System.arraycopy(src, 0, result, 1, src.length);
result[0] = value;
@@ -1014,4 +1296,3 @@
return MH.findVirtual(MethodHandles.lookup(), ScriptFunction.class, name, MH.type(rtype, types));
}
}
-
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index 012898b..84bf928 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -151,7 +151,7 @@
* Is this a ScriptFunction generated with strict semantics?
* @return true if strict, false otherwise
*/
- public boolean isStrict() {
+ public final boolean isStrict() {
return (flags & IS_STRICT) != 0;
}
@@ -164,11 +164,11 @@
return getName();
}
- boolean isBuiltin() {
+ final boolean isBuiltin() {
return (flags & IS_BUILTIN) != 0;
}
- boolean isConstructor() {
+ final boolean isConstructor() {
return (flags & IS_CONSTRUCTOR) != 0;
}
@@ -179,7 +179,7 @@
* according to ECMA 10.4.3.
* @return true if this argument must be an object
*/
- boolean needsWrappedThis() {
+ final boolean needsWrappedThis() {
return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0;
}
@@ -318,7 +318,7 @@
* Used to find an apply to call version that fits this callsite.
* We cannot just, as in the normal matcher case, return e.g. (Object, Object, int)
* for (Object, Object, int, int, int) or we will destroy the semantics and get
- * a function that, when padded with undefineds, behaves differently
+ * a function that, when padded with undefined values, behaves differently
* @param type actual call site type
* @return apply to call that perfectly fits this callsite or null if none found
*/
@@ -359,31 +359,13 @@
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
* @return the best function for the specified call site type.
*/
- CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
- assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
- assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
+ abstract CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden);
- if (isRecompilable()) {
- final CompiledFunction candidate = pickFunction(callSiteType, false);
- if (candidate != null) {
- return candidate;
- }
- return pickFunction(callSiteType, true); //try vararg last
- }
-
- CompiledFunction best = null;
- for (final CompiledFunction candidate: code) {
- if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
- best = candidate;
- }
- }
-
- return best;
+ boolean isValidCallSite(final MethodType callSiteType) {
+ return callSiteType.parameterCount() >= 2 && // Must have at least (callee, this)
+ callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class); // Callee must be assignable from script function
}
-
- abstract boolean isRecompilable();
-
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
}
@@ -407,15 +389,16 @@
/**
* Get the property map to use for objects allocated by this function.
*
+ * @param prototype the prototype of the allocated object
* @return the property map for allocated objects.
*/
- PropertyMap getAllocatorMap() {
+ PropertyMap getAllocatorMap(final ScriptObject prototype) {
return null;
}
/**
* This method is used to create the immutable portion of a bound function.
- * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
+ * See {@link ScriptFunction#createBound(Object, Object[])}
*
* @param fn the original function being bound
* @param self this reference to bind. Can be null.
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
index e041e51..0353bdc 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -64,6 +64,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.LongAdder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -148,7 +149,7 @@
/** Method handle to retrieve prototype of this object */
public static final MethodHandle GETPROTO = findOwnMH_V("getProto", ScriptObject.class);
- static final MethodHandle MEGAMORPHIC_GET = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class);
+ static final MethodHandle MEGAMORPHIC_GET = findOwnMH_V("megamorphicGet", Object.class, String.class, boolean.class, boolean.class);
static final MethodHandle GLOBALFILTER = findOwnMH_S("globalFilter", Object.class, Object.class);
static final MethodHandle DECLARE_AND_SET = findOwnMH_V("declareAndSet", void.class, String.class, Object.class);
@@ -211,7 +212,7 @@
*/
public ScriptObject(final PropertyMap map) {
if (Context.DEBUG) {
- ScriptObject.count++;
+ ScriptObject.count.increment();
}
this.arrayData = ArrayData.EMPTY_ARRAY;
this.setMap(map == null ? PropertyMap.newMap() : map);
@@ -224,7 +225,7 @@
* same combination of prototype and property map.
*
* @param proto the prototype object
- * @param map intial {@link PropertyMap}
+ * @param map initial {@link PropertyMap}
*/
protected ScriptObject(final ScriptObject proto, final PropertyMap map) {
this(map);
@@ -287,9 +288,10 @@
*/
public void addBoundProperties(final ScriptObject source, final Property[] properties) {
PropertyMap newMap = this.getMap();
+ final boolean extensible = newMap.isExtensible();
for (final Property property : properties) {
- newMap = addBoundProperty(newMap, source, property);
+ newMap = addBoundProperty(newMap, source, property, extensible);
}
this.setMap(newMap);
@@ -302,13 +304,18 @@
* @param propMap the property map
* @param source the source object
* @param property the property to be added
+ * @param extensible whether the current object is extensible or not
* @return the new property map
*/
- protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property) {
+ protected PropertyMap addBoundProperty(final PropertyMap propMap, final ScriptObject source, final Property property, final boolean extensible) {
PropertyMap newMap = propMap;
final String key = property.getKey();
final Property oldProp = newMap.findProperty(key);
if (oldProp == null) {
+ if (! extensible) {
+ throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+ }
+
if (property instanceof UserAccessorProperty) {
// Note: we copy accessor functions to this object which is semantically different from binding.
final UserAccessorProperty prop = this.newUserAccessors(key, property.getFlags(), property.getGetterFunction(source), property.getSetterFunction(source));
@@ -337,11 +344,15 @@
*/
public void addBoundProperties(final Object source, final AccessorProperty[] properties) {
PropertyMap newMap = this.getMap();
+ final boolean extensible = newMap.isExtensible();
for (final AccessorProperty property : properties) {
final String key = property.getKey();
if (newMap.findProperty(key) == null) {
+ if (! extensible) {
+ throw typeError("object.non.extensible", key, ScriptRuntime.safeToString(this));
+ }
newMap = newMap.addPropertyBind(property, source);
}
}
@@ -699,8 +710,7 @@
final long longIndex = ArrayIndex.toLongIndex(index);
final long oldLength = getArray().length();
if (longIndex >= oldLength) {
- setArray(getArray().ensure(longIndex));
- doesNotHaveEnsureDelete(longIndex, oldLength, false);
+ setArray(getArray().ensure(longIndex).safeDelete(oldLength, longIndex - 1, false));
}
setArray(getArray().set(index, value, false));
}
@@ -798,9 +808,11 @@
if (deep) {
final ScriptObject myProto = getProto();
- if (myProto != null) {
- return myProto.findProperty(key, deep, start);
- }
+ final FindProperty find = myProto == null ? null : myProto.findProperty(key, true, start);
+ // checkSharedProtoMap must be invoked after myProto.checkSharedProtoMap to propagate
+ // shared proto invalidation up the prototype chain. It also must be invoked when prototype is null.
+ checkSharedProtoMap();
+ return find;
}
return null;
@@ -821,7 +833,7 @@
if (deep) {
final ScriptObject myProto = getProto();
if (myProto != null) {
- return myProto.hasProperty(key, deep);
+ return myProto.hasProperty(key, true);
}
}
@@ -1247,11 +1259,8 @@
if (oldProto != newProto) {
proto = newProto;
- // Let current listeners know that the protototype has changed and set our map
- final PropertyListeners listeners = getMap().getListeners();
- if (listeners != null) {
- listeners.protoChanged();
- }
+ // Let current listeners know that the prototype has changed
+ getMap().protoChanged(true);
// Replace our current allocator map with one that is associated with the new prototype.
setMap(getMap().changeProto(newProto));
}
@@ -1303,7 +1312,7 @@
}
p = p.getProto();
}
- setProto((ScriptObject)newProto);
+ setProto((ScriptObject) newProto);
} else {
throw typeError("cant.set.proto.to.non.object", ScriptRuntime.safeToString(this), ScriptRuntime.safeToString(newProto));
}
@@ -1442,7 +1451,7 @@
* in {@link ScriptFunction} for hasInstance implementation, walks
* the proto chain
*
- * @param instance instace to check
+ * @param instance instance to check
* @return true if 'instance' is an instance of this object
*/
public boolean isInstance(final ScriptObject instance) {
@@ -1849,7 +1858,7 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- return notAFunction();
+ return notAFunction(desc);
}
/**
@@ -1859,14 +1868,14 @@
* @param desc the call site descriptor.
* @param request the link request
*
- * @return GuardedInvocation to be invoed at call site.
+ * @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findCallMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- return notAFunction();
+ return notAFunction(desc);
}
- private GuardedInvocation notAFunction() {
- throw typeError("not.a.function", ScriptRuntime.safeToString(this));
+ private GuardedInvocation notAFunction(final CallSiteDescriptor desc) {
+ throw typeError("not.a.function", NashornCallSiteDescriptor.getFunctionErrorMessage(desc, this));
}
/**
@@ -1986,11 +1995,11 @@
final ScriptObject owner = find.getOwner();
final Class<ClassCastException> exception = explicitInstanceOfCheck ? null : ClassCastException.class;
- final SwitchPoint protoSwitchPoint;
+ final SwitchPoint[] protoSwitchPoints;
if (mh == null) {
mh = Lookup.emptyGetter(returnType);
- protoSwitchPoint = getProtoSwitchPoint(name, owner);
+ protoSwitchPoints = getProtoSwitchPoints(name, owner);
} else if (!find.isSelf()) {
assert mh.type().returnType().equals(returnType) :
"return type mismatch for getter " + mh.type().returnType() + " != " + returnType;
@@ -1998,30 +2007,30 @@
// Add a filter that replaces the self object with the prototype owning the property.
mh = addProtoFilter(mh, find.getProtoChainLength());
}
- protoSwitchPoint = getProtoSwitchPoint(name, owner);
+ protoSwitchPoints = getProtoSwitchPoints(name, owner);
} else {
- protoSwitchPoint = null;
+ protoSwitchPoints = null;
}
- final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
+ final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoints, exception);
return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
Context.getContextTrusted().getLogger(ObjectClassGenerator.class).warning("Megamorphic getter: " + desc + " " + name + " " +isMethod);
- final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod);
+ final MethodHandle invoker = MH.insertArguments(MEGAMORPHIC_GET, 1, name, isMethod, NashornCallSiteDescriptor.isScope(desc));
final MethodHandle guard = getScriptObjectGuard(desc.getMethodType(), true);
return new GuardedInvocation(invoker, guard);
}
@SuppressWarnings("unused")
- private Object megamorphicGet(final String key, final boolean isMethod) {
+ private Object megamorphicGet(final String key, final boolean isMethod, final boolean isScope) {
final FindProperty find = findProperty(key, true);
if (find != null) {
return find.getObjectValue();
}
- return isMethod ? getNoSuchMethod(key, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
+ return isMethod ? getNoSuchMethod(key, isScope, INVALID_PROGRAM_POINT) : invokeNoSuchProperty(key, isScope, INVALID_PROGRAM_POINT);
}
// Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
@@ -2102,17 +2111,32 @@
* @param owner the property owner, null if property is not defined
* @return a SwitchPoint or null
*/
- public final SwitchPoint getProtoSwitchPoint(final String name, final ScriptObject owner) {
+ public final SwitchPoint[] getProtoSwitchPoints(final String name, final ScriptObject owner) {
if (owner == this || getProto() == null) {
return null;
}
+ final List<SwitchPoint> switchPoints = new ArrayList<>();
for (ScriptObject obj = this; obj != owner && obj.getProto() != null; obj = obj.getProto()) {
final ScriptObject parent = obj.getProto();
parent.getMap().addListener(name, obj.getMap());
+ final SwitchPoint sp = parent.getMap().getSharedProtoSwitchPoint();
+ if (sp != null && !sp.hasBeenInvalidated()) {
+ switchPoints.add(sp);
+ }
}
- return getMap().getSwitchPoint(name);
+ switchPoints.add(getMap().getSwitchPoint(name));
+ return switchPoints.toArray(new SwitchPoint[switchPoints.size()]);
+ }
+
+ private void checkSharedProtoMap() {
+ // Check if our map has an expected shared prototype property map. If it has, make sure that
+ // the prototype map has not been invalidated, and that it does match the actual map of the prototype.
+ if (getMap().isInvalidSharedMapFor(getProto())) {
+ // Change our own map to one that does not assume a shared prototype map.
+ setMap(getMap().makeUnsharedCopy());
+ }
}
/**
@@ -2194,7 +2218,7 @@
return new GuardedInvocation(
Lookup.EMPTY_SETTER,
NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
- getProtoSwitchPoint(name, null),
+ getProtoSwitchPoints(name, null),
explicitInstanceOfCheck ? null : ClassCastException.class);
}
@@ -2291,7 +2315,7 @@
MH.dropArguments(
MH.constant(
ScriptFunction.class,
- func.makeBoundFunction(thiz, new Object[] { name })),
+ func.createBound(thiz, new Object[] { name })),
0,
Object.class),
NashornGuards.combineGuards(
@@ -2340,7 +2364,7 @@
find.getGetter(Object.class, INVALID_PROGRAM_POINT, request),
find.getProtoChainLength(),
func),
- getProtoSwitchPoint(NO_SUCH_PROPERTY_NAME, find.getOwner()),
+ getProtoSwitchPoints(NO_SUCH_PROPERTY_NAME, find.getOwner()),
//TODO this doesn't need a ClassCastException as guard always checks script object
null);
}
@@ -2356,20 +2380,21 @@
/**
* Invoke fall back if a property is not found.
* @param name Name of property.
+ * @param isScope is this a scope access?
* @param programPoint program point
* @return Result from call.
*/
- protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+ protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+ final Object func = (find != null)? find.getObjectValue() : null;
Object ret = UNDEFINED;
-
- if (find != null) {
- final Object func = find.getObjectValue();
-
- if (func instanceof ScriptFunction) {
- ret = ScriptRuntime.apply((ScriptFunction)func, this, name);
- }
+ if (func instanceof ScriptFunction) {
+ final ScriptFunction sfunc = (ScriptFunction)func;
+ final Object self = isScope && sfunc.isStrict()? UNDEFINED : this;
+ ret = ScriptRuntime.apply(sfunc, self, name);
+ } else if (isScope) {
+ throw referenceError("not.defined", name);
}
if (isValid(programPoint)) {
@@ -2383,21 +2408,27 @@
/**
* Get __noSuchMethod__ as a function bound to this object and {@code name} if it is defined.
* @param name the method name
+ * @param isScope is this a scope access?
* @return the bound function, or undefined
*/
- private Object getNoSuchMethod(final String name, final int programPoint) {
+ private Object getNoSuchMethod(final String name, final boolean isScope, final int programPoint) {
final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
if (find == null) {
- return invokeNoSuchProperty(name, programPoint);
+ return invokeNoSuchProperty(name, isScope, programPoint);
}
final Object value = find.getObjectValue();
if (!(value instanceof ScriptFunction)) {
+ if (isScope) {
+ throw referenceError("not.defined", name);
+ }
return UNDEFINED;
}
- return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
+ final ScriptFunction func = (ScriptFunction)value;
+ final Object self = isScope && func.isStrict()? UNDEFINED : this;
+ return func.createBound(self, new Object[] {name});
}
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String name) {
@@ -2406,7 +2437,7 @@
}
return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()),
- NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), getProtoSwitchPoint(name, null),
+ NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), getProtoSwitchPoints(name, null),
explicitInstanceOfCheck ? null : ClassCastException.class);
}
@@ -2646,11 +2677,7 @@
}
if (newLength > arrayLength) {
- data = data.ensure(newLength - 1);
- if (data.canDelete(arrayLength, newLength - 1, false)) {
- data = data.delete(arrayLength, newLength - 1);
- }
- setArray(data);
+ setArray(data.ensure(newLength - 1).safeDelete(arrayLength, newLength - 1, false));
return;
}
@@ -2712,7 +2739,7 @@
}
}
- return JSType.toInt32(invokeNoSuchProperty(key, programPoint));
+ return JSType.toInt32(invokeNoSuchProperty(key, false, programPoint));
}
@Override
@@ -2794,7 +2821,7 @@
}
}
- return JSType.toLong(invokeNoSuchProperty(key, programPoint));
+ return JSType.toLong(invokeNoSuchProperty(key, false, programPoint));
}
@Override
@@ -2876,7 +2903,7 @@
}
}
- return JSType.toNumber(invokeNoSuchProperty(key, INVALID_PROGRAM_POINT));
+ return JSType.toNumber(invokeNoSuchProperty(key, false, INVALID_PROGRAM_POINT));
}
@Override
@@ -2957,7 +2984,7 @@
}
}
- return invokeNoSuchProperty(key, INVALID_PROGRAM_POINT);
+ return invokeNoSuchProperty(key, false, INVALID_PROGRAM_POINT);
}
@Override
@@ -3071,23 +3098,12 @@
return false;
}
- private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
- if (longIndex > oldLength) {
- ArrayData array = getArray();
- if (array.canDelete(oldLength, longIndex - 1, strict)) {
- array = array.delete(oldLength, longIndex - 1);
- }
- setArray(array);
- }
- }
-
private void doesNotHave(final int index, final int value, final int callSiteFlags) {
final long oldLength = getArray().length();
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
final boolean strict = isStrictFlag(callSiteFlags);
- setArray(getArray().set(index, value, strict));
- doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+ setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
}
}
@@ -3096,8 +3112,7 @@
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
final boolean strict = isStrictFlag(callSiteFlags);
- setArray(getArray().set(index, value, strict));
- doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+ setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
}
}
@@ -3106,8 +3121,7 @@
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
final boolean strict = isStrictFlag(callSiteFlags);
- setArray(getArray().set(index, value, strict));
- doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+ setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
}
}
@@ -3116,8 +3130,7 @@
final long longIndex = ArrayIndex.toLongIndex(index);
if (!doesNotHaveCheckArrayKeys(longIndex, value, callSiteFlags) && !doesNotHaveEnsureLength(longIndex, oldLength, callSiteFlags)) {
final boolean strict = isStrictFlag(callSiteFlags);
- setArray(getArray().set(index, value, strict));
- doesNotHaveEnsureDelete(longIndex, oldLength, strict);
+ setArray(getArray().set(index, value, strict).safeDelete(oldLength, longIndex - 1, strict));
}
}
@@ -3786,15 +3799,20 @@
}
/** This is updated only in debug mode - counts number of {@code ScriptObject} instances created */
- private static int count;
+ private static LongAdder count;
+ static {
+ if (Context.DEBUG) {
+ count = new LongAdder();
+ }
+ }
/**
* Get number of {@code ScriptObject} instances created. If not running in debug
* mode this is always 0
*
* @return number of ScriptObjects created
*/
- public static int getCount() {
- return count;
+ public static long getCount() {
+ return count.longValue();
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
index 49109da..ae46d25 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
@@ -685,6 +685,33 @@
}
/**
+ * ECMA 11.4.1 - delete operator, implementation for slow scopes
+ *
+ * This implementation of 'delete' walks the scope chain to find the scope that contains the
+ * property to be deleted, then invokes delete on it.
+ *
+ * @param obj top scope object
+ * @param property property to delete
+ * @param strict are we in strict mode
+ *
+ * @return true if property was successfully found and deleted
+ */
+ public static boolean SLOW_DELETE(final Object obj, final Object property, final Object strict) {
+ if (obj instanceof ScriptObject) {
+ ScriptObject sobj = (ScriptObject) obj;
+ final String key = property.toString();
+ while (sobj != null && sobj.isScope()) {
+ final FindProperty find = sobj.findProperty(key, false);
+ if (find != null) {
+ return sobj.delete(key, Boolean.TRUE.equals(strict));
+ }
+ sobj = sobj.getProto();
+ }
+ }
+ return DELETE(obj, property, strict);
+ }
+
+ /**
* ECMA 11.4.1 - delete operator, special case
*
* This is 'delete' that always fails. We have to check strict mode and throw error.
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
index f4df779..d06c06f 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -70,6 +71,9 @@
/** EXIT name - special property used by $EXEC API. */
public static final String EXIT_NAME = "$EXIT";
+ /** THROW_ON_ERROR name - special property of the $EXEC function used by $EXEC API. */
+ public static final String THROW_ON_ERROR_NAME = "throwOnError";
+
/** Names of special properties used by $ENV API. */
public static final String ENV_NAME = "$ENV";
@@ -244,6 +248,19 @@
}
}
+ // if we got a non-zero exit code ("failure"), then we have to decide to throw error or not
+ if (exit != 0) {
+ // get the $EXEC function object from the global object
+ final Object exec = global.get(EXEC_NAME);
+ assert exec instanceof ScriptObject : EXEC_NAME + " is not a script object!";
+
+ // Check if the user has set $EXEC.throwOnError property to true. If so, throw RangeError
+ // If that property is not set or set to false, then silently proceed with the rest.
+ if (JSType.toBoolean(((ScriptObject)exec).get(THROW_ON_ERROR_NAME))) {
+ throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exit));
+ }
+ }
+
// Return the result from stdout.
return out;
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index 4fe1b4f..4427930 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -186,10 +186,7 @@
private SetMethod createNewPropertySetter(final SwitchPoint builtinSwitchPoint) {
final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter(builtinSwitchPoint) : createNewSpillPropertySetter(builtinSwitchPoint);
- final PropertyListeners listeners = map.getListeners();
- if (listeners != null) {
- listeners.propertyAdded(sm.property);
- }
+ map.propertyAdded(sm.property, true);
return sm;
}
@@ -204,7 +201,7 @@
//fast type specific setter
final MethodHandle fastSetter = property.getSetter(type, newMap); //0 sobj, 1 value, slot folded for spill property already
- //slow setter, that calls ScriptObject.set with appropraite type and key name
+ //slow setter, that calls ScriptObject.set with appropriate type and key name
MethodHandle slowSetter = ScriptObject.SET_SLOW[getAccessorTypeIndex(type)];
slowSetter = MH.insertArguments(slowSetter, 3, NashornCallSiteDescriptor.getFlags(desc));
slowSetter = MH.insertArguments(slowSetter, 1, name);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/SharedPropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/SharedPropertyMap.java
new file mode 100644
index 0000000..215d0c8
--- /dev/null
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SharedPropertyMap.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.lang.invoke.SwitchPoint;
+
+/**
+ * This class represents a property map that can be shared among multiple prototype objects, allowing all inheriting
+ * top-level objects to also share one property map. This is class is only used for prototype objects, the
+ * top-level objects use ordinary {@link PropertyMap}s with the {@link PropertyMap#sharedProtoMap} field
+ * set to the expected shared prototype map.
+ *
+ * <p>When an instance of this class is evolved because a property is added, removed, or modified in an object
+ * using it, the {@link #invalidateSwitchPoint()} method is invoked to signal to all callsites and inheriting
+ * objects that the assumption of a single shared prototype map is no longer valid. The property map resulting
+ * from the modification will no longer be an instance of this class.</p>
+ */
+public final class SharedPropertyMap extends PropertyMap {
+
+ private SwitchPoint switchPoint;
+
+ private static final long serialVersionUID = 2166297719721778876L;
+
+ /**
+ * Create a new shared property map from the given {@code map}.
+ * @param map property map to copy
+ */
+ public SharedPropertyMap(final PropertyMap map) {
+ super(map);
+ this.switchPoint = new SwitchPoint();
+ }
+
+ @Override
+ public void propertyAdded(final Property property, final boolean isSelf) {
+ if (isSelf) {
+ invalidateSwitchPoint();
+ }
+ super.propertyAdded(property, isSelf);
+ }
+
+ @Override
+ public void propertyDeleted(final Property property, final boolean isSelf) {
+ if (isSelf) {
+ invalidateSwitchPoint();
+ }
+ super.propertyDeleted(property, isSelf);
+ }
+
+ @Override
+ public void propertyModified(final Property oldProperty, final Property newProperty, final boolean isSelf) {
+ if (isSelf) {
+ invalidateSwitchPoint();
+ }
+ super.propertyModified(oldProperty, newProperty, isSelf);
+ }
+
+ @Override
+ synchronized boolean isValidSharedProtoMap() {
+ return switchPoint != null;
+ }
+
+ @Override
+ synchronized SwitchPoint getSharedProtoSwitchPoint() {
+ return switchPoint;
+ }
+
+ /**
+ * Invalidate the shared prototype switch point if this is a shared prototype map.
+ */
+ synchronized void invalidateSwitchPoint() {
+ if (switchPoint != null) {
+ assert !switchPoint.hasBeenInvalidated();
+ SwitchPoint.invalidateAll(new SwitchPoint[]{ switchPoint });
+ switchPoint = null;
+ }
+ }
+}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Source.java b/nashorn/src/jdk/nashorn/internal/runtime/Source.java
index 1f702ba..b2ffbe6 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Source.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Source.java
@@ -971,7 +971,7 @@
return initLogger(Context.getContextTrusted());
}
- private File dumpFile(final String dir) {
+ private File dumpFile(final File dirFile) {
final URL u = getURL();
final StringBuilder buf = new StringBuilder();
// make it unique by prefixing current date & time
@@ -986,11 +986,17 @@
buf.append(getName());
}
- return new File(dir, buf.toString());
+ return new File(dirFile, buf.toString());
}
void dump(final String dir) {
- final File file = dumpFile(dir);
+ final File dirFile = new File(dir);
+ final File file = dumpFile(dirFile);
+ if (!dirFile.exists() && !dirFile.mkdirs()) {
+ debug("Skipping source dump for " + name);
+ return;
+ }
+
try (final FileOutputStream fos = new FileOutputStream(file)) {
final PrintWriter pw = new PrintWriter(fos);
pw.print(data.toString());
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/StoredScript.java b/nashorn/src/jdk/nashorn/internal/runtime/StoredScript.java
index 66153e2..eea01e7 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/StoredScript.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/StoredScript.java
@@ -77,7 +77,7 @@
return compilationId;
}
- private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller<ScriptEnvironment> installer) {
+ private Map<String, Class<?>> installClasses(final Source source, final CodeInstaller installer) {
final Map<String, Class<?>> installedClasses = new HashMap<>();
final byte[] mainClassBytes = classBytes.get(mainClassName);
final Class<?> mainClass = installer.install(mainClassName, mainClassBytes);
@@ -96,7 +96,7 @@
return installedClasses;
}
- FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller<ScriptEnvironment> installer) {
+ FunctionInitializer installFunction(final RecompilableScriptFunctionData data, final CodeInstaller installer) {
final Map<String, Class<?>> installedClasses = installClasses(data.getSource(), installer);
assert initializers != null;
@@ -124,7 +124,7 @@
* @param installer the installer
* @return main script class
*/
- Class<?> installScript(final Source source, final CodeInstaller<ScriptEnvironment> installer) {
+ Class<?> installScript(final Source source, final CodeInstaller installer) {
final Map<String, Class<?>> installedClasses = installClasses(source, installer);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Timing.java b/nashorn/src/jdk/nashorn/internal/runtime/Timing.java
index e1d464d..d4a5280 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Timing.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Timing.java
@@ -28,12 +28,14 @@
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
+import java.util.function.Function;
import java.util.function.Supplier;
-
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.logging.Loggable;
@@ -156,11 +158,15 @@
}
final class TimeSupplier implements Supplier<String> {
- private final Map<String, Long> timings;
-
- TimeSupplier() {
- timings = new LinkedHashMap<>();
- }
+ private final Map<String, LongAdder> timings = new ConcurrentHashMap<>();
+ private final LinkedBlockingQueue<String> orderedTimingNames = new LinkedBlockingQueue<>();
+ private final Function<String, LongAdder> newTimingCreator = new Function<String, LongAdder>() {
+ @Override
+ public LongAdder apply(final String s) {
+ orderedTimingNames.add(s);
+ return new LongAdder();
+ }
+ };
String[] getStrings() {
final List<String> strs = new ArrayList<>();
@@ -184,26 +190,26 @@
int maxKeyLength = 0;
int maxValueLength = 0;
- for (final Map.Entry<String, Long> entry : timings.entrySet()) {
+ for (final Map.Entry<String, LongAdder> entry : timings.entrySet()) {
maxKeyLength = Math.max(maxKeyLength, entry.getKey().length());
- maxValueLength = Math.max(maxValueLength, toMillisPrint(entry.getValue()).length());
+ maxValueLength = Math.max(maxValueLength, toMillisPrint(entry.getValue().longValue()).length());
}
maxKeyLength++;
final StringBuilder sb = new StringBuilder();
sb.append("Accumulated compilation phase timings:\n\n");
- for (final Map.Entry<String, Long> entry : timings.entrySet()) {
+ for (final String timingName: orderedTimingNames) {
int len;
len = sb.length();
- sb.append(entry.getKey());
+ sb.append(timingName);
len = sb.length() - len;
while (len++ < maxKeyLength) {
sb.append(' ');
}
- final Long duration = entry.getValue();
+ final long duration = timings.get(timingName).longValue();
final String strDuration = toMillisPrint(duration);
len = strDuration.length();
for (int i = 0; i < maxValueLength - len; i++) {
@@ -233,11 +239,7 @@
}
private void accumulateTime(final String module, final long duration) {
- Long accumulatedTime = timings.get(module);
- if (accumulatedTime == null) {
- accumulatedTime = 0L;
- }
- timings.put(module, accumulatedTime + duration);
+ timings.computeIfAbsent(module, newTimingCreator).add(duration);
}
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java b/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java
index 57c7e5f..db26bcd 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Undefined.java
@@ -96,8 +96,12 @@
switch (operator) {
case "new":
- case "call":
- throw lookupTypeError("cant.call.undefined", desc);
+ case "call": {
+ final String name = NashornCallSiteDescriptor.getFunctionDescription(desc);
+ final String msg = name != null? "not.a.function" : "cant.call.undefined";
+ throw typeError(msg, name);
+ }
+
case "callMethod":
throw lookupTypeError("cant.read.property.of.undefined", desc);
// NOTE: we support getElem and setItem as JavaScript doesn't distinguish items from properties. Nashorn itself
@@ -125,7 +129,8 @@
}
private static ECMAException lookupTypeError(final String msg, final CallSiteDescriptor desc) {
- return typeError(msg, desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null);
+ final String name = desc.getNameToken(2);
+ return typeError(msg, name != null && !name.isEmpty()? name : null);
}
private static final MethodHandle GET_METHOD = findOwnMH("get", Object.class, Object.class);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
index 1a9be63..1780e3f 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java
@@ -26,6 +26,7 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -45,7 +46,7 @@
*
*/
public final class WithObject extends Scope {
- private static final MethodHandle WITHEXPRESSIONGUARD = findOwnMH("withExpressionGuard", boolean.class, Object.class, PropertyMap.class, SwitchPoint.class);
+ private static final MethodHandle WITHEXPRESSIONGUARD = findOwnMH("withExpressionGuard", boolean.class, Object.class, PropertyMap.class, SwitchPoint[].class);
private static final MethodHandle WITHEXPRESSIONFILTER = findOwnMH("withFilterExpression", Object.class, Object.class);
private static final MethodHandle WITHSCOPEFILTER = findOwnMH("withFilterScope", Object.class, Object.class);
private static final MethodHandle BIND_TO_EXPRESSION_OBJ = findOwnMH("bindToExpression", Object.class, Object.class, Object.class);
@@ -209,16 +210,18 @@
}
@Override
- protected Object invokeNoSuchProperty(final String name, final int programPoint) {
+ protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
if (find != null) {
final Object func = find.getObjectValue();
if (func instanceof ScriptFunction) {
- return ScriptRuntime.apply((ScriptFunction)func, expression, name);
+ final ScriptFunction sfunc = (ScriptFunction)func;
+ final Object self = isScope && sfunc.isStrict()? UNDEFINED : expression;
+ return ScriptRuntime.apply(sfunc, self, name);
}
}
- return getProto().invokeNoSuchProperty(name, programPoint);
+ return getProto().invokeNoSuchProperty(name, isScope, programPoint);
}
@Override
@@ -352,18 +355,29 @@
}
private static Object bindToExpression(final ScriptFunction fn, final Object receiver) {
- return fn.makeBoundFunction(withFilterExpression(receiver), ScriptRuntime.EMPTY_ARRAY);
+ return fn.createBound(withFilterExpression(receiver), ScriptRuntime.EMPTY_ARRAY);
}
private MethodHandle expressionGuard(final String name, final ScriptObject owner) {
final PropertyMap map = expression.getMap();
- final SwitchPoint sp = expression.getProtoSwitchPoint(name, owner);
+ final SwitchPoint[] sp = expression.getProtoSwitchPoints(name, owner);
return MH.insertArguments(WITHEXPRESSIONGUARD, 1, map, sp);
}
@SuppressWarnings("unused")
- private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint sp) {
- return ((WithObject)receiver).expression.getMap() == map && (sp == null || !sp.hasBeenInvalidated());
+ private static boolean withExpressionGuard(final Object receiver, final PropertyMap map, final SwitchPoint[] sp) {
+ return ((WithObject)receiver).expression.getMap() == map && !hasBeenInvalidated(sp);
+ }
+
+ private static boolean hasBeenInvalidated(final SwitchPoint[] switchPoints) {
+ if (switchPoints != null) {
+ for (final SwitchPoint switchPoint : switchPoints) {
+ if (switchPoint.hasBeenInvalidated()) {
+ return true;
+ }
+ }
+ }
+ return false;
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index db87195..91fa4b3 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -258,7 +258,7 @@
* Factory method for unspecified array - start as int
* @return ArrayData
*/
- public final static ArrayData initialArray() {
+ public static ArrayData initialArray() {
return new IntArrayData();
}
@@ -278,7 +278,7 @@
* @param size size required
* @return size given, always >= size
*/
- protected final static int alignUp(final int size) {
+ protected static int alignUp(final int size) {
return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
}
@@ -288,7 +288,7 @@
* @param length the initial length
* @return ArrayData
*/
- public static final ArrayData allocate(final int length) {
+ public static ArrayData allocate(final int length) {
if (length == 0) {
return new IntArrayData();
} else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
@@ -304,7 +304,7 @@
* @param array the array
* @return ArrayData wrapping this array
*/
- public static final ArrayData allocate(final Object array) {
+ public static ArrayData allocate(final Object array) {
final Class<?> clazz = array.getClass();
if (clazz == int[].class) {
@@ -324,7 +324,7 @@
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static final ArrayData allocate(final int[] array) {
+ public static ArrayData allocate(final int[] array) {
return new IntArrayData(array, array.length);
}
@@ -334,7 +334,7 @@
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static final ArrayData allocate(final long[] array) {
+ public static ArrayData allocate(final long[] array) {
return new LongArrayData(array, array.length);
}
@@ -344,7 +344,7 @@
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static final ArrayData allocate(final double[] array) {
+ public static ArrayData allocate(final double[] array) {
return new NumberArrayData(array, array.length);
}
@@ -354,7 +354,7 @@
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static final ArrayData allocate(final Object[] array) {
+ public static ArrayData allocate(final Object[] array) {
return new ObjectArrayData(array, array.length);
}
@@ -364,7 +364,7 @@
* @param buf the nio ByteBuffer to wrap
* @return the ArrayData
*/
- public static final ArrayData allocate(final ByteBuffer buf) {
+ public static ArrayData allocate(final ByteBuffer buf) {
return new ByteBufferArrayData(buf);
}
@@ -374,7 +374,7 @@
* @param underlying the underlying ArrayData to wrap in the freeze filter
* @return the frozen ArrayData
*/
- public static final ArrayData freeze(final ArrayData underlying) {
+ public static ArrayData freeze(final ArrayData underlying) {
return new FrozenArrayFilter(underlying);
}
@@ -384,7 +384,7 @@
* @param underlying the underlying ArrayData to wrap in the seal filter
* @return the sealed ArrayData
*/
- public static final ArrayData seal(final ArrayData underlying) {
+ public static ArrayData seal(final ArrayData underlying) {
return new SealedArrayFilter(underlying);
}
@@ -394,7 +394,7 @@
* @param underlying the underlying ArrayData to wrap in the non extensible filter
* @return new array data, filtered
*/
- public static final ArrayData preventExtension(final ArrayData underlying) {
+ public static ArrayData preventExtension(final ArrayData underlying) {
return new NonExtensibleArrayFilter(underlying);
}
@@ -404,7 +404,7 @@
* @param underlying the underlying ArrayDAta to wrap in the non extensible filter
* @return new array data, filtered
*/
- public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) {
+ public static ArrayData setIsLengthNotWritable(final ArrayData underlying) {
return new LengthNotWritableFilter(underlying);
}
@@ -676,19 +676,34 @@
}
/**
- * Returns if element at specific index range can be deleted or not.
+ * Returns if element at specific index can be deleted or not.
*
- * @param fromIndex the start index
- * @param toIndex the end index
+ * @param longIndex the index
* @param strict are we in strict mode
*
* @return true if range can be deleted
*/
- public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+ public boolean canDelete(final long longIndex, final boolean strict) {
return true;
}
/**
+ * Delete a range from the array if {@code fromIndex} is less than or equal to {@code toIndex}
+ * and the array supports deletion.
+ *
+ * @param fromIndex the start index (inclusive)
+ * @param toIndex the end index (inclusive)
+ * @param strict are we in strict mode
+ * @return an array with the range deleted, or this array if no deletion took place
+ */
+ public final ArrayData safeDelete(final long fromIndex, final long toIndex, final boolean strict) {
+ if (fromIndex <= toIndex && canDelete(fromIndex, strict)) {
+ return delete(fromIndex, toIndex);
+ }
+ return this;
+ }
+
+ /**
* Returns property descriptor for element at a given index
*
* @param global the global object
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
index 85f1b43..3c17d53 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ByteBufferArrayData.java
@@ -164,7 +164,7 @@
}
@Override
- public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+ public boolean canDelete(final long longIndex, final boolean strict) {
return false;
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
index e892f9f..260dc8e 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
@@ -191,7 +191,7 @@
/**
* Return element setter for a {@link ContinuousArrayData}
- * @param clazz clazz for exact type guard
+ * @param clazz class for exact type guard
* @param setHas set has guard
* @param elementType element type
* @return method handle for element setter
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java
deleted file mode 100644
index 170b65d..0000000
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/InvalidArrayIndexException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-/**
- * Mechanism for communicating that something isn't a plain
- * numeric integer array index. This enables things like
- * array getters for the fast case in a try, basically
- * just consisting of an "array[index]" access without
- * any checks of boundary conditions that rarely happen
- */
-@SuppressWarnings("serial")
-class InvalidArrayIndexException extends Exception {
-
- private final Object index;
-
- InvalidArrayIndexException(final Object index) {
- super(index == null ? "null" : index.toString());
- this.index = index;
- }
-
- InvalidArrayIndexException(final int index) {
- this(Integer.valueOf(index));
- }
-
- InvalidArrayIndexException(final long index) {
- this(Long.valueOf(index));
- }
-
- InvalidArrayIndexException(final double index) {
- this(Double.valueOf(index));
- }
-
- @Override
- public String toString() {
- return index.toString();
- }
-
- Object getIndex() {
- return index;
- }
-
-}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
index 3e78f2d..67efe47 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SealedArrayFilter.java
@@ -50,15 +50,15 @@
@Override
public boolean canDelete(final int index, final boolean strict) {
- if (strict) {
- throw typeError("cant.delete.property", Integer.toString(index), "sealed array");
- }
- return false;
+ return canDelete(ArrayIndex.toLongIndex(index), strict);
}
@Override
- public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
- return canDelete((int) fromIndex, strict);
+ public boolean canDelete(final long longIndex, final boolean strict) {
+ if (strict) {
+ throw typeError("cant.delete.property", Long.toString(longIndex), "sealed array");
+ }
+ return false;
}
@Override
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
index ede8d87..91ad425 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
@@ -36,7 +36,7 @@
* Handle arrays where the index is very large.
*/
class SparseArrayData extends ArrayData {
- static final int MAX_DENSE_LENGTH = 8 * 1024 * 1024;
+ static final int MAX_DENSE_LENGTH = 1024 * 1024;
/** Underlying array. */
private ArrayData underlying;
@@ -166,8 +166,9 @@
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
if (index >= 0 && index < maxDenseLength) {
+ final long oldLength = underlying.length();
ensure(index);
- underlying = underlying.set(index, value, strict);
+ underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
@@ -181,8 +182,9 @@
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
if (index >= 0 && index < maxDenseLength) {
+ final long oldLength = underlying.length();
ensure(index);
- underlying = underlying.set(index, value, strict);
+ underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
@@ -195,8 +197,9 @@
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
if (index >= 0 && index < maxDenseLength) {
+ final long oldLength = underlying.length();
ensure(index);
- underlying = underlying.set(index, value, strict);
+ underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
@@ -209,8 +212,9 @@
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (index >= 0 && index < maxDenseLength) {
+ final long oldLength = underlying.length();
ensure(index);
- underlying = underlying.set(index, value, strict);
+ underlying = underlying.set(index, value, strict).safeDelete(oldLength, index - 1, strict);
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
index 40b3210..56b9157a 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
@@ -83,7 +83,7 @@
}
@Override
- public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+ public boolean canDelete(final long longIndex, final boolean strict) {
return false;
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
index 9865dcb..e4f2a2c 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
@@ -34,7 +34,7 @@
* This filter handles the presence of undefined array elements.
*/
final class UndefinedArrayFilter extends ArrayFilter {
- /** Bit vector tracking undefines. */
+ /** Bit vector tracking undefined slots. */
private final BitVector undefined;
UndefinedArrayFilter(final ArrayData underlying) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/AdaptationException.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/AdaptationException.java
index 3bf3eec..aa29e99 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/AdaptationException.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/AdaptationException.java
@@ -30,6 +30,7 @@
private final AdaptationResult adaptationResult;
AdaptationException(final AdaptationResult.Outcome outcome, final String classList) {
+ super(null, null, false, false);
this.adaptationResult = new AdaptationResult(outcome, classList);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index 9cdf6d5..1d0a166 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -50,7 +50,6 @@
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
-import jdk.nashorn.internal.objects.ScriptFunctionImpl;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.OptimisticReturnFilters;
@@ -70,7 +69,7 @@
private static final MethodHandle VOID_TO_OBJECT = MH.constant(Object.class, ScriptRuntime.UNDEFINED);
/**
- * The default dynalink relink threshold for megamorphisism is 8. In the case
+ * The default dynalink relink threshold for megamorphism is 8. In the case
* of object fields only, it is fine. However, with dual fields, in order to get
* performance on benchmarks with a lot of object instantiation and then field
* reassignment, it can take slightly more relinks to become stable with type
@@ -190,7 +189,7 @@
* @return true if the obj is an instance of @FunctionalInterface interface
*/
public static boolean isFunctionalInterfaceObject(final Object obj) {
- return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
+ return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethodName(obj.getClass()) != null);
}
/**
@@ -214,7 +213,7 @@
* @param type method type
* @param programPoint program point to bind to callsite
*
- * @return callsite for a math instrinic node
+ * @return callsite for a math intrinsic node
*/
public static CallSite mathBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int programPoint) {
final MethodHandle mh;
@@ -397,8 +396,8 @@
* @throws ECMAException with {@code TypeError} if the object is not a callable.
*/
public static Object bindCallable(final Object callable, final Object boundThis, final Object[] boundArgs) {
- if (callable instanceof ScriptFunctionImpl) {
- return ((ScriptFunctionImpl)callable).makeBoundFunction(boundThis, boundArgs);
+ if (callable instanceof ScriptFunction) {
+ return ((ScriptFunction)callable).createBound(boundThis, boundArgs);
} else if (callable instanceof BoundCallable) {
return ((BoundCallable)callable).bind(boundArgs);
} else if (isCallable(callable)) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
index 477d586..3bc1149 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
@@ -99,9 +99,10 @@
return null;
}
- final GuardedInvocation inv;
+ GuardedInvocation inv;
if (jsObjectClass.isInstance(self)) {
inv = lookup(desc, request, linkerServices);
+ inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
} else {
throw new AssertionError(); // Should never reach here.
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index d12bbc8..8fd28cc 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -77,9 +77,10 @@
return null;
}
- final GuardedInvocation inv;
+ GuardedInvocation inv;
if (self instanceof JSObject) {
inv = lookup(desc, request, linkerServices);
+ inv = inv.replaceMethods(linkerServices.filterInternalObjects(inv.getInvocation()), inv.getGuard());
} else if (self instanceof Map || self instanceof Bindings) {
// guard to make sure the Map or Bindings does not turn into JSObject later!
final GuardedInvocation beanInv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
index be7b81a..4bc7b42 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java
@@ -203,6 +203,8 @@
// This is the superclass for our generated adapter.
private final Class<?> superClass;
+ // Interfaces implemented by our generated adapter.
+ private final List<Class<?>> interfaces;
// Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
// loader that has the visibility of all original types (class to extend and interfaces to implement) and of the
// Nashorn classes.
@@ -254,6 +256,7 @@
assert interfaces != null;
this.superClass = superClass;
+ this.interfaces = interfaces;
this.classOverride = classOverride;
this.commonLoader = commonLoader;
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
@@ -571,7 +574,7 @@
mv.visitVarInsn(ALOAD, 0);
if (fromFunction && !mi.getName().equals(samName)) {
// Constructors initializing from a ScriptFunction only initialize methods with the SAM name.
- // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overriden too. This
+ // NOTE: if there's a concrete overloaded method sharing the SAM name, it'll be overridden too. This
// is a deliberate design choice. All other method handles are initialized to null.
mv.visitInsn(ACONST_NULL);
} else {
@@ -1031,6 +1034,24 @@
endMethod(mv);
}
+ // find the appropriate super type to use for invokespecial on the given interface
+ private Class<?> findInvokespecialOwnerFor(final Class<?> cl) {
+ assert Modifier.isInterface(cl.getModifiers()) : cl + " is not an interface";
+
+ if (cl.isAssignableFrom(superClass)) {
+ return superClass;
+ }
+
+ for (final Class<?> iface : interfaces) {
+ if (cl.isAssignableFrom(iface)) {
+ return iface;
+ }
+ }
+
+ // we better that interface that extends the given interface!
+ throw new AssertionError("can't find the class/interface that extends " + cl);
+ }
+
private void emitSuperCall(final InstructionAdapter mv, final Class<?> owner, final String name, final String methodDesc) {
mv.visitVarInsn(ALOAD, 0);
int nextParam = 1;
@@ -1042,7 +1063,9 @@
// default method - non-abstract, interface method
if (Modifier.isInterface(owner.getModifiers())) {
- mv.invokespecial(Type.getInternalName(owner), name, methodDesc, false);
+ // we should call default method on the immediate "super" type - not on (possibly)
+ // the indirectly inherited interface class!
+ mv.invokespecial(Type.getInternalName(findInvokespecialOwnerFor(owner)), name, methodDesc, false);
} else {
mv.invokespecial(superClassName, name, methodDesc, false);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
index 46324db..10dbf01 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
@@ -43,6 +43,7 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.LongAdder;
import jdk.internal.dynalink.ChainedCallSite;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -70,7 +71,7 @@
LinkerCallSite(final NashornCallSiteDescriptor descriptor) {
super(descriptor);
if (Context.DEBUG) {
- LinkerCallSite.count++;
+ LinkerCallSite.count.increment();
}
}
@@ -173,7 +174,7 @@
* @return self reference
*/
public static Object increaseMissCount(final String desc, final Object self) {
- ++missCount;
+ missCount.increment();
if (r.nextInt(100) < missSamplingPercentage) {
final AtomicInteger i = missCounts.get(desc);
if (i == null) {
@@ -500,7 +501,7 @@
* @param desc callsite descriptor string
* @param args arguments to function
*
- * @throws Throwable if invocation failes or throws exception/error
+ * @throws Throwable if invocation fails or throws exception/error
*/
@SuppressWarnings("unused")
public void traceMiss(final String desc, final Object... args) throws Throwable {
@@ -509,12 +510,19 @@
}
// counters updated in debug mode
- private static int count;
+ private static LongAdder count;
private static final HashMap<String, AtomicInteger> missCounts = new HashMap<>();
- private static int missCount;
+ private static LongAdder missCount;
private static final Random r = new Random();
private static final int missSamplingPercentage = Options.getIntProperty("nashorn.tcs.miss.samplePercent", 1);
+ static {
+ if (Context.DEBUG) {
+ count = new LongAdder();
+ missCount = new LongAdder();
+ }
+ }
+
@Override
protected int getMaxChainLength() {
return 8;
@@ -524,16 +532,16 @@
* Get the callsite count
* @return the count
*/
- public static int getCount() {
- return count;
+ public static long getCount() {
+ return count.longValue();
}
/**
* Get the callsite miss count
* @return the missCount
*/
- public static int getMissCount() {
- return missCount;
+ public static long getMissCount() {
+ return missCount.longValue();
}
/**
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
index 5b87965..6b7bce3 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -42,13 +41,11 @@
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodHandleTransformer;
import jdk.internal.dynalink.support.DefaultInternalObjectFilter;
-import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.support.Lookup;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.options.Options;
/**
@@ -79,10 +76,10 @@
}
// cache of @FunctionalInterface method of implementor classes
- private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
+ private static final ClassValue<String> FUNCTIONAL_IFACE_METHOD_NAME = new ClassValue<String>() {
@Override
- protected Method computeValue(final Class<?> type) {
- return findFunctionalInterfaceMethod(type);
+ protected String computeValue(final Class<?> type) {
+ return findFunctionalInterfaceMethodName(type);
}
};
@@ -107,19 +104,21 @@
// annotated interface. This way Java method, constructor references or
// implementations of java.util.function.* interfaces can be called as though
// those are script functions.
- final Method m = getFunctionalInterfaceMethod(self.getClass());
- if (m != null) {
+ final String name = getFunctionalInterfaceMethodName(self.getClass());
+ if (name != null) {
final MethodType callType = desc.getMethodType();
- // 'callee' and 'thiz' passed from script + actual arguments
- if (callType.parameterCount() != m.getParameterCount() + 2) {
- throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
- }
- return new GuardedInvocation(
- // drop 'thiz' passed from the script.
- MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1,
- callType.parameterType(1)), Guards.getInstanceOfGuard(
- m.getDeclaringClass())).asTypeSafeReturn(
- new NashornBeansLinkerServices(linkerServices), callType);
+ // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
+ final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(),
+ "dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2),
+ NashornCallSiteDescriptor.getFlags(desc));
+ final GuardedInvocation gi = getGuardedInvocation(beansLinker,
+ linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
+ new NashornBeansLinkerServices(linkerServices));
+
+ // drop 'thiz' passed from the script.
+ return gi.replaceMethods(
+ MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
+ gi.getGuard());
}
}
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
@@ -163,13 +162,13 @@
return arg instanceof ConsString ? arg.toString() : arg;
}
- private static Method findFunctionalInterfaceMethod(final Class<?> clazz) {
+ private static String findFunctionalInterfaceMethodName(final Class<?> clazz) {
if (clazz == null) {
return null;
}
for (final Class<?> iface : clazz.getInterfaces()) {
- // check accessiblity up-front
+ // check accessibility up-front
if (! Context.isAccessibleClass(iface)) {
continue;
}
@@ -179,20 +178,20 @@
// return the first abstract method
for (final Method m : iface.getMethods()) {
if (Modifier.isAbstract(m.getModifiers())) {
- return m;
+ return m.getName();
}
}
}
}
// did not find here, try super class
- return findFunctionalInterfaceMethod(clazz.getSuperclass());
+ return findFunctionalInterfaceMethodName(clazz.getSuperclass());
}
// Returns @FunctionalInterface annotated interface's single abstract
- // method. If not found, returns null.
- static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
- return FUNCTIONAL_IFACE_METHOD.get(clazz);
+ // method name. If not found, returns null.
+ static String getFunctionalInterfaceMethodName(final Class<?> clazz) {
+ return FUNCTIONAL_IFACE_METHOD_NAME.get(clazz);
}
static MethodHandleTransformer createHiddenObjectFilter() {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
index 5fb9f36..aade455 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
@@ -27,6 +27,8 @@
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED;
+import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
@@ -92,7 +94,7 @@
if(BeansLinker.isDynamicMethod(self)) {
throw typeError("method.not.constructor", ScriptRuntime.safeToString(self));
}
- throw typeError("not.a.function", ScriptRuntime.safeToString(self));
+ throw typeError("not.a.function", desc.getFunctionErrorMessage(self));
case "call":
if(BeansLinker.isDynamicConstructor(self)) {
throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self));
@@ -100,10 +102,12 @@
if(BeansLinker.isDynamicMethod(self)) {
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
}
- throw typeError("not.a.function", ScriptRuntime.safeToString(self));
+ throw typeError("not.a.function", desc.getFunctionErrorMessage(self));
case "callMethod":
- case "getMethod":
throw typeError("no.such.function", getArgument(linkRequest), ScriptRuntime.safeToString(self));
+ case "getMethod":
+ // evaluate to undefined, later on Undefined will take care of throwing TypeError
+ return getInvocation(MH.dropArguments(GET_UNDEFINED.get(TYPE_OBJECT_INDEX), 0, Object.class), self, linkerServices, desc);
case "getProp":
case "getElem":
if(NashornCallSiteDescriptor.isOptimistic(desc)) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
index 27fc3a2..cc654dc 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
@@ -34,6 +34,7 @@
import jdk.internal.dynalink.support.AbstractCallSiteDescriptor;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.ir.debug.NashornTextifier;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}. The reason we have our own subclass is that
@@ -150,7 +151,7 @@
public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name,
final MethodType methodType, final int flags) {
final String[] tokenizedName = CallSiteDescriptorFactory.tokenizeName(name);
- assert tokenizedName.length == 2 || tokenizedName.length == 3;
+ assert tokenizedName.length >= 2;
assert "dyn".equals(tokenizedName[0]);
assert tokenizedName[1] != null;
// TODO: see if we can move mangling/unmangling into Dynalink
@@ -248,6 +249,54 @@
}
/**
+ * If this is a dyn:call or dyn:new, this returns function description from callsite.
+ * Caller has to make sure this is a dyn:call or dyn:new call site.
+ *
+ * @return function description if available (or null)
+ */
+ public String getFunctionDescription() {
+ assert getFirstOperator().equals("call") || getFirstOperator().equals("new");
+ return getNameTokenCount() > 2? getNameToken(2) : null;
+ }
+
+ /**
+ * If this is a dyn:call or dyn:new, this returns function description from callsite.
+ * Caller has to make sure this is a dyn:call or dyn:new call site.
+ *
+ * @param desc call site descriptor
+ * @return function description if available (or null)
+ */
+ public static String getFunctionDescription(final CallSiteDescriptor desc) {
+ return desc instanceof NashornCallSiteDescriptor ?
+ ((NashornCallSiteDescriptor)desc).getFunctionDescription() : null;
+ }
+
+
+ /**
+ * Returns the error message to be used when dyn:call or dyn:new is used on a non-function.
+ *
+ * @param obj object on which dyn:call or dyn:new is used
+ * @return error message
+ */
+ public String getFunctionErrorMessage(final Object obj) {
+ final String funcDesc = getFunctionDescription();
+ return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj);
+ }
+
+ /**
+ * Returns the error message to be used when dyn:call or dyn:new is used on a non-function.
+ *
+ * @param desc call site descriptor
+ * @param obj object on which dyn:call or dyn:new is used
+ * @return error message
+ */
+ public static String getFunctionErrorMessage(final CallSiteDescriptor desc, final Object obj) {
+ return desc instanceof NashornCallSiteDescriptor ?
+ ((NashornCallSiteDescriptor)desc).getFunctionErrorMessage(obj) :
+ ScriptRuntime.safeToString(obj);
+ }
+
+ /**
* Returns the Nashorn-specific flags for this call site descriptor.
* @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
* {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
@@ -274,7 +323,7 @@
* {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
* generated outside of Nashorn.
* @param flag the tested flag
- * @return true if the flag is set, false otherwise (it will be false if the decriptor is not a Nashorn call site
+ * @return true if the flag is set, false otherwise (it will be false if the descriptor is not a Nashorn call site
* descriptor).
*/
private static boolean isFlag(final CallSiteDescriptor desc, final int flag) {
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java b/nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
index 084f765..99936c5 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/logging/DebugLogger.java
@@ -99,10 +99,10 @@
final StringBuilder sb = new StringBuilder();
sb.append('[')
- .append(record.getLoggerName())
- .append("] ")
- .append(record.getMessage())
- .append('\n');
+ .append(record.getLoggerName())
+ .append("] ")
+ .append(record.getMessage())
+ .append('\n');
return sb.toString();
}
@@ -194,7 +194,7 @@
*/
public void indent(final int pos) {
if (isEnabled) {
- indent += pos * INDENT_SPACE;
+ indent += pos * INDENT_SPACE;
}
}
@@ -227,57 +227,14 @@
}
/**
- * Check if the logger is above the level of detail given
+ * Check if the event of given level will be logged.
* @see java.util.logging.Level
*
- * The higher the level, the more severe the warning
- *
* @param level logging level
- * @return true if level is above the given one
+ * @return true if event of given level will be logged.
*/
- public boolean levelCoarserThan(final Level level) {
- return getLevel().intValue() > level.intValue();
- }
-
- /**
- * Check if the logger is above or equal to the level
- * of detail given
- * @see java.util.logging.Level
- *
- * The higher the level, the more severe the warning
- *
- * @param level logging level
- * @return true if level is above the given one
- */
- public boolean levelCoarserThanOrEqual(final Level level) {
- return getLevel().intValue() >= level.intValue();
- }
-
- /**
- * Check if the logger is below the level of detail given
- * @see java.util.logging.Level
- *
- * The higher the level, the more severe the warning
- *
- * @param level logging level
- * @return true if level is above the given one
- */
- public boolean levelFinerThan(final Level level) {
- return getLevel().intValue() < level.intValue();
- }
-
- /**
- * Check if the logger is below or equal to the level
- * of detail given
- * @see java.util.logging.Level
- *
- * The higher the level, the more severe the warning
- *
- * @param level logging level
- * @return true if level is above the given one
- */
- public boolean levelFinerThanOrEqual(final Level level) {
- return getLevel().intValue() <= level.intValue();
+ public boolean isLoggable(final Level level) {
+ return logger.isLoggable(level);
}
/**
@@ -566,7 +523,7 @@
* @param str string to log
*/
public void log(final Level level, final String str) {
- if (isEnabled && !isQuiet) {
+ if (isEnabled && !isQuiet && logger.isLoggable(level)) {
final StringBuilder sb = new StringBuilder();
for (int i = 0 ; i < indent ; i++) {
sb.append(' ');
@@ -584,7 +541,7 @@
* @param objs objects for which to invoke toString and concatenate to log
*/
public void log(final Level level, final Object... objs) {
- if (isEnabled && !isQuiet) {
+ if (isEnabled && !isQuiet && logger.isLoggable(level)) {
final StringBuilder sb = new StringBuilder();
for (final Object obj : objs) {
sb.append(obj);
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java b/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
index b6790aa..2fae703 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/OptionTemplate.java
@@ -163,7 +163,7 @@
/**
* Does this option automatically enable another option, i.e. a dependency.
- * @return the dependecy or null if non exists
+ * @return the dependency or null if none exists
*/
public String getDependency() {
return this.dependency;
@@ -304,8 +304,8 @@
}
}
- boolean matches(final String key0) {
- return key0.equals(this.shortName) || key0.equals(this.name);
+ boolean nameMatches(final String aName) {
+ return aName.equals(this.shortName) || aName.equals(this.name);
}
private static final int LINE_BREAK = 64;
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java
index bcaffba..f85c4f2 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java
@@ -519,9 +519,25 @@
}
}
- private static OptionTemplate getOptionTemplate(final String key) {
+ /**
+ * Retrieves an option template identified by key.
+ * @param shortKey the short (that is without the e.g. "nashorn.option." part) key
+ * @return the option template identified by the key
+ * @throws IllegalArgumentException if the key doesn't specify an existing template
+ */
+ public OptionTemplate getOptionTemplateByKey(final String shortKey) {
+ final String fullKey = key(shortKey);
+ for(final OptionTemplate t: validOptions) {
+ if(t.getKey().equals(fullKey)) {
+ return t;
+ }
+ }
+ throw new IllegalArgumentException(shortKey);
+ }
+
+ private static OptionTemplate getOptionTemplateByName(final String name) {
for (final OptionTemplate t : Options.validOptions) {
- if (t.matches(key)) {
+ if (t.nameMatches(name)) {
return t;
}
}
@@ -681,7 +697,7 @@
}
final String token = st.nextToken();
- this.template = Options.getOptionTemplate(token);
+ this.template = getOptionTemplateByName(token);
if (this.template == null) {
throw new IllegalArgumentException(argument);
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
index e55947c..6590053 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/Config.java
@@ -65,7 +65,7 @@
final boolean DONT_OPTIMIZE = false;
- final boolean USE_STRING_TEMPLATES = true; // use embeded string templates in Regex object as byte arrays instead of compiling them into int bytecode array
+ final boolean USE_STRING_TEMPLATES = true; // use embedded string templates in Regex object as byte arrays instead of compiling them into int bytecode array
final boolean NON_UNICODE_SDW = true;
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java
index 537bf0f..a3892c7 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java
+++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/joni/exception/JOniException.java
@@ -24,6 +24,6 @@
private static final long serialVersionUID = -6027192180014164667L;
public JOniException(final String message) {
- super(message);
+ super(message, null, false, false);
}
}
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
index 9bb5dd8..003887c 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 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
@@ -31,6 +31,7 @@
lexer.error.json.invalid.number=Invalid JSON number format
lexer.error.invalid.escape.char=Invalid escape character
lexer.error.illegal.identifier.character=Illegal character in identifier
+lexer.error.here.non.matching.delimiter=Quoted here string end marker must have matching delimiters
parser.error.illegal.continue.stmt=Illegal continue statement
parser.error.illegal.break.stmt=Illegal break statement
@@ -78,6 +79,7 @@
type.error.not.a.regexp={0} is not a RegExp
type.error.not.a.string={0} is not a String
type.error.not.a.function={0} is not a function
+type.error.not.a.function.value={0}, which has value {1}, is not a function
type.error.not.a.constructor={0} is not a constructor function
type.error.not.a.file={0} is not a File
type.error.not.a.numeric.array={0} is not a numeric array
@@ -148,6 +150,7 @@
type.error.method.not.constructor=Java method {0} cannot be used as a constructor.
type.error.env.not.object=$ENV must be an Object.
type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
+type.error.java.array.conversion.failed=Java.to conversion to array type {0} failed
type.error.constructor.requires.new=Constructor {0} requires "new".
type.error.new.on.nonpublic.javatype=new cannot be used with non-public java type {0}.
@@ -161,6 +164,7 @@
range.error.invalid.date=Invalid Date
range.error.too.many.errors=Script contains too many errors: {0} errors
range.error.concat.string.too.big=Concatenated String is too big
+range.error.exec.returned.non.zero=$EXEC returned non-zero exit code: {0}
reference.error.not.defined="{0}" is not defined
reference.error.cant.be.used.as.lhs="{0}" can not be used as the left-hand side of assignment
@@ -171,7 +175,9 @@
syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
io.error.cant.write=cannot write "{0}"
+
config.error.no.dest=no destination directory supplied
+config.error.eagerCompilationConflictsWithOptimisticTypes={0}=false (eager compilation) is not compatible with {1}=true.
uri.error.bad.uri=Bad URI "{0}" near offset {1}
list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context.
diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js b/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js
index 8671d36..94d02ab 100644
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/parser.js
@@ -55,7 +55,7 @@
// do not start with '/'. If regexp, then eval it to make RegExp object
return value.startsWith('/')? eval(value) : value.substring(1);
} else {
- // anythin else is returned "as is""
+ // anything else is returned "as is"
return value;
}
});
diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java
index f8747b2..9ee02af 100644
--- a/nashorn/src/jdk/nashorn/tools/Shell.java
+++ b/nashorn/src/jdk/nashorn/tools/Shell.java
@@ -54,7 +54,6 @@
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options;
/**
@@ -255,12 +254,9 @@
return COMPILATION_ERROR;
}
- new Compiler(
+ Compiler.forNoInstallerCompilation(
context,
- env,
- null, //null - pass no code installer - this is compile only
functionNode.getSource(),
- context.getErrorManager(),
env._strict | functionNode.isStrict()).
compile(functionNode, CompilationPhases.COMPILE_ALL_NO_INSTALL);
diff --git a/nashorn/test/script/basic/JDK-8026016.js.EXPECTED b/nashorn/test/script/basic/JDK-8026016.js.EXPECTED
index a2d2383..8d95d91 100644
--- a/nashorn/test/script/basic/JDK-8026016.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8026016.js.EXPECTED
@@ -1,182 +1,182 @@
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-TypeError: Cannot call undefined
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such method _,0
-no such method _,1
-no such method _,2
-no such method _,3
-no such method _,4
-no such method _,5
-no such method _,6
-no such method _,7
-no such method _,8
-no such method _,9
-no such method _,10
-no such method _,11
-no such method _,12
-no such method _,13
-no such method _,14
-no such method _,15
-no such method _,16
-no such method _,17
-no such method _,18
-no such method _,19
-no such method _,20
-no such method _,21
-no such method _,22
-no such method _,23
-no such method _,24
-no such method _,25
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-TypeError: Cannot call undefined
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
-no such property _
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+TypeError: o._ is not a function
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such method _,0
+no such method _,1
+no such method _,2
+no such method _,3
+no such method _,4
+no such method _,5
+no such method _,6
+no such method _,7
+no such method _,8
+no such method _,9
+no such method _,10
+no such method _,11
+no such method _,12
+no such method _,13
+no such method _,14
+no such method _,15
+no such method _,16
+no such method _,17
+no such method _,18
+no such method _,19
+no such method _,20
+no such method _,21
+no such method _,22
+no such method _,23
+no such method _,24
+no such method _,25
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+TypeError: o._ is not a function
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
+no such property _
diff --git a/nashorn/test/script/basic/JDK-8043232.js b/nashorn/test/script/basic/JDK-8043232.js
index fa46b41..d1f3d85 100644
--- a/nashorn/test/script/basic/JDK-8043232.js
+++ b/nashorn/test/script/basic/JDK-8043232.js
@@ -29,14 +29,14 @@
*/
// call explicit constructor
-print(new (java.awt["Color(int,int,int)"])(255,0,255));
+print(new (java.lang["String(char[],int,int)"])(['a','b', 'c', 'd'], 1, 3));
// print the constructor itself
-print(java.awt["Color(int,int,int)"]);
+print(java.lang["String(char[],int,int)"]);
// store constructor to call later
-var Color = java.awt["Color(int,int,int)"];
+var Color = java.lang["String(char[],int,int)"];
// call stored constructor
-print(new Color(33, 233, 2))
+print(new Color(['r','r', 'e', 'd'], 1, 3))
// check if default constructor works
var obj = new (java.lang["Object()"])();
diff --git a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED
index 03382ea..43d23eb 100644
--- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED
@@ -1,14 +1,28 @@
-java.awt.Color[r=255,g=0,b=255]
-[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)]
-java.awt.Color[r=33,g=233,b=2]
+bcd
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
+red
TypeError: No such Java class: java.lang.NonExistent
TypeError: No such Java constructor: Object(String)
TypeError: Java constructor signature invalid: Object()xxxxx
TypeError: Java constructor signature invalid: Object(
TypeError: Java constructor signature invalid: Object)
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor.
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor.
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new".
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ String java.lang.System.getProperty(String,String)
+ String java.lang.System.getProperty(String)
+] cannot be used as a constructor.
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+] cannot be used as a constructor.
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
TypeError: No such Java constructor: Runnable()
TypeError: No such Java constructor: Runnable(int)
java.lang.InstantiationException: java.io.InputStream
diff --git a/nashorn/test/script/basic/JDK-8044750.js b/nashorn/test/script/basic/JDK-8044750.js
index b084d57..0123fb8 100644
--- a/nashorn/test/script/basic/JDK-8044750.js
+++ b/nashorn/test/script/basic/JDK-8044750.js
@@ -25,6 +25,8 @@
* JDK-8044750: megamorphic getter for scope objects does not call __noSuchProperty__ hook
*
* @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
* @run
*/
@@ -40,7 +42,9 @@
}
}
-for (var i = 0; i < 20; i++) {
+var LIMIT = 20; // should be more than megamorphic threshold set via @option
+
+for (var i = 0; i < LIMIT; i++) {
var obj = {};
obj.foo = i;
obj[i] = i;
@@ -51,3 +55,30 @@
// callsite inside func should see __noSuchProperty__
// hook on global scope object.
func({});
+
+function checkFoo() {
+ with({}) {
+ try {
+ foo;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+}
+
+var oldNoSuchProperty = this.__noSuchProperty__;
+delete this.__noSuchProperty__;
+
+// keep deleting/restorting __noSuchProperty__ alternatively
+// to make "foo" access in checkFoo function megamorphic!
+
+for (var i = 0; i < LIMIT; i++) {
+ // no __noSuchProperty__ and 'with' scope object has no 'foo'
+ delete __noSuchProperty__;
+ Assert.assertFalse(checkFoo(), "Expected false in iteration " + i);
+
+ // __noSuchProperty__ is exists but 'with' scope object has no 'foo'
+ this.__noSuchProperty__ = oldNoSuchProperty;
+ Assert.assertTrue(checkFoo(), "Expected true in iteration " + i);
+}
diff --git a/nashorn/test/script/basic/JDK-8049086.js b/nashorn/test/script/basic/JDK-8049086.js
index da4a962..7dd7ac4 100644
--- a/nashorn/test/script/basic/JDK-8049086.js
+++ b/nashorn/test/script/basic/JDK-8049086.js
@@ -58,7 +58,7 @@
// (a) Java methods (b) Java classes (as these respond to new)
// (c) FunctionalInterface objects (d) JSObjects that are 'functions'
-print("java.awt.Color is java function? " + Java.isJavaFunction(java.awt.Color));
+print("java.lang.String is java function? " + Java.isJavaFunction(java.lang.String));
print("java.lang.Runnable instance is java function? "
+ Java.isJavaFunction(new java.lang.Runnable(function() {})));
print("eval is java function? " + Java.isJavaFunction(eval));
diff --git a/nashorn/test/script/basic/JDK-8049086.js.EXPECTED b/nashorn/test/script/basic/JDK-8049086.js.EXPECTED
index d67db5d..e868572 100644
--- a/nashorn/test/script/basic/JDK-8049086.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8049086.js.EXPECTED
@@ -13,7 +13,7 @@
Object is script object? true
{} is script object? true
/foo/ is script object? true
-java.awt.Color is java function? true
+java.lang.String is java function? true
java.lang.Runnable instance is java function? true
eval is java function? false
println is java function? true
diff --git a/nashorn/test/script/basic/JDK-8049242.js b/nashorn/test/script/basic/JDK-8049242.js
index 3e803b3..c44e330 100644
--- a/nashorn/test/script/basic/JDK-8049242.js
+++ b/nashorn/test/script/basic/JDK-8049242.js
@@ -29,14 +29,14 @@
*/
// call explicit constructor
-print(new (Java.type("java.awt.Color")["(int,int,int)"])(255,0,255));
+print(new (Java.type("java.lang.String")["(char[],int,int)"])(['a', 'b', 'c'],0, 3));
// print the constructor itself
-print(Java.type("java.awt.Color")["(int,int,int)"]);
+print(Java.type("java.lang.String")["(char[],int,int)"]);
// store constructor to call later
-var Color = Java.type("java.awt.Color")["(int,int,int)"];
+var Color = Java.type("java.lang.String")["(char[],int,int)"];
// call stored constructor
-print(new Color(33, 233, 2))
+print(new Color(['j', 'a', 'v', 'a'], 1, 3))
// check if default constructor works
var obj = new (Java.type("java.lang.Object")["()"])();
diff --git a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED
index 4a2f416..f54d15b 100644
--- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED
@@ -1,10 +1,10 @@
-java.awt.Color[r=255,g=0,b=255]
-[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)]
-java.awt.Color[r=33,g=233,b=2]
+abc
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
+ava
TypeError: null is not a function
TypeError: null is not a function
TypeError: null is not a function
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires "new".
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
TypeError: null is not a function
TypeError: null is not a function
java.lang.InstantiationException: java.io.InputStream
diff --git a/nashorn/test/script/basic/JDK-8053905.js b/nashorn/test/script/basic/JDK-8053905.js
index aa6c9db..9d47c97 100644
--- a/nashorn/test/script/basic/JDK-8053905.js
+++ b/nashorn/test/script/basic/JDK-8053905.js
@@ -28,6 +28,7 @@
* @runif external.octane
* @fork
* @option -Dnashorn.compiler.splitter.threshold=1000
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
* @option -scripting
* @option --lazy-compilation=false
*/
diff --git a/nashorn/test/script/basic/JDK-8058561.js b/nashorn/test/script/basic/JDK-8058561.js
index f27d1d1..9f8f910 100644
--- a/nashorn/test/script/basic/JDK-8058561.js
+++ b/nashorn/test/script/basic/JDK-8058561.js
@@ -26,7 +26,9 @@
*
* @test
* @run
+ * @fork
* @option --lazy-compilation=false
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
*/
// Just attempting to compile this caused the NPE
diff --git a/nashorn/test/script/basic/JDK-8068901.js b/nashorn/test/script/basic/JDK-8068901.js
new file mode 100644
index 0000000..0c24eef
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8068901.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8068901: Surprising behavior with more than one functional interface on a class
+ *
+ * @test
+ * @run
+ */
+
+var Consumer = java.util.function.Consumer;
+var JFunction = java.util.function.Function;
+
+var fc = new (Java.extend(JFunction, Consumer))({
+ apply: function(x) { print("fc invoked as a function") },
+ accept: function(x) { print("fc invoked as a consumer") }
+});
+
+var c = new Consumer(function(x) { print("c invoked as a consumer") });
+
+var cf = new (Java.extend(Consumer, JFunction))({
+ apply: function(x) { print("cf invoked as a function") },
+ accept: function(x) { print("cf invoked as a consumer") }
+});
+
+var f = new JFunction(function(x) { print("f invoked as a function") });
+
+for each(x in [fc, c, fc, cf, f, cf, c, fc, f, cf]) { x(null); }
+
diff --git a/nashorn/test/script/basic/JDK-8068901.js.EXPECTED b/nashorn/test/script/basic/JDK-8068901.js.EXPECTED
new file mode 100644
index 0000000..edf7ff1
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8068901.js.EXPECTED
@@ -0,0 +1,10 @@
+fc invoked as a function
+c invoked as a consumer
+fc invoked as a function
+cf invoked as a consumer
+f invoked as a function
+cf invoked as a consumer
+c invoked as a consumer
+fc invoked as a function
+f invoked as a function
+cf invoked as a consumer
diff --git a/nashorn/test/script/basic/JDK-8068903.js b/nashorn/test/script/basic/JDK-8068903.js
new file mode 100644
index 0000000..8209bbb
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8068903.js
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8068903: Can't invoke vararg @FunctionalInterface methods
+ *
+ * @test
+ * @run
+ */
+
+var vc = new (Java.type("jdk.nashorn.test.models.VarArgConsumer"))(
+ function(x) {
+ Assert.assertTrue(x.length == 3);
+ Assert.assertTrue(x[0] == 1);
+ Assert.assertTrue(x[1] == 2);
+ Assert.assertTrue(x[2] == 3);
+ }
+);
+
+vc(1, 2, 3);
diff --git a/nashorn/test/script/basic/JDK-8073733.js b/nashorn/test/script/basic/JDK-8073733.js
new file mode 100644
index 0000000..0d5077e2
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8073733.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8073733: TypeError messages with "call" and "new" could be improved
+ *
+ * @test
+ * @run
+ */
+
+var func = undefined;
+try {
+ func();
+} catch (e) {
+ print(e);
+}
+
+var obj = {};
+try {
+ obj.foo();
+} catch (e) {
+ print(e);
+}
+
+try {
+ new func();
+} catch (e) {
+ print(e);
+}
diff --git a/nashorn/test/script/basic/JDK-8073733.js.EXPECTED b/nashorn/test/script/basic/JDK-8073733.js.EXPECTED
new file mode 100644
index 0000000..22c8982
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8073733.js.EXPECTED
@@ -0,0 +1,3 @@
+TypeError: func is not a function
+TypeError: obj.foo is not a function
+TypeError: func is not a function
diff --git a/nashorn/test/script/basic/JDK-8078612_eager_1a.js b/nashorn/test/script/basic/JDK-8078612_eager_1a.js
index 11d00c6..1ff5a65 100644
--- a/nashorn/test/script/basic/JDK-8078612_eager_1a.js
+++ b/nashorn/test/script/basic/JDK-8078612_eager_1a.js
@@ -29,6 +29,7 @@
* @option -pcc
* @option --lazy-compilation=false
* @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
* @fork
*/
diff --git a/nashorn/test/script/basic/JDK-8078612_eager_1b.js b/nashorn/test/script/basic/JDK-8078612_eager_1b.js
index 11d00c6..1ff5a65 100644
--- a/nashorn/test/script/basic/JDK-8078612_eager_1b.js
+++ b/nashorn/test/script/basic/JDK-8078612_eager_1b.js
@@ -29,6 +29,7 @@
* @option -pcc
* @option --lazy-compilation=false
* @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
* @fork
*/
diff --git a/nashorn/test/script/basic/JDK-8078612_eager_2a.js b/nashorn/test/script/basic/JDK-8078612_eager_2a.js
index 4904d8e..5915efc 100644
--- a/nashorn/test/script/basic/JDK-8078612_eager_2a.js
+++ b/nashorn/test/script/basic/JDK-8078612_eager_2a.js
@@ -29,6 +29,7 @@
* @option -pcc
* @option --lazy-compilation=false
* @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
* @fork
*/
diff --git a/nashorn/test/script/basic/JDK-8078612_eager_2b.js b/nashorn/test/script/basic/JDK-8078612_eager_2b.js
index 4904d8e..5915efc 100644
--- a/nashorn/test/script/basic/JDK-8078612_eager_2b.js
+++ b/nashorn/test/script/basic/JDK-8078612_eager_2b.js
@@ -29,6 +29,7 @@
* @option -pcc
* @option --lazy-compilation=false
* @option -Dnashorn.persistent.code.cache=build/nashorn_code_cache
+ * @option -Dnashorn.options.allowEagerCompilationSilentOverride
* @fork
*/
diff --git a/nashorn/test/script/basic/JDK-8079470.js.EXPECTED b/nashorn/test/script/basic/JDK-8079470.js.EXPECTED
index 65707f5..8be1c42 100644
--- a/nashorn/test/script/basic/JDK-8079470.js.EXPECTED
+++ b/nashorn/test/script/basic/JDK-8079470.js.EXPECTED
@@ -1,2 +1,2 @@
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod File java.io.File.java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
diff --git a/nashorn/test/script/basic/JDK-8087312.js b/nashorn/test/script/basic/JDK-8087312.js
new file mode 100644
index 0000000..e009660
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8087312.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * JDK-8087312: PropertyMapWrapper.equals should compare className
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.debug=true
+ */
+
+function createObject(type) {
+ // we want to make sure two different object literals with the same keys and types share the same property map.
+ if (type) {
+ return {
+ a: "a",
+ b: 1,
+ c: 0.1
+ }
+ } else {
+ return {
+ a: "x",
+ b: 10,
+ c: 3.4
+ }
+ }
+}
+
+var o1 = createObject(false);
+var o2 = createObject(true);
+Assert.assertTrue(Debug.map(o1) === Debug.map(o2));
+
diff --git a/nashorn/test/script/basic/JDK-8114838.js b/nashorn/test/script/basic/JDK-8114838.js
new file mode 100644
index 0000000..7a2420a
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8114838.js
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8114838: Anonymous functions escape to surrounding scope when defined under "with" statement
+ *
+ * @test
+ * @run
+ */
+
+// do *not* introduce new lines! The next line should be 32
+with({}) { function () {} }
+if (typeof this["L:32"] != 'undefined') {
+ throw new Error("anonymous name spills into global scope");
+}
+
+var func = eval("function() {}");
+if (typeof func != 'function') {
+ throw new Error("eval of anonymous function does not work!");
+}
+
+var ScriptEngineManager = Java.type("javax.script.ScriptEngineManager");
+var engine = new ScriptEngineManager().getEngineByName("nashorn");
+var func2 = engine.eval("function() {}");
+if (typeof func2 != 'function') {
+ throw new Error("eval of anonymous function does not work from script engine!");
+}
diff --git a/nashorn/test/script/basic/JDK-8130853.js b/nashorn/test/script/basic/JDK-8130853.js
new file mode 100644
index 0000000..872cf72
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8130853.js
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8130853: Non-extensible global is not handled property
+ *
+ * @test
+ * @run
+ */
+
+// don't allow extensions to global
+Object.preventExtensions(this);
+try {
+ eval("var x = 34;");
+ throw new Error("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ throw e;
+ }
+}
+
+try {
+ eval("function func() {}");
+ throw new Error("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ throw e;
+ }
+}
+
+function checkLoad(code) {
+ try {
+ load({ name: "test", script: code });
+ throw new Error("should have thrown TypeError for load: " + code);
+ } catch (e) {
+ if (! (e instanceof TypeError)) {
+ throw e;
+ }
+ }
+}
+
+checkLoad("var y = 55");
+checkLoad("function f() {}");
+
+// check script engine eval
+var ScriptEngineManager = Java.type("javax.script.ScriptEngineManager");
+var e = new ScriptEngineManager().getEngineByName("nashorn");
+var global = e.eval("this");
+e.eval("Object.preventExtensions(this);");
+try {
+ e.eval("var myVar = 33;");
+ throw new Error("should have thrown TypeError");
+} catch (e) {
+ if (! (e.cause.ecmaError instanceof global.TypeError)) {
+ throw e;
+ }
+}
+
+// Object.bindProperties on arbitrary non-extensible object
+var obj = {};
+Object.preventExtensions(obj);
+try {
+ Object.bindProperties(obj, { foo: 434 });
+ throw new Error("should have thrown TypeError");
+} catch (e) {
+ if (! (e instanceof TypeError)) {
+ throw e;
+ }
+}
diff --git a/nashorn/test/script/basic/JDK-8131039.js b/nashorn/test/script/basic/JDK-8131039.js
new file mode 100644
index 0000000..9bcd13f
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8131039.js
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8131039: after adding a function property to Object.prototype, JSON.parse with reviver function goes into infinite loop
+ *
+ * @test
+ * @run
+ */
+
+Object.prototype.func = function() {}
+
+function identity(k, v) { return v };
+var obj = JSON.parse('{\"name\" : \"nashorn\"}', identity);
+Assert.assertTrue(obj.name, "nashorn");
diff --git a/nashorn/test/script/basic/JDK-8131340.js b/nashorn/test/script/basic/JDK-8131340.js
new file mode 100644
index 0000000..bcdd749
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8131340.js
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8131340: Varargs function is recompiled each time it is linked
+ *
+ * @test
+ * @run
+ */
+
+// This is an indirect test. If repeated calls were to cause recompilation
+// this would trigger an assertion in RecompilableScriptFunctionData.
+
+function varargs() {
+ return arguments;
+}
+
+varargs(1);
+varargs(2);
+varargs(3);
+varargs(4);
+varargs(5);
+varargs(6);
diff --git a/nashorn/test/script/basic/JDK-8131683.js b/nashorn/test/script/basic/JDK-8131683.js
new file mode 100644
index 0000000..3159662
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8131683.js
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8131683: Delete fails over multiple scopes
+ *
+ * @test
+ * @run
+ */
+
+a = 1;
+b = 2;
+c = 3;
+
+var A = 1;
+var B = 2;
+var C = 3;
+function D() {}
+
+print((function() {
+ var x; // force creation of scope
+ (function() { x; })();
+ return delete a;
+})());
+
+print((function() {
+ eval("");
+ return delete b;
+})());
+
+print((function() {
+ return eval("delete c");
+})());
+
+print((function() {
+ eval("d = 4");
+ return eval("delete d");
+})());
+
+print(typeof a);
+print(typeof b);
+print(typeof c);
+print(typeof d);
+
+print((function() {
+ var x; // force creation of scope
+ (function() { x; })();
+ return delete A;
+})());
+
+print((function() {
+ eval("");
+ return delete B;
+})());
+
+print((function() {
+ return eval("delete C");
+})());
+
+print((function() {
+ eval("");
+ return delete D;
+})());
+
+print(typeof A);
+print(typeof B);
+print(typeof C);
+print(typeof D);
+
diff --git a/nashorn/test/script/basic/JDK-8131683.js.EXPECTED b/nashorn/test/script/basic/JDK-8131683.js.EXPECTED
new file mode 100644
index 0000000..d1fbed7
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8131683.js.EXPECTED
@@ -0,0 +1,16 @@
+true
+true
+true
+true
+undefined
+undefined
+undefined
+undefined
+false
+false
+false
+false
+number
+number
+number
+function
diff --git a/nashorn/test/script/basic/JDK-8133119.js b/nashorn/test/script/basic/JDK-8133119.js
new file mode 100644
index 0000000..4a0e5a5
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8133119.js
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8133119: Error message associated with TypeError for call and new should include stringified Node
+ *
+ * @test
+ * @run
+ */
+
+var obj = {}
+try {
+ obj.func();
+} catch (e) {
+ print(e);
+}
+
+var arr = [33];
+try {
+ arr[0].func();
+} catch (e) {
+ print(e);
+}
+
+try {
+ new obj.func();
+} catch (e) {
+ print(e);
+}
+
+try {
+ new arr[0].func();
+} catch (e) {
+ print(e);
+}
+
+obj.foo = {}
+try {
+ new obj.foo();
+} catch (e) {
+ print(e);
+}
+
+try {
+ obj.foo();
+} catch (e) {
+ print(e);
+}
+
+var v = new java.util.Vector();
+try {
+ v();
+} catch (e) {
+ print(e);
+}
+
+try {
+ new v();
+} catch (e) {
+ print(e);
+}
diff --git a/nashorn/test/script/basic/JDK-8133119.js.EXPECTED b/nashorn/test/script/basic/JDK-8133119.js.EXPECTED
new file mode 100644
index 0000000..84eb39c
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8133119.js.EXPECTED
@@ -0,0 +1,8 @@
+TypeError: obj.func is not a function
+TypeError: arr[0].func is not a function
+TypeError: obj.func is not a function
+TypeError: arr[0].func is not a function
+TypeError: obj.foo is not a function
+TypeError: obj.foo is not a function
+TypeError: v is not a function
+TypeError: v is not a function
diff --git a/nashorn/test/script/basic/JDK-8134488.js b/nashorn/test/script/basic/JDK-8134488.js
new file mode 100644
index 0000000..928961a
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134488.js
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134488: var statement in if(false) block incorrectly evacuated into enclosing function
+ *
+ * @test
+ * @run
+ */
+
+var x = "string";
+print(x);
+
+(function f1() {
+ (function f2() {
+ // If it finds both 'print' and 'x', it'll print 'string'.
+ print(x);
+ })();
+
+ if (false) {
+ (function f3() {
+ var x;
+ })();
+ }
+
+})();
diff --git a/nashorn/test/script/basic/JDK-8134488.js.EXPECTED b/nashorn/test/script/basic/JDK-8134488.js.EXPECTED
new file mode 100644
index 0000000..b0cb3a7
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134488.js.EXPECTED
@@ -0,0 +1,2 @@
+string
+string
diff --git a/nashorn/test/script/basic/JDK-8134490.js b/nashorn/test/script/basic/JDK-8134490.js
new file mode 100644
index 0000000..d7c10fd
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134490.js
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134490: Dead var statement evacuation incorrectly descends into nested functions
+ *
+ * @test
+ * @run
+ */
+
+var v1;
+
+function f1()
+{
+v1 = 1;
+return true;
+(function () { var v1; })();
+}
+
+f1();
+// If it executes without throwing an exception in code generator, it's working.
diff --git a/nashorn/test/script/basic/JDK-8134569.js b/nashorn/test/script/basic/JDK-8134569.js
new file mode 100644
index 0000000..7963779
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134569.js
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134569: Add tests for prototype callsites
+ *
+ * @test
+ * @run
+ */
+
+function create() {
+ function C() {
+ this.i1 = 1;
+ this.i2 = 2;
+ this.i3 = 3;
+ return this;
+ }
+ return new C();
+}
+
+function createEmpty() {
+ function C() {
+ return this;
+ }
+ return new C();
+}
+
+function createDeep() {
+ function C() {
+ this.i1 = 1;
+ this.i2 = 2;
+ this.i3 = 3;
+ return this;
+ }
+ function D() {
+ this.p1 = 1;
+ this.p2 = 2;
+ this.p3 = 3;
+ return this;
+ }
+ C.prototype = new D();
+ return new C();
+}
+
+function createDeeper() {
+ function C() {
+ this.i1 = 1;
+ this.i2 = 2;
+ this.i3 = 3;
+ return this;
+ }
+ function D() {
+ this.p1 = 1;
+ this.p2 = 2;
+ this.p3 = 3;
+ return this;
+ }
+ function E() {
+ this.e1 = 1;
+ this.e2 = 2;
+ this.e3 = 3;
+ return this;
+ }
+ D.prototype = new E();
+ C.prototype = new D();
+ return new C();
+}
+
+function createEval() {
+ return eval("Object.create({})");
+}
+
+function p(o) { print(o.x) }
+
+function e(o) { print(o.e1) }
+
+var a, b, c;
+
+create();
+a = create();
+b = create();
+c = create();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = create();
+b = create();
+c = create();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEmpty();
+b = createEmpty();
+c = createEmpty();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEmpty();
+b = createEmpty();
+c = createEmpty();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeep();
+b = createDeep();
+c = createDeep();
+a.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeep();
+b = createDeep();
+c = createDeep();
+b.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+a.__proto__.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+b.__proto__.__proto__.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+a.__proto__.__proto__ = null;
+
+e(a);
+e(b);
+e(c);
+
+a = createDeeper();
+b = createDeeper();
+c = createDeeper();
+b.__proto__.__proto__ = null;
+
+e(a);
+e(b);
+e(c);
+
+
+a = createEval();
+b = createEval();
+c = createEval();
+a.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
+
+a = createEval();
+b = createEval();
+c = createEval();
+b.__proto__.x = 123;
+
+p(a);
+p(b);
+p(c);
diff --git a/nashorn/test/script/basic/JDK-8134569.js.EXPECTED b/nashorn/test/script/basic/JDK-8134569.js.EXPECTED
new file mode 100644
index 0000000..9793ca5
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134569.js.EXPECTED
@@ -0,0 +1,36 @@
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+123
+undefined
+undefined
+undefined
+123
+undefined
+undefined
+1
+1
+1
+undefined
+1
+123
+undefined
+undefined
+undefined
+123
+undefined
diff --git a/nashorn/test/script/basic/JDK-8134609.js b/nashorn/test/script/basic/JDK-8134609.js
new file mode 100644
index 0000000..ac4c4f9
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134609.js
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134609: Allow constructors with same prototoype map to share the allocator map
+ *
+ * @test
+ * @run
+ * @fork
+ * @option -Dnashorn.debug
+ */
+
+function createProto(members) {
+ function P() {
+ for (var id in members) {
+ if (members.hasOwnProperty(id)) {
+ this[id] = members[id];
+ }
+ }
+ return this;
+ }
+ return new P();
+}
+
+function createSubclass(prototype, members) {
+ function C() {
+ for (var id in members) {
+ if (members.hasOwnProperty(id)) {
+ this[id] = members[id];
+ }
+ }
+ return this;
+ }
+
+ C.prototype = prototype;
+
+ return new C();
+}
+
+function assertP1(object, value) {
+ Assert.assertTrue(object.p1 === value);
+}
+
+// First prototype will have non-shared proto-map. Second and third will be shared.
+var proto0 = createProto({p1: 0, p2: 1});
+var proto1 = createProto({p1: 1, p2: 2});
+var proto2 = createProto({p1: 2, p2: 3});
+
+Assert.assertTrue(Debug.map(proto1) === Debug.map(proto2));
+
+assertP1(proto1, 1);
+assertP1(proto2, 2);
+
+// First instantiation will have a non-shared prototype map, from the second one
+// maps will be shared until a different proto map comes along.
+var child0 = createSubclass(proto1, {c1: 1, c2: 2});
+var child1 = createSubclass(proto2, {c1: 2, c2: 3});
+var child2 = createSubclass(proto1, {c1: 3, c2: 4});
+var child3 = createSubclass(proto2, {c1: 1, c2: 2});
+var child4 = createSubclass(proto0, {c1: 3, c2: 2});
+
+Assert.assertTrue(Debug.map(child1) === Debug.map(child2));
+Assert.assertTrue(Debug.map(child1) === Debug.map(child3));
+Assert.assertTrue(Debug.map(child3) !== Debug.map(child4));
+
+assertP1(child1, 2);
+assertP1(child2, 1);
+assertP1(child3, 2);
+assertP1(child4, 0);
+
+Assert.assertTrue(delete proto2.p1);
+
+assertP1(child3, undefined);
+assertP1(child2, 1);
+Assert.assertTrue(Debug.map(child1) !== Debug.map(child3));
diff --git a/nashorn/test/script/basic/JDK-8134731.js b/nashorn/test/script/basic/JDK-8134731.js
new file mode 100644
index 0000000..e5cd339
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134731.js
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134731: `Function.prototype.apply` interacts incorrectly with `arguments`
+ *
+ * @test
+ * @run
+ */
+
+function func() {
+ return (function(f){
+ return function(a1, a2, a3, a4){
+ return (f.apply(this, arguments));
+ }
+ })(function(){
+ return arguments.length;
+ })
+}
+
+Assert.assertTrue(func()() == 0);
+Assert.assertTrue(func()(33) == 1);
+Assert.assertTrue(func()(33, true) == 2);
+Assert.assertTrue(func()(33, true, "hello") == 3);
+Assert.assertTrue(func()(33, true, "hello", "world") == 4);
+Assert.assertTrue(func()(33, true, "hello", "world", 42) == 5);
diff --git a/nashorn/test/script/basic/JDK-8134939.js b/nashorn/test/script/basic/JDK-8134939.js
new file mode 100644
index 0000000..67990d1
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8134939.js
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8134939: Improve toString method of Dynalink OverloadedDynamicMethod
+ *
+ * @test
+ * @run
+ */
+
+var overloadedSetter = new (Java.type("jdk.nashorn.test.models.OverloadedSetter"));
+
+Assert.assertEquals(String(overloadedSetter.foo),
+ "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+ " String jdk.nashorn.test.models.OverloadedSetter.foo(String)\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.foo(int)\n" +
+ "]");
+
+Assert.assertEquals(String(overloadedSetter.setColor),
+ "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.setColor(int)\n" +
+ " void jdk.nashorn.test.models.OverloadedSetter.setColor(String)\n" +
+ "]");
diff --git a/nashorn/test/script/basic/JDK-8135000.js b/nashorn/test/script/basic/JDK-8135000.js
new file mode 100644
index 0000000..34ad8e8
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8135000.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8135000: Number.prototype.toFixed returns wrong string for 0.5 and -0.5
+ *
+ * @test
+ * @run
+ */
+
+print(-2.6.toFixed());
+print(-2.5.toFixed());
+print(-2.4.toFixed());
+print(-1.6.toFixed());
+print(-1.5.toFixed());
+print(-1.4.toFixed());
+print(-0.6.toFixed());
+print(-0.5.toFixed());
+print(-0.4.toFixed());
+print(0.4.toFixed());
+print(0.5.toFixed());
+print(0.6.toFixed());
+print(1.4.toFixed());
+print(1.5.toFixed());
+print(1.6.toFixed());
+print(2.4.toFixed());
+print(2.5.toFixed());
+print(2.6.toFixed());
diff --git a/nashorn/test/script/basic/JDK-8135000.js.EXPECTED b/nashorn/test/script/basic/JDK-8135000.js.EXPECTED
new file mode 100644
index 0000000..e296377
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8135000.js.EXPECTED
@@ -0,0 +1,18 @@
+-3
+-3
+-2
+-2
+-2
+-1
+-1
+-1
+0
+0
+1
+1
+1
+2
+2
+2
+3
+3
diff --git a/nashorn/test/script/basic/JDK-8135190.js b/nashorn/test/script/basic/JDK-8135190.js
new file mode 100644
index 0000000..f6f4947
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8135190.js
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8135190: Method code too large in Babel browser.js script
+ *
+ * @test
+ * @run
+ */
+
+// Make sure huge object literals are parsed correctly and don't throw
+// (using buildObject -> JSON.stringify -> eval -> testObject)
+
+function buildObject(n, d) {
+ if (n < 2) {
+ return {name: "property", type: "identifier"};
+ }
+ var obj = {};
+ for (var i = 0; i < n; i++) {
+ obj["expr" + i] = buildObject(Math.floor(n / d), d);
+ }
+ return obj;
+}
+
+function testObject(obj, n, d) {
+ var keys = Object.keys(obj);
+ if (n < 2) {
+ Assert.assertTrue(keys.length === 2);
+ Assert.assertTrue(keys[0] === "name");
+ Assert.assertTrue(keys[1] === "type");
+ } else {
+ Assert.assertTrue(keys.length === n);
+ for (var i = 0; i < n; i++) {
+ Assert.assertTrue(keys[i] === "expr" + i);
+ }
+ }
+ if (n >= 2) {
+ for (var k in keys) {
+ testObject(obj[keys[k]], Math.floor(n / d), d)
+ }
+ }
+}
+
+var fieldObject = (eval("(" + JSON.stringify(buildObject(25, 2)) + ")"));
+testObject(fieldObject, 25, 2);
+var spillObject = (eval("(" + JSON.stringify(buildObject(1000, 100)) + ")"));
+testObject(spillObject, 1000, 100);
diff --git a/nashorn/test/script/basic/JDK-8136544.js b/nashorn/test/script/basic/JDK-8136544.js
new file mode 100644
index 0000000..b1eeb35
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8136544.js
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8136544: Call site switching to megamorphic causes incorrect property read
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=8
+ * @run
+ */
+
+var ScriptContext = Java.type("javax.script.ScriptContext");
+var ScriptEngineManager = Java.type("javax.script.ScriptEngineManager");
+var m = new ScriptEngineManager();
+var e = m.getEngineByName("nashorn");
+
+var scope = e.getBindings(ScriptContext.ENGINE_SCOPE);
+var MYVAR = "myvar";
+
+function loopupVar() {
+ try {
+ e.eval(MYVAR);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+// make sure we exercise callsite beyond megamorphic threshold we set
+// in this test via nashorn.unstable.relink.threshold property
+// In each iteration, callsite is exercised twice (two evals)
+// So, LIMIT should be more than 4 to exercise megamorphic callsites.
+
+var LIMIT = 5; // This LIMIT should be more than 4
+
+for (var i = 0; i < LIMIT; i++) {
+ // remove the variable and lookup
+ delete scope[MYVAR];
+ Assert.assertFalse(loopupVar(), "Expected true in iteration " + i);
+
+ // set that variable and check again
+ scope[MYVAR] = "foo";
+ Assert.assertTrue(loopupVar(), "Expected false in iteration " + i);
+}
diff --git a/nashorn/test/script/basic/JDK-8136694.js b/nashorn/test/script/basic/JDK-8136694.js
new file mode 100644
index 0000000..29009e4
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8136694.js
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8136694: Megemorphic scope access does not throw ReferenceError when property is missing
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.unstable.relink.threshold=16
+ * @run
+ */
+
+function checkFoo() {
+ try {
+ // The 'foo' access becomes megamorphic
+ foo;
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+
+// Similar check for 'with' blocks as well.
+function checkFooInWith() {
+ with({}) {
+ try {
+ // The 'foo' access becomes megamorphic
+ foo;
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+}
+
+function loop(checker) {
+ // LIMIT has to be more than the megamorphic threashold
+ // set via @option in this test header!
+ var LIMIT = 20;
+ for (var i = 0; i < LIMIT; i++) {
+ // make sure global has no "foo"
+ delete foo;
+ Assert.assertFalse(checker(), "Expected false in interation " + i);
+
+ // now add 'foo' in global
+ foo = 44;
+ Assert.assertTrue(checker(), "Expected true in interation " + i);
+ }
+}
+
+
+loop(checkFoo);
+loop(checkFooInWith);
diff --git a/nashorn/test/script/basic/JDK-8137134.js b/nashorn/test/script/basic/JDK-8137134.js
new file mode 100644
index 0000000..fe4869a
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8137134.js
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8137134: invokespecial on indirect super interface is generated by Java adapter generator
+ *
+ * @test
+ * @run
+ */
+
+var B = Java.type("jdk.nashorn.test.models.B");
+var b1 = new B() {}
+print(b1.a());
+print(b1.b());
+
+var b2 = new B() {
+ b: function() {
+ return "from B.b in script";
+ }
+};
+
+print(b2.a());
+print(b2.b());
+
+var b3 = new B() {
+ a: function() {
+ return "from A.a in script";
+ },
+ b: function() {
+ return "from B.b in script";
+ }
+};
+
+print(b3.a());
+print(b3.b());
diff --git a/nashorn/test/script/basic/JDK-8137134.js.EXPECTED b/nashorn/test/script/basic/JDK-8137134.js.EXPECTED
new file mode 100644
index 0000000..3ec4b30
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8137134.js.EXPECTED
@@ -0,0 +1,6 @@
+from A.a
+from B.b
+from A.a
+from B.b in script
+from A.a in script
+from B.b in script
diff --git a/nashorn/test/script/basic/JDK-8137281.js b/nashorn/test/script/basic/JDK-8137281.js
new file mode 100644
index 0000000..7c12b32
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8137281.js
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8137281: OutOfMemoryError with large numeric keys in JSON.parse
+ *
+ * @test
+ * @run
+ */
+
+function createObject(startKey, level1, level2) {
+ var root = {};
+ var key = startKey;
+ for (var i = 0; i < level1; i++) {
+ var child = {};
+ for (var j = 0; j < level2; j++) {
+ child[key++] = {};
+ }
+ root[key++] = child;
+ }
+ return root;
+}
+
+JSON.parse(JSON.stringify(createObject(500000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(1000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(2000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(4000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(8000000, 20, 20)));
+JSON.parse(JSON.stringify(createObject(16000000, 20, 20)));
diff --git a/nashorn/test/script/basic/JDK-8138632.js b/nashorn/test/script/basic/JDK-8138632.js
new file mode 100644
index 0000000..cd88cda
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8138632.js
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8138632: Sparse array does not handle growth of underlying dense array
+ *
+ * @test
+ * @run
+ */
+
+var x = [];
+x[10000000] = 1;
+x[10] = 1;
+x[20] = 1;
+print(Object.keys(x));
diff --git a/nashorn/test/script/basic/JDK-8138632.js.EXPECTED b/nashorn/test/script/basic/JDK-8138632.js.EXPECTED
new file mode 100644
index 0000000..ef7fdec
--- /dev/null
+++ b/nashorn/test/script/basic/JDK-8138632.js.EXPECTED
@@ -0,0 +1 @@
+10,20,10000000
diff --git a/nashorn/test/script/basic/NASHORN-75.js.EXPECTED b/nashorn/test/script/basic/NASHORN-75.js.EXPECTED
index e1352a3..9c27c82 100644
--- a/nashorn/test/script/basic/NASHORN-75.js.EXPECTED
+++ b/nashorn/test/script/basic/NASHORN-75.js.EXPECTED
@@ -1,3 +1,3 @@
-TypeError: [RegExp /a|b/g] is not a function
-TypeError: [String hello] is not a function
-TypeError: [object Object] is not a function
+TypeError: RegExp("a|b", "g") is not a function
+TypeError: new String("hello") is not a function
+TypeError: new Object() is not a function
diff --git a/nashorn/test/script/basic/errors.js.EXPECTED b/nashorn/test/script/basic/errors.js.EXPECTED
index 8fae2ca..4e3385e 100644
--- a/nashorn/test/script/basic/errors.js.EXPECTED
+++ b/nashorn/test/script/basic/errors.js.EXPECTED
@@ -1,31 +1,31 @@
-Error is a function
-EvalError is a function
-RangeError is a function
-ReferenceError is a function
-SyntaxError is a function
-TypeError is a function
-URIError is a function
-Error.arity 1
-EvalError.arity 1
-RangeError.arity 1
-ReferenceError.arity 1
-SyntaxError.arity 1
-TypeError.arity 1
-URIError.arity 1
-true
-my error
-Error
-thrown @ 49
-true
-ReferenceError
-"foo" is not defined
-true
-TypeError
-Cannot call undefined
-Error
-EvalError
-RangeError
-ReferenceError
-SyntaxError
-TypeError
-URIError
+Error is a function
+EvalError is a function
+RangeError is a function
+ReferenceError is a function
+SyntaxError is a function
+TypeError is a function
+URIError is a function
+Error.arity 1
+EvalError.arity 1
+RangeError.arity 1
+ReferenceError.arity 1
+SyntaxError.arity 1
+TypeError.arity 1
+URIError.arity 1
+true
+my error
+Error
+thrown @ 49
+true
+ReferenceError
+"foo" is not defined
+true
+TypeError
+Object.foo_method is not a function
+Error
+EvalError
+RangeError
+ReferenceError
+SyntaxError
+TypeError
+URIError
diff --git a/nashorn/test/script/basic/javaarrayconversion.js b/nashorn/test/script/basic/javaarrayconversion.js
index 6168247..37bf4687 100644
--- a/nashorn/test/script/basic/javaarrayconversion.js
+++ b/nashorn/test/script/basic/javaarrayconversion.js
@@ -128,24 +128,32 @@
// Converting to string, toString takes precedence over valueOf
test({ valueOf: function() { return "42"; }, toString: function() { return "43"; } }, "java.lang.String", "43")
+function assertCanConvert(sourceType, targetType) {
+ Java.to([new (Java.type(sourceType))()], targetType + "[]")
+ ++testCount;
+}
+
function assertCantConvert(sourceType, targetType) {
try {
- Java.to([new Java.type(sourceType)()], targetType + "[]")
+ Java.to([new (Java.type(sourceType))()], targetType + "[]")
throw "no TypeError encountered"
} catch(e) {
- if(!(e instanceof TypeError)) {
+ if(!(e instanceof TypeError) ||
+ !e.message.startsWith("Java.to conversion to array type")) {
throw e;
}
++testCount;
}
}
+// Arbitrary POJOs to JS Primitive type should work
+assertCanConvert("java.util.BitSet", "int")
+assertCanConvert("java.util.BitSet", "double")
+assertCanConvert("java.util.BitSet", "long")
+assertCanConvert("java.util.BitSet", "boolean")
+assertCanConvert("java.util.BitSet", "java.lang.String")
+
// Arbitrary POJOs can't be converted to Java values
-assertCantConvert("java.util.BitSet", "int")
-assertCantConvert("java.util.BitSet", "double")
-assertCantConvert("java.util.BitSet", "long")
-assertCantConvert("java.util.BitSet", "boolean")
-assertCantConvert("java.util.BitSet", "java.lang.String")
assertCantConvert("java.util.BitSet", "java.lang.Double")
assertCantConvert("java.util.BitSet", "java.lang.Long")
diff --git a/nashorn/test/script/nosecurity/JDK-8073613.js b/nashorn/test/script/nosecurity/JDK-8073613.js
new file mode 100644
index 0000000..5376ba7
--- /dev/null
+++ b/nashorn/test/script/nosecurity/JDK-8073613.js
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+/**
+ * JDK-8073613: Here documents: how to avoid string interpolation?
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+var a = 2,
+ b = 3
+
+print(<<EOD)
+${a}${b}
+EOD
+
+print(<<"EOD")
+${a}${b}
+EOD
+
+print(<<'EOM')
+${a}${b}
+EOM
+
+print(<<"EOM")
+$\{a}
+EOM
+
diff --git a/nashorn/test/script/nosecurity/JDK-8073613.js.EXPECTED b/nashorn/test/script/nosecurity/JDK-8073613.js.EXPECTED
new file mode 100644
index 0000000..7ef62b4
--- /dev/null
+++ b/nashorn/test/script/nosecurity/JDK-8073613.js.EXPECTED
@@ -0,0 +1,4 @@
+23
+${a}${b}
+${a}${b}
+$\{a}
diff --git a/nashorn/test/script/trusted/JDK-8006529.js b/nashorn/test/script/trusted/JDK-8006529.js
index 5f61807..7a4c094 100644
--- a/nashorn/test/script/trusted/JDK-8006529.js
+++ b/nashorn/test/script/trusted/JDK-8006529.js
@@ -120,7 +120,7 @@
var sourceForMethod = Source.class.getMethod("sourceFor", java.lang.String.class, java.lang.String.class)
var ParserConstructor = Parser.class.getConstructor(ScriptEnvironment.class, Source.class, ErrorManager.class)
-var CompilerConstructor = Compiler.class.getConstructor(Context.class, ScriptEnvironment.class, CodeInstaller.class, Source.class, ErrorManager.class, boolean.class);
+var CompilerConstructor = Compiler.class.getMethod("forNoInstallerCompilation", Context.class, Source.class, boolean.class);
// compile(script) -- compiles a script specified as a string with its
// source code, returns a jdk.nashorn.internal.ir.FunctionNode object
@@ -134,7 +134,7 @@
var parser = ParserConstructor.newInstance(env, source, ThrowErrorManager.class.newInstance());
var func = parseMethod.invoke(parser);
- var compiler = CompilerConstructor.newInstance(ctxt, env, null, source, null, false);
+ var compiler = CompilerConstructor.invoke(null, ctxt, source, false);
return compileMethod.invoke(compiler, func, phases);
};
diff --git a/nashorn/test/script/trusted/JDK-8087292.js b/nashorn/test/script/trusted/JDK-8087292.js
new file mode 100644
index 0000000..2973eb3
--- /dev/null
+++ b/nashorn/test/script/trusted/JDK-8087292.js
@@ -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.
+ */
+
+/**
+ * JDK-8087292: nashorn should have a "fail-fast" option for scripting, analog to bash "set -e"
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+function tryExec() {
+ try {
+ `java`
+ } catch (e) {
+ print(e);
+ }
+
+ // make sure we got non-zero ("failure") exit code!
+ if ($EXIT == 0) {
+ print("Error: expected $EXIT code to be non-zero");
+ }
+}
+
+// no exception now!
+tryExec();
+
+// turn on error with non-zero exit code
+$EXEC.throwOnError = true;
+tryExec();
+
+// no exception after this
+$EXEC.throwOnError = false;
+tryExec();
diff --git a/nashorn/test/script/trusted/JDK-8087292.js.EXPECTED b/nashorn/test/script/trusted/JDK-8087292.js.EXPECTED
new file mode 100644
index 0000000..60c5f80
--- /dev/null
+++ b/nashorn/test/script/trusted/JDK-8087292.js.EXPECTED
@@ -0,0 +1 @@
+RangeError: $EXEC returned non-zero exit code: 1
diff --git a/nashorn/test/script/trusted/classfilter.js.EXPECTED b/nashorn/test/script/trusted/classfilter.js.EXPECTED
index 43d6303..365df61 100644
--- a/nashorn/test/script/trusted/classfilter.js.EXPECTED
+++ b/nashorn/test/script/trusted/classfilter.js.EXPECTED
@@ -4,7 +4,18 @@
typeof java.util.Map evalutes to function
typeof java.util.HashMap evalutes to function
var m = new java.util.HashMap(); m.put('foo', 42); m evalutes to {foo=42}
-java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println]
+java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+]
java.lang.System.exit evalutes to [jdk.internal.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)]
new javax.script.SimpleBindings throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.SimpleBindings
Java.type('javax.script.ScriptContext') throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.ScriptContext
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java
similarity index 95%
rename from nashorn/test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java
rename to nashorn/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java
index 99443f3..0b52d9d 100644
--- a/nashorn/test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/JSONCompatibleTest.java
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.nashorn.api.scripting;
+package jdk.nashorn.api.scripting.test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@@ -33,6 +33,9 @@
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.NashornScriptEngine;
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java
index 0d9dc4d..918e931 100644
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/PluggableJSObjectTest.java
@@ -27,6 +27,7 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.nio.IntBuffer;
@@ -34,9 +35,11 @@
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Set;
+import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import jdk.nashorn.api.scripting.AbstractJSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
import org.testng.annotations.Test;
/**
@@ -286,4 +289,23 @@
fail(exp.getMessage());
}
}
+
+ // @bug 8137258: JSObjectLinker and BrowserJSObjectLinker should not expose internal JS objects
+ @Test
+ public void hidingInternalObjectsForJSObjectTest() throws Exception {
+ final ScriptEngineManager engineManager = new ScriptEngineManager();
+ final ScriptEngine e = engineManager.getEngineByName("nashorn");
+
+ final String code = "function func(obj) { obj.foo = [5, 5]; obj.bar = {} }";
+ e.eval(code);
+
+ // call the exposed function but pass user defined JSObject impl as argument
+ ((Invocable)e).invokeFunction("func", new AbstractJSObject() {
+ @Override
+ public void setMember(final String name, final Object value) {
+ // make sure that wrapped objects are passed (and not internal impl. objects)
+ assertTrue(value.getClass() == ScriptObjectMirror.class);
+ }
+ });
+ }
}
diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java
index 3b55455..05b614a 100644
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java
@@ -26,9 +26,11 @@
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import javax.script.Bindings;
+import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
@@ -820,4 +822,93 @@
public void recursiveEvalCallScriptContextTest() throws ScriptException {
new RecursiveEval().program();
}
+
+ private static final String VAR_NAME = "myvar";
+
+ private static boolean lookupVar(final ScriptEngine engine, final String varName) {
+ try {
+ engine.eval(varName);
+ return true;
+ } catch (final ScriptException se) {
+ return false;
+ }
+ }
+
+ // @bug 8136544: Call site switching to megamorphic causes incorrect property read
+ @Test
+ public void megamorphicPropertyReadTest() throws ScriptException {
+ final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+ final ScriptEngine engine = factory.getScriptEngine();
+ final Bindings scope = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+ boolean ret;
+
+ // Why 16 is the upper limit of this loop? The default nashorn dynalink megamorphic threshold is 16.
+ // See jdk.nashorn.internal.runtime.linker.Bootstrap.NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD
+ // We do, 'eval' of the same in this loop twice. So, 16*2 = 32 times that callsite in the script
+ // is exercised - much beyond the default megamorphic threshold.
+
+ for (int i = 0; i < 16; i++) {
+ scope.remove(VAR_NAME);
+ ret = lookupVar(engine, VAR_NAME);
+ assertFalse(ret, "Expected false in iteration " + i);
+ scope.put(VAR_NAME, "foo");
+ ret = lookupVar(engine, VAR_NAME);
+ assertTrue(ret, "Expected true in iteration " + i);
+ }
+ }
+
+ // @bug 8138616: invokeFunction fails if function calls a function defined in GLOBAL_SCOPE
+ @Test
+ public void invokeFunctionInGlobalScopeTest() throws Exception {
+ final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+ final ScriptContext ctxt = engine.getContext();
+
+ // define a function called "func"
+ engine.eval("func = function() { return 42 }");
+
+ // move ENGINE_SCOPE Bindings to GLOBAL_SCOPE
+ ctxt.setBindings(ctxt.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.GLOBAL_SCOPE);
+
+ // create a new Bindings and set as ENGINE_SCOPE
+ ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+ // define new function that calls "func" now in GLOBAL_SCOPE
+ engine.eval("newfunc = function() { return func() }");
+
+ // call "newfunc" and check the return value
+ Object value = ((Invocable)engine).invokeFunction("newfunc");
+ assertTrue(((Number)value).intValue() == 42);
+ }
+
+
+ // @bug 8138616: invokeFunction fails if function calls a function defined in GLOBAL_SCOPE
+ // variant of above that replaces default ScriptContext of the engine with a fresh instance!
+ @Test
+ public void invokeFunctionInGlobalScopeTest2() throws Exception {
+ final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
+
+ // create a new ScriptContext instance
+ final ScriptContext ctxt = new SimpleScriptContext();
+ // set it as 'default' ScriptContext
+ engine.setContext(ctxt);
+
+ // create a new Bindings and set as ENGINE_SCOPE
+ ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+ // define a function called "func"
+ engine.eval("func = function() { return 42 }");
+
+ // move ENGINE_SCOPE Bindings to GLOBAL_SCOPE
+ ctxt.setBindings(ctxt.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.GLOBAL_SCOPE);
+
+ // create a new Bindings and set as ENGINE_SCOPE
+ ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
+
+ // define new function that calls "func" now in GLOBAL_SCOPE
+ engine.eval("newfunc = function() { return func() }");
+
+ // call "newfunc" and check the return value
+ Object value = ((Invocable)engine).invokeFunction("newfunc");
+ assertTrue(((Number)value).intValue() == 42);
+ }
}
diff --git a/nashorn/test/src/jdk/nashorn/test/models/A.java b/nashorn/test/src/jdk/nashorn/test/models/A.java
new file mode 100644
index 0000000..3b302a6
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/test/models/A.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+public interface A {
+ default String a() {
+ return "from A.a";
+ }
+}
diff --git a/nashorn/test/src/jdk/nashorn/test/models/B.java b/nashorn/test/src/jdk/nashorn/test/models/B.java
new file mode 100644
index 0000000..8c98c19
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/test/models/B.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+public interface B extends A {
+ default String b() {
+ return "from B.b";
+ }
+}
diff --git a/nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java b/nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java
new file mode 100644
index 0000000..a9b5401
--- /dev/null
+++ b/nashorn/test/src/jdk/nashorn/test/models/VarArgConsumer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.test.models;
+
+/**
+ * Simple function interface with a varargs SAM method.
+ */
+@FunctionalInterface
+public interface VarArgConsumer {
+ public void apply(Object... o);
+}
+