From c6307aec19f8c01902dd460d2238e10af6c6ea57 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 15 May 2019 11:53:47 +0200 Subject: [PATCH 001/263] 8223911: Disable bad node budget verification until the fix Reviewed-by: kvn, thartmann --- src/hotspot/share/opto/loopnode.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index cbec15a3bb3..501e59eb35a 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1384,7 +1384,8 @@ private: uint required = _nodes_required; require_nodes_final(); uint delta = C->live_nodes() - live_at_begin; - assert(delta <= 2 * required, "Bad node estimate (actual: %d, request: %d)", + // Assert is disabled, see JDK-8223911 and related issues. + assert(true || delta <= 2 * required, "Bad node estimate (actual: %d, request: %d)", delta, required); } From 48b04f9a08838bcac6e96d9ecfd4e01c1c934627 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Wed, 15 May 2019 14:30:22 +0200 Subject: [PATCH 002/263] 8223885: hs_err and replay file may contain garbage when overwriting existing file Truncate file before overwriting. Reviewed-by: stuefe, dholmes --- src/hotspot/share/utilities/vmError.cpp | 2 +- test/hotspot/jtreg/ProblemList.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 169ae12e533..64194085e50 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1198,7 +1198,7 @@ volatile intptr_t VMError::first_error_tid = -1; static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { int fd = -1; if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) { - fd = open(buf, O_RDWR | O_CREAT, 0666); + fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666); } return fd; } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 91d85be8c58..70217ab7591 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -41,7 +41,6 @@ # :hotspot_compiler compiler/ciReplay/TestSAServer.java 8029528 generic-all -compiler/ciReplay/TestServerVM.java 8223885 generic-all compiler/codecache/stress/OverloadCompileQueueTest.java 8166554 generic-all compiler/codegen/Test6896617.java 8193479 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8140405 generic-all From 53845dabdcb525d53b51fd96e2ba19d6dd6b6df1 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Wed, 15 May 2019 08:58:23 -0400 Subject: [PATCH 003/263] 8223215: Shenandoah: Support verifying subset of roots Reviewed-by: shade, rkennke --- .../share/gc/shenandoah/shenandoahHeap.cpp | 7 ++ .../gc/shenandoah/shenandoahRootProcessor.cpp | 26 ------ .../gc/shenandoah/shenandoahRootProcessor.hpp | 3 - .../gc/shenandoah/shenandoahRootVerifier.cpp | 90 +++++++++++++++++++ .../gc/shenandoah/shenandoahRootVerifier.hpp | 55 ++++++++++++ .../gc/shenandoah/shenandoahVerifier.cpp | 25 ++++-- .../gc/shenandoah/shenandoahVerifier.hpp | 2 + 7 files changed, 170 insertions(+), 38 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b9d98152dfe..68650bdae75 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2145,6 +2145,9 @@ void ShenandoahHeap::op_init_updaterefs() { retire_and_reset_gclabs(); if (ShenandoahVerify) { + if (!is_degenerated_gc_in_progress()) { + verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::ThreadRoots); + } verifier()->verify_before_updaterefs(); } @@ -2182,6 +2185,10 @@ void ShenandoahHeap::op_final_updaterefs() { } assert(!cancelled_gc(), "Should have been done right before"); + if (ShenandoahVerify && !is_degenerated_gc_in_progress()) { + verifier()->verify_roots_no_forwarded_except(ShenandoahRootVerifier::ThreadRoots); + } + concurrent_mark()->update_roots(is_degenerated_gc_in_progress() ? ShenandoahPhaseTimings::degen_gc_update_roots: ShenandoahPhaseTimings::final_update_refs_roots); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index a4c57ab9e2f..5b3459b4140 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -75,32 +75,6 @@ ShenandoahRootProcessor::~ShenandoahRootProcessor() { ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); } -void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) { - CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); - CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); - - CodeCache::blobs_do(&blobs); - ClassLoaderDataGraph::cld_do(&clds); - Universe::oops_do(oops); - Management::oops_do(oops); - JvmtiExport::oops_do(oops); - JNIHandles::oops_do(oops); - ObjectSynchronizer::oops_do(oops); - SystemDictionary::oops_do(oops); - - AlwaysTrueClosure always_true; - WeakProcessor::weak_oops_do(&always_true, oops); - - if (ShenandoahStringDedup::is_enabled()) { - ShenandoahStringDedup::oops_do_slow(oops); - } - - // Do thread roots the last. This allows verification code to find - // any broken objects from those special roots first, not the accidental - // dangling reference from the thread root. - Threads::possibly_parallel_oops_do(false, oops, &blobs); -} - void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops, CLDClosure* clds, CodeBlobClosure* blobs, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index 49506456fba..b1fd3c1c296 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -107,9 +107,6 @@ public: ThreadClosure* thread_cl, uint worker_id); - // For slow debug/verification code - void process_all_roots_slow(OopClosure* oops); - // Number of worker threads used by the root processor. uint n_workers() const; }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp new file mode 100644 index 00000000000..2a4e3c7afa5 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + */ + + +#include "precompiled.hpp" + + +#include "classfile/classLoaderDataGraph.hpp" +#include "classfile/systemDictionary.hpp" +#include "code/codeCache.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahRootVerifier.hpp" +#include "gc/shenandoah/shenandoahStringDedup.hpp" +#include "gc/shared/weakProcessor.inline.hpp" +#include "memory/universe.hpp" +#include "runtime/thread.hpp" +#include "services/management.hpp" +#include "utilities/debug.hpp" + +// Check for overflow of number of root types. +STATIC_ASSERT((static_cast(ShenandoahRootVerifier::AllRoots) + 1) > static_cast(ShenandoahRootVerifier::AllRoots)); + +ShenandoahRootVerifier::ShenandoahRootVerifier() : _types(AllRoots) { +} + +void ShenandoahRootVerifier::excludes(RootTypes types) { + _types = static_cast(static_cast(_types) & (~static_cast(types))); +} + +bool ShenandoahRootVerifier::verify(RootTypes type) const { + return (_types & type) != 0; +} + +void ShenandoahRootVerifier::oops_do(OopClosure* oops) { + CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); + if (verify(CodeRoots)) { + CodeCache::blobs_do(&blobs); + } + + if (verify(CLDGRoots)) { + CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); + ClassLoaderDataGraph::cld_do(&clds); + } + + if (verify(SerialRoots)) { + Universe::oops_do(oops); + Management::oops_do(oops); + JvmtiExport::oops_do(oops); + JNIHandles::oops_do(oops); + ObjectSynchronizer::oops_do(oops); + SystemDictionary::oops_do(oops); + } + + if (verify(WeakRoots)) { + AlwaysTrueClosure always_true; + WeakProcessor::weak_oops_do(&always_true, oops); + } + + if (ShenandoahStringDedup::is_enabled() && verify(StringDedupRoots)) { + ShenandoahStringDedup::oops_do_slow(oops); + } + + if (verify(ThreadRoots)) { + // Do thread roots the last. This allows verification code to find + // any broken objects from those special roots first, not the accidental + // dangling reference from the thread root. + Threads::possibly_parallel_oops_do(false, oops, &blobs); + } +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp new file mode 100644 index 00000000000..d79f14eb69f --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTVERIFIER_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHROOTVERIFIER_HPP + +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" + +class ShenandoahRootVerifier : public StackObj { +public: + enum RootTypes { + SerialRoots = 1 << 0, + ThreadRoots = 1 << 1, + CodeRoots = 1 << 2, + CLDGRoots = 1 << 3, + WeakRoots = 1 << 4, + StringDedupRoots = 1 << 5, + AllRoots = (SerialRoots | ThreadRoots | CodeRoots | CLDGRoots | WeakRoots | StringDedupRoots) + }; + +private: + RootTypes _types; + +public: + ShenandoahRootVerifier(); + + void excludes(RootTypes types); + void oops_do(OopClosure* cl); + +private: + bool verify(RootTypes type) const; +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTVERIFIER_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 4b2c8b5785d..0cb93611b4e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -419,7 +419,7 @@ public: class ShenandoahVerifierReachableTask : public AbstractGangTask { private: const char* _label; - ShenandoahRootProcessor* _rp; + ShenandoahRootVerifier* _verifier; ShenandoahVerifier::VerifyOptions _options; ShenandoahHeap* _heap; ShenandoahLivenessData* _ld; @@ -429,12 +429,12 @@ private: public: ShenandoahVerifierReachableTask(MarkBitMap* bitmap, ShenandoahLivenessData* ld, - ShenandoahRootProcessor* rp, + ShenandoahRootVerifier* verifier, const char* label, ShenandoahVerifier::VerifyOptions options) : AbstractGangTask("Shenandoah Parallel Verifier Reachable Task"), _label(label), - _rp(rp), + _verifier(verifier), _options(options), _heap(ShenandoahHeap::heap()), _ld(ld), @@ -458,7 +458,7 @@ public: ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Roots", _label), _options); - _rp->process_all_roots_slow(&cl); + _verifier->oops_do(&cl); } size_t processed = 0; @@ -692,10 +692,9 @@ void ShenandoahVerifier::verify_at_safepoint(const char *label, // This verifies what application can see, since it only cares about reachable objects. size_t count_reachable = 0; if (ShenandoahVerifyLevel >= 2) { - ShenandoahRootProcessor rp(_heap, _heap->workers()->active_workers(), - ShenandoahPhaseTimings::_num_phases); // no need for stats + ShenandoahRootVerifier verifier; - ShenandoahVerifierReachableTask task(_verification_bit_map, ld, &rp, label, options); + ShenandoahVerifierReachableTask task(_verification_bit_map, ld, &verifier, label, options); _heap->workers()->run_task(&task); count_reachable = task.processed(); } @@ -943,7 +942,15 @@ public: void ShenandoahVerifier::verify_roots_no_forwarded() { guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens"); - ShenandoahRootProcessor rp(_heap, 1, ShenandoahPhaseTimings::_num_phases); // no need for stats + ShenandoahRootVerifier verifier; ShenandoahVerifyNoForwared cl; - rp.process_all_roots_slow(&cl); + verifier.oops_do(&cl); +} + +void ShenandoahVerifier::verify_roots_no_forwarded_except(ShenandoahRootVerifier::RootTypes types) { + guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens"); + ShenandoahRootVerifier verifier; + verifier.excludes(types); + ShenandoahVerifyNoForwared cl; + verifier.oops_do(&cl); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index 53cebe5bfab..38b6c7d17a3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_SHENANDOAH_SHENANDOAHVERIFIER_HPP #include "gc/shared/markBitMap.hpp" +#include "gc/shenandoah/shenandoahRootVerifier.hpp" #include "memory/allocation.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/stack.hpp" @@ -189,6 +190,7 @@ public: // Roots should only contain to-space oops void verify_roots_no_forwarded(); + void verify_roots_no_forwarded_except(ShenandoahRootVerifier::RootTypes types); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHVERIFIER_HPP From 23301277c56eff451a6ed7c50d635377d60d8a22 Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Fri, 10 May 2019 17:13:02 -0700 Subject: [PATCH 004/263] 8223737: Fix HostsFileNameService for IPv6 literal addresses Reviewed-by: chegar, msheppar --- .../share/classes/java/net/InetAddress.java | 32 ++++---------- .../InternalNameServiceWithHostsFileTest.java | 44 ++++++++++++++----- 2 files changed, 40 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index a05f128bf0f..a1671547da3 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -45,6 +45,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.atomic.AtomicLong; +import java.util.Arrays; import jdk.internal.access.JavaNetInetAddressAccess; import jdk.internal.access.SharedSecrets; @@ -989,29 +990,28 @@ class InetAddress implements java.io.Serializable { String hostEntry; String host = null; - String addrString = addrToString(addr); try (Scanner hostsFileScanner = new Scanner(new File(hostsFile), "UTF-8")) { while (hostsFileScanner.hasNextLine()) { hostEntry = hostsFileScanner.nextLine(); if (!hostEntry.startsWith("#")) { hostEntry = removeComments(hostEntry); - if (hostEntry.contains(addrString)) { - host = extractHost(hostEntry, addrString); - if (host != null) { - break; - } + String[] mapping = hostEntry.split("\\s+"); + if (mapping.length >= 2 && + Arrays.equals(addr, createAddressByteArray(mapping[0]))) { + host = mapping[1]; + break; } } } } catch (FileNotFoundException e) { throw new UnknownHostException("Unable to resolve address " - + addrString + " as hosts file " + hostsFile + + Arrays.toString(addr) + " as hosts file " + hostsFile + " not found "); } if ((host == null) || (host.isEmpty()) || (host.equals(" "))) { throw new UnknownHostException("Requested address " - + addrString + + Arrays.toString(addr) + " resolves to an invalid entry in hosts file " + hostsFile); } @@ -1107,22 +1107,6 @@ class InetAddress implements java.io.Serializable { } return hostAddr; } - - /** - * IP Address to host mapping - * use first host alias in list - */ - private String extractHost(String hostEntry, String addrString) { - String[] mapping = hostEntry.split("\\s+"); - String host = null; - - if (mapping.length >= 2) { - if (mapping[0].equalsIgnoreCase(addrString)) { - host = mapping[1]; - } - } - return host; - } } static final InetAddressImpl impl; diff --git a/test/jdk/java/net/InetAddress/InternalNameServiceWithHostsFileTest.java b/test/jdk/java/net/InetAddress/InternalNameServiceWithHostsFileTest.java index 64f64669272..dc76ac9177c 100644 --- a/test/jdk/java/net/InetAddress/InternalNameServiceWithHostsFileTest.java +++ b/test/jdk/java/net/InetAddress/InternalNameServiceWithHostsFileTest.java @@ -56,19 +56,28 @@ public class InternalNameServiceWithHostsFileTest { byte[] expectedIpv6LocalhostAddress = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; - try { - // 10.2.3.4 testHost.testDomain - testHostsMapping(expectedIpv4Address, "testHost.testDomain"); - // ::1 ip6-localhost ip6-loopback - testHostsMapping(expectedIpv6LocalhostAddress, "ip6-localhost"); - // fe00::0 ip6-localnet - testHostsMapping(expectedIpv6LocalAddress, "ip6-localnet"); - // fe80::1 link-local-host - testHostsMapping(expectedIpv6Address, "link-local-host"); + // 10.2.3.4 testHost.testDomain + testHostsMapping(expectedIpv4Address, "testHost.testDomain"); + // ::1 ip6-localhost ip6-loopback + testHostsMapping(expectedIpv6LocalhostAddress, "ip6-localhost"); + // fe00::0 ip6-localnet + testHostsMapping(expectedIpv6LocalAddress, "ip6-localnet"); + // fe80::1 link-local-host + testHostsMapping(expectedIpv6Address, "link-local-host"); - } catch (UnknownHostException uhEx) { - System.out.println("UHE unexpected caught == " + uhEx.getMessage()); - } + testReverseLookup("10.2.3.4", "testHost.testDomain"); + + testReverseLookup("::1", "ip6-localhost"); + testReverseLookup("0:0:0:0:0:0:0:1", "ip6-localhost"); + testReverseLookup("0000:0000:0000:0000:0000:0000:0000:0001", "ip6-localhost"); + + testReverseLookup("fe00::0", "ip6-localnet"); + testReverseLookup("fe00:0:0:0:0:0:0:0", "ip6-localnet"); + testReverseLookup("fe00:0000:0000:0000:0000:0000:0000:0000", "ip6-localnet"); + + testReverseLookup("fe80::1", "link-local-host"); + testReverseLookup("fe80:000:0:00:0:000:00:1", "link-local-host"); + testReverseLookup("fe80:0000:0000:0000:0000:0000:0000:0001", "link-local-host"); } private static void testHostsMapping(byte[] expectedIpAddress, String hostName) @@ -94,4 +103,15 @@ public class InternalNameServiceWithHostsFileTest { + " equal to expected address == " + Arrays.toString(expectedIpAddress)); } + + private static void testReverseLookup(String numericHost, String expectedName) + throws UnknownHostException { + String lookupResult = InetAddress.getByName(numericHost).getHostName(); + if (!expectedName.equals(lookupResult)) { + throw new RuntimeException( + String.format( + "reverse lookup of \"%s\" is \"%s\", should be \"%s\"\n", + numericHost, lookupResult, expectedName)); + } + } } From e18cecafb93922cc2d986c4a77fca4b4e3589928 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 15 May 2019 11:06:33 -0700 Subject: [PATCH 005/263] 8184770: JDWP support for IPv6 Reviewed-by: sspitsyn, chegar --- .../tools/jdi/SocketListeningConnector.java | 4 +- .../sun/tools/jdi/SocketTransportService.java | 98 ++- .../native/libdt_socket/socketTransport.c | 726 ++++++++++++------ .../share/native/libdt_socket/sysSocket.h | 6 +- .../unix/native/libdt_socket/socket_md.c | 16 +- .../windows/native/libdt_socket/socket_md.c | 24 +- .../startListening/startlis001.java | 46 +- ...ConnectionTest.java => JdwpAllowTest.java} | 160 ++-- test/jdk/com/sun/jdi/JdwpAttachTest.java | 191 +++++ test/jdk/com/sun/jdi/JdwpListenTest.java | 177 +++++ test/jdk/com/sun/jdi/JdwpNetProps.java | 204 +++++ 11 files changed, 1243 insertions(+), 409 deletions(-) rename test/jdk/com/sun/jdi/{BasicJDWPConnectionTest.java => JdwpAllowTest.java} (60%) create mode 100644 test/jdk/com/sun/jdi/JdwpAttachTest.java create mode 100644 test/jdk/com/sun/jdi/JdwpListenTest.java create mode 100644 test/jdk/com/sun/jdi/JdwpNetProps.java diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketListeningConnector.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketListeningConnector.java index 74117e60398..b2feead2ee4 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketListeningConnector.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketListeningConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -101,7 +101,7 @@ public class SocketListeningConnector extends GenericListeningConnector { if (isWildcardPort(args)) { String[] address = listener.address().split(":"); if (address.length > 1) { - args.get(ARG_PORT).setValue(address[1]); + args.get(ARG_PORT).setValue(address[address.length - 1]); } } } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java index 0f3780e8255..c62128bc442 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/SocketTransportService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -79,12 +79,7 @@ public class SocketTransportService extends TransportService { try { address = InetAddress.getLocalHost(); } catch (UnknownHostException uhe) { - byte[] loopback = {0x7f,0x00,0x00,0x01}; - try { - address = InetAddress.getByAddress("127.0.0.1", loopback); - } catch (UnknownHostException x) { - throw new InternalError("unable to get local hostname"); - } + address = InetAddress.getLoopbackAddress(); } } @@ -201,6 +196,44 @@ public class SocketTransportService extends TransportService { }; } + private static class HostPort { + public final String host; + public final int port; + private HostPort(String host, int port) { + this.host = host; + this.port = port; + } + + /** + * Creates an instance for given URN, which can be either or :. + * If host is '*', the returned HostPort instance has host set to null. + * If host is a literal IPv6 address, it may be in square brackets. + */ + public static HostPort parse(String hostPort) { + int splitIndex = hostPort.lastIndexOf(':'); + + int port; + try { + port = Integer.decode(hostPort.substring(splitIndex + 1)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("unable to parse port number in address"); + } + if (port < 0 || port > 0xFFFF) { + throw new IllegalArgumentException("port out of range"); + } + + if (splitIndex <= 0) { // empty host means local connection + return new HostPort(InetAddress.getLoopbackAddress().getHostAddress(), port); + } else if (splitIndex == 1 && hostPort.charAt(0) == '*') { + return new HostPort(null, port); + } else if (hostPort.charAt(0) == '[' && hostPort.charAt(splitIndex - 1) == ']') { + return new HostPort(hostPort.substring(1, splitIndex - 1), port); + } else { + return new HostPort(hostPort.substring(0, splitIndex), port); + } + } + } + /** * Attach to the specified address with optional attach and handshake * timeout. @@ -215,31 +248,14 @@ public class SocketTransportService extends TransportService { throw new IllegalArgumentException("timeout is negative"); } - int splitIndex = address.indexOf(':'); - String host; - String portStr; - if (splitIndex < 0) { - host = "localhost"; - portStr = address; - } else { - host = address.substring(0, splitIndex); - portStr = address.substring(splitIndex+1); - } - - if (host.equals("*")) { - host = InetAddress.getLocalHost().getHostName(); - } - - int port; - try { - port = Integer.decode(portStr).intValue(); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - "unable to parse port number in address"); - } + HostPort hostPort = HostPort.parse(address); // open TCP connection to VM - InetSocketAddress sa = new InetSocketAddress(host, port); + // formally "*" is not correct hostname to attach + // but lets connect to localhost + InetSocketAddress sa = new InetSocketAddress(hostPort.host == null + ? InetAddress.getLoopbackAddress().getHostAddress() + : hostPort.host, hostPort.port); Socket s = new Socket(); try { s.connect(sa, (int)attachTimeout); @@ -290,26 +306,8 @@ public class SocketTransportService extends TransportService { */ public ListenKey startListening(String address) throws IOException { // use ephemeral port if address isn't specified. - if (address == null || address.length() == 0) { - address = "0"; - } - - int splitIndex = address.indexOf(':'); - String localaddr = null; - if (splitIndex >= 0) { - localaddr = address.substring(0, splitIndex); - address = address.substring(splitIndex+1); - } - - int port; - try { - port = Integer.decode(address).intValue(); - } catch (NumberFormatException e) { - throw new IllegalArgumentException( - "unable to parse port number in address"); - } - - return startListening(localaddr, port); + HostPort hostPort = HostPort.parse((address == null || address.isEmpty()) ? "0" : address); + return startListening(hostPort.host, hostPort.port); } /** diff --git a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c index b76a93ca036..a786d5ef562 100644 --- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -47,7 +47,7 @@ * Service Provider Interface - see src/share/javavm/export/jdwpTransport.h. */ -static int serverSocketFD; +static int serverSocketFD = -1; static int socketFD = -1; static jdwpTransportCallback *callback; static JavaVM *jvm; @@ -78,8 +78,9 @@ static jint send_fully(int, char *, int); /* version >= JDWPTRANSPORT_VERSION_1_1 */ typedef struct { - uint32_t subnet; - uint32_t netmask; + /* subnet and mask are stored as IPv6 addresses, IPv4 is stored as mapped IPv6 */ + struct in6_addr subnet; + struct in6_addr netmask; } AllowedPeerInfo; #define STR(x) #x @@ -89,6 +90,9 @@ static AllowedPeerInfo _peers[MAX_PEER_ENTRIES]; static int _peers_cnt = 0; +static int allowOnlyIPv4 = 0; // reflects "java.net.preferIPv4Stack" sys. property +static int preferredAddressFamily = AF_INET; // "java.net.preferIPv6Addresses" + /* * Record the last error for this thread. */ @@ -137,13 +141,19 @@ getLastError() { /* Set options common to client and server sides */ static jdwpTransportError -setOptionsCommon(int fd) +setOptionsCommon(int domain, int fd) { jvalue dontcare; int err; - dontcare.i = 0; /* keep compiler happy */ + if (domain == AF_INET6) { + int off = 0; + // make the socket a dual mode socket + // this may fail if IPv4 is not supported - it's ok + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); + } + dontcare.i = 0; /* keep compiler happy */ err = dbgsysSetSocketOption(fd, TCP_NODELAY, JNI_TRUE, dontcare); if (err < 0) { RETURN_IO_ERROR("setsockopt TCPNODELAY failed"); @@ -223,31 +233,6 @@ handshake(int fd, jlong timeout) { return JDWPTRANSPORT_ERROR_NONE; } -static uint32_t -getLocalHostAddress() { - // Simple routine to guess localhost address. - // it looks up "localhost" and returns 127.0.0.1 if lookup - // fails. - struct addrinfo hints, *res = NULL; - uint32_t addr; - int err; - - // Use portable way to initialize the structure - memset((void *)&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - - err = getaddrinfo("localhost", NULL, &hints, &res); - if (err < 0 || res == NULL) { - return dbgsysHostToNetworkLong(INADDR_LOOPBACK); - } - - // getaddrinfo might return more than one address - // but we are using first one only - addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr; - freeaddrinfo(res); - return addr; -} - static int getPortNumber(const char *s_port) { u_long n; @@ -274,199 +259,290 @@ getPortNumber(const char *s_port) { return n; } -static jdwpTransportError -parseAddress(const char *address, struct sockaddr_in *sa) { - char *colon; - int port; +static unsigned short getPort(struct sockaddr *sa) +{ + return dbgsysNetworkToHostShort(sa->sa_family == AF_INET + ? (((struct sockaddr_in*)sa)->sin_port) + : (((struct sockaddr_in6*)sa)->sin6_port)); +} - memset((void *)sa, 0, sizeof(struct sockaddr_in)); - sa->sin_family = AF_INET; +/* + * Result must be released with dbgsysFreeAddrInfo. + */ +static jdwpTransportError +parseAddress(const char *address, struct addrinfo **result) { + const char *colon; + size_t hostLen; + char *host = NULL; + const char *port; + struct addrinfo hints; + int res; + + *result = NULL; /* check for host:port or port */ - colon = strchr(address, ':'); - port = getPortNumber((colon == NULL) ? address : colon +1); - if (port < 0) { + colon = strrchr(address, ':'); + port = (colon == NULL ? address : colon + 1); + + /* ensure the port is valid (getaddrinfo allows port to be empty) */ + if (getPortNumber(port) < 0) { RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid port number specified"); } - sa->sin_port = dbgsysHostToNetworkShort((u_short)port); - if (colon == NULL) { - // bind to localhost only if no address specified - sa->sin_addr.s_addr = getLocalHostAddress(); - } else if (strncmp(address, "localhost:", 10) == 0) { - // optimize for common case - sa->sin_addr.s_addr = getLocalHostAddress(); - } else if (*address == '*' && *(address+1) == ':') { - // we are explicitly asked to bind server to all available IP addresses - // has no meaning for client. - sa->sin_addr.s_addr = dbgsysHostToNetworkLong(INADDR_ANY); - } else { - char *buf; - char *hostname; - uint32_t addr; - int ai; - buf = (*callback->alloc)((int)strlen(address) + 1); - if (buf == NULL) { + memset (&hints, 0, sizeof(hints)); + hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_NUMERICSERV; // port must be a number + + hostLen = (colon == NULL ? 0 : colon - address); + if (hostLen == 0) { + /* no hostname - use localhost address (pass NULL to getaddrinfo) */ + } else if (*address == '*' && hostLen == 1) { + /* *:port - listen on all interfaces + * use IPv6 socket (to accept IPv6 and mapped IPv4), + * pass hostname == NULL to getaddrinfo. + */ + hints.ai_family = allowOnlyIPv4 ? AF_INET : AF_INET6; + hints.ai_flags |= AI_PASSIVE | (allowOnlyIPv4 ? 0 : AI_V4MAPPED | AI_ALL); + } else { + if (address[0] == '[' && colon[-1] == ']') { + address++; + hostLen -= 2; + } + host = (*callback->alloc)((int)hostLen + 1); + if (host == NULL) { RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); } - strcpy(buf, address); - buf[colon - address] = '\0'; - hostname = buf; + strncpy(host, address, hostLen); + host[hostLen] = '\0'; + } - /* - * First see if the host is a literal IP address. - * If not then try to resolve it. - */ - addr = dbgsysInetAddr(hostname); - if (addr == 0xffffffff) { - struct addrinfo hints; - struct addrinfo *results = NULL; - memset (&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - - ai = dbgsysGetAddrInfo(hostname, NULL, &hints, &results); - - if (ai != 0) { - /* don't use RETURN_IO_ERROR as unknown host is normal */ - setLastError(0, "getaddrinfo: unknown host"); - (*callback->free)(buf); - return JDWPTRANSPORT_ERROR_IO_ERROR; - } - - /* lookup was successful */ - sa->sin_addr = ((struct sockaddr_in *)results->ai_addr)->sin_addr; - freeaddrinfo(results); - } else { - sa->sin_addr.s_addr = addr; - } - - (*callback->free)(buf); + res = dbgsysGetAddrInfo(host, port, &hints, result); + if (host != NULL) { + (*callback->free)(host); + } + if (res != 0) { + setLastError(res, "getaddrinfo: unknown host"); + return JDWPTRANSPORT_ERROR_IO_ERROR; } return JDWPTRANSPORT_ERROR_NONE; } -static const char * -ip_s2u(const char *instr, uint32_t *ip) { - // Convert string representation of ip to integer - // in network byte order (big-endian) - char t[4] = { 0, 0, 0, 0 }; - const char *s = instr; - int i = 0; +/* + * Input is sockaddr just because all clients have it. + */ +static void convertIPv4ToIPv6(const struct sockaddr *addr4, struct in6_addr *addr6) { + // Implement in a platform-independent way. + // Spec requires in_addr has s_addr member, in6_addr has s6_addr[16] member. + struct in_addr *a4 = &(((struct sockaddr_in*)addr4)->sin_addr); + memset(addr6, 0, sizeof(*addr6)); // for safety - while (1) { - if (*s == '.') { - ++i; - ++s; - continue; - } - if (*s == 0 || *s == '+' || *s == '/') { - break; - } - if (*s < '0' || *s > '9') { - return instr; - } - t[i] = (t[i] * 10) + (*s - '0'); - ++s; - } - - *ip = *(uint32_t*)(t); - return s; -} - -static const char * -mask_s2u(const char *instr, uint32_t *mask) { - // Convert the number of bits to a netmask - // in network byte order (big-endian) - unsigned char m = 0; - const char *s = instr; - - while (1) { - if (*s == 0 || *s == '+') { - break; - } - if (*s < '0' || *s > '9') { - return instr; - } - m = (m * 10) + (*s - '0'); - ++s; - } - - if (m == 0 || m > 32) { - // Drop invalid input - return instr; - } - - *mask = htonl((uint32_t)(~0) << (32 - m)); - return s; -} - -static int -ip_in_subnet(uint32_t subnet, uint32_t mask, uint32_t ipaddr) { - return (ipaddr & mask) == subnet; + // Mapped address contains 80 zero bits, then 16 "1" bits, then IPv4 address (4 bytes). + addr6->s6_addr[10] = addr6->s6_addr[11] = 0xFF; + memcpy(&(addr6->s6_addr[12]), &(a4->s_addr), 4); } +/* + * Parses address (IPv4 or IPv6), fills in result by parsed address. + * For IPv4 mapped IPv6 is returned in result, isIPv4 is set. + */ static jdwpTransportError -parseAllowedPeers(const char *allowed_peers) { - // Build a list of allowed peers from char string - // of format 192.168.0.10+192.168.0.0/24 - const char *s = NULL; - const char *p = allowed_peers; - uint32_t ip = 0; - uint32_t mask = 0xFFFFFFFF; +parseAllowedAddr(const char *buffer, struct in6_addr *result, int *isIPv4) { + struct addrinfo hints; + struct addrinfo *addrInfo = NULL; + int err; - while (1) { - s = ip_s2u(p, &ip); - if (s == p) { + /* + * To parse both IPv4 and IPv6 need to specify AF_UNSPEC family + * (with AF_INET6 IPv4 addresses are not parsed even with AI_V4MAPPED and AI_ALL flags). + */ + memset (&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // IPv6 or mapped IPv4 + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_NUMERICHOST; // only numeric addresses, no resolution + + err = dbgsysGetAddrInfo(buffer, NULL, &hints, &addrInfo); + + if (err != 0) { + setLastError(err, "getaddrinfo: failed to parse address"); + return JDWPTRANSPORT_ERROR_IO_ERROR; + } + + if (addrInfo->ai_family == AF_INET6) { + memcpy(result, &(((struct sockaddr_in6 *)(addrInfo->ai_addr))->sin6_addr), sizeof(*result)); + *isIPv4 = 0; + } else { // IPv4 address - convert to mapped IPv6 + struct in6_addr addr6; + convertIPv4ToIPv6(addrInfo->ai_addr, &addr6); + memcpy(result, &addr6, sizeof(*result)); + *isIPv4 = 1; + } + + dbgsysFreeAddrInfo(addrInfo); + + return JDWPTRANSPORT_ERROR_NONE; +} + +/* + * Parses prefix length from buffer (integer value), fills in result with corresponding net mask. + * For IPv4 (isIPv4 is set), maximum prefix length is 32 bit, for IPv6 - 128 bit. + */ +static jdwpTransportError +parseAllowedMask(const char *buffer, int isIPv4, struct in6_addr *result) { + int prefixLen = 0; + int maxValue = isIPv4 ? 32 : 128; + + do { + if (*buffer < '0' || *buffer > '9') { + return JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT; + } + prefixLen = prefixLen * 10 + (*buffer - '0'); + if (prefixLen > maxValue) { // avoid overflow + return JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT; + } + buffer++; + } while (*buffer != '\0'); + + if (isIPv4) { + // IPv4 are stored as mapped IPv6, prefixLen needs to be converted too + prefixLen += 96; + } + + if (prefixLen == 0) { + return JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT; + } + + // generate mask for prefix length + memset(result, 0, sizeof(*result)); + + // prefixLen <= 128, so we won't go over result's size + for (int i = 0; prefixLen > 0; i++, prefixLen -= 8) { + if (prefixLen >= 8) { + // set the whole byte + result->s6_addr[i] = 0xFF; + } else { + // set only "prefixLen" bits + result->s6_addr[i] = (char)(0xFF << (8 - prefixLen)); + } + } + + return JDWPTRANSPORT_ERROR_NONE; +} + +/* + * Internal implementation of parseAllowedPeers (requires writable buffer). + */ +static jdwpTransportError +parseAllowedPeersInternal(char *buffer) { + char *next; + int isIPv4 = 0; + + do { + char *mask = NULL; + char *endOfAddr = strpbrk(buffer, "/+"); + if (endOfAddr == NULL) { + // this is the last address and there is no prefix length + next = NULL; + } else { + next = endOfAddr + 1; + if (*endOfAddr == '/') { + // mask (prefix length) presents + char *endOfMask = strchr(next, '+'); + mask = next; + if (endOfMask == NULL) { + // no more addresses + next = NULL; + } else { + next = endOfMask + 1; + *endOfMask = '\0'; + } + } + *endOfAddr = '\0'; + } + + // parse subnet address (IPv4 is stored as mapped IPv6) + if (parseAllowedAddr(buffer, &(_peers[_peers_cnt].subnet), &isIPv4) != JDWPTRANSPORT_ERROR_NONE) { _peers_cnt = 0; - fprintf(stderr, "Error in allow option: '%s'\n", s); + fprintf(stderr, "Error in allow option: '%s'\n", buffer); RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid IP address in allow option"); } - - if (*s == '/') { - // netmask specified - s = mask_s2u(s + 1, &mask); - if (*(s - 1) == '/') { - // Input is not consumed, something bad happened + if (mask != NULL) { + if (parseAllowedMask(mask, isIPv4, &(_peers[_peers_cnt].netmask)) != JDWPTRANSPORT_ERROR_NONE) { _peers_cnt = 0; - fprintf(stderr, "Error in allow option: '%s'\n", s); + fprintf(stderr, "Error in allow option: '%s'\n", mask); RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "invalid netmask in allow option"); } + // for safety update subnet to satisfy the mask + for (size_t i = 0; i < sizeof(_peers[_peers_cnt].subnet); i++) { + _peers[_peers_cnt].subnet.s6_addr[i] &= _peers[_peers_cnt].netmask.s6_addr[i]; + } } else { - // reset netmask - mask = 0xFFFFFFFF; + memset(&(_peers[_peers_cnt].netmask), 0xFF, sizeof(_peers[_peers_cnt].netmask)); } + _peers_cnt++; + buffer = next; + } while (next != NULL); - if (*s == '+' || *s == 0) { - if (_peers_cnt >= MAX_PEER_ENTRIES) { - fprintf(stderr, "Error in allow option: '%s'\n", allowed_peers); - RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, - "exceeded max number of allowed peers: " MAX_PEERS_STR); - } - _peers[_peers_cnt].subnet = ip; - _peers[_peers_cnt].netmask = mask; - _peers_cnt++; - if (*s == 0) { - // end of options - break; - } - // advance to next IP block - p = s + 1; - } - } return JDWPTRANSPORT_ERROR_NONE; } +/* + * Parses 'allow' argument (fills in list of allowed peers (global _peers variable)). + * 'Allow' value consists of tokens separated by '+', + * each token contains IP address (IPv4 or IPv6) and optional prefixLength: + * '[/]'. + * Example: '192.168.1.10+192.168.0.0/24' + * - connections are allowed from 192.168.1.10 and subnet 192.168.0.XX. + */ +static jdwpTransportError +parseAllowedPeers(const char *allowed_peers, size_t len) { + // Build a list of allowed peers from char string + // of format 192.168.0.10+192.168.0.0/24 + + // writable copy of the value + char *buffer = (*callback->alloc)((int)len + 1); + if (buffer == NULL) { + RETURN_ERROR(JDWPTRANSPORT_ERROR_OUT_OF_MEMORY, "out of memory"); + } + strncpy(buffer, allowed_peers, len); + buffer[len] = '\0'; + + jdwpTransportError err = parseAllowedPeersInternal(buffer); + + (*callback->free)(buffer); + + return err; +} + static int -isPeerAllowed(struct sockaddr_in *peer) { - int i; - for (i = 0; i < _peers_cnt; ++i) { - int peer_ip = peer->sin_addr.s_addr; - if (ip_in_subnet(_peers[i].subnet, _peers[i].netmask, peer_ip)) { +isAddressInSubnet(const struct in6_addr *address, const struct in6_addr *subnet, const struct in6_addr *mask) { + for (size_t i = 0; i < sizeof(struct in6_addr); i++) { + if ((address->s6_addr[i] & mask->s6_addr[i]) != subnet->s6_addr[i]) { + return 0; + } + } + return 1; +} + +static int +isPeerAllowed(struct sockaddr_storage *peer) { + struct in6_addr tmp; + struct in6_addr *addr6; + // _peers contains IPv6 subnet and mask (IPv4 is converted to mapped IPv6) + if (peer->ss_family == AF_INET) { + convertIPv4ToIPv6((struct sockaddr *)peer, &tmp); + addr6 = &tmp; + } else { + addr6 = &(((struct sockaddr_in6 *)peer)->sin6_addr); + } + + for (int i = 0; i < _peers_cnt; ++i) { + if (isAddressInSubnet(addr6, &(_peers[i].subnet), &(_peers[i].netmask))) { return 1; } } @@ -490,65 +566,58 @@ socketTransport_getCapabilities(jdwpTransportEnv* env, return JDWPTRANSPORT_ERROR_NONE; } - -static jdwpTransportError JNICALL -socketTransport_startListening(jdwpTransportEnv* env, const char* address, - char** actualAddress) +/* + * Starts listening on the specified addrinfo, + * returns listening socket and actual listening port. + * If the function fails and returned socket != -1, the socket should be closed. + */ +static jdwpTransportError startListening(struct addrinfo *ai, int *socket, char** actualAddress) { - struct sockaddr_in sa; int err; - memset((void *)&sa,0,sizeof(struct sockaddr_in)); - sa.sin_family = AF_INET; - - /* no address provided */ - if ((address == NULL) || (address[0] == '\0')) { - address = "0"; - } - - err = parseAddress(address, &sa); - if (err != JDWPTRANSPORT_ERROR_NONE) { - return err; - } - - serverSocketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0); - if (serverSocketFD < 0) { + *socket = dbgsysSocket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP); + if (*socket < 0) { RETURN_IO_ERROR("socket creation failed"); } - err = setOptionsCommon(serverSocketFD); + err = setOptionsCommon(ai->ai_family, *socket); if (err) { return err; } - if (sa.sin_port != 0) { + + if (getPort(ai->ai_addr) != 0) { /* * Only need SO_REUSEADDR if we're using a fixed port. If we * start seeing EADDRINUSE due to collisions in free ports * then we should retry the dbgsysBind() a few times. */ - err = setReuseAddrOption(serverSocketFD); + err = setReuseAddrOption(*socket); if (err) { return err; } } - err = dbgsysBind(serverSocketFD, (struct sockaddr *)&sa, sizeof(sa)); + err = dbgsysBind(*socket, ai->ai_addr, (socklen_t)ai->ai_addrlen); if (err < 0) { RETURN_IO_ERROR("bind failed"); } - err = dbgsysListen(serverSocketFD, 1); + err = dbgsysListen(*socket, 1); // only 1 debugger can attach if (err < 0) { RETURN_IO_ERROR("listen failed"); } { char buf[20]; - socklen_t len = sizeof(sa); + struct sockaddr_storage addr; + socklen_t len = sizeof(addr); jint portNum; - err = dbgsysGetSocketName(serverSocketFD, - (struct sockaddr *)&sa, &len); - portNum = dbgsysNetworkToHostShort(sa.sin_port); + err = dbgsysGetSocketName(*socket, (struct sockaddr *)&addr, &len); + if (err != 0) { + RETURN_IO_ERROR("getsockname failed"); + } + + portNum = getPort((struct sockaddr *)&addr); sprintf(buf, "%d", portNum); *actualAddress = (*callback->alloc)((int)strlen(buf) + 1); if (*actualAddress == NULL) { @@ -561,13 +630,63 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, return JDWPTRANSPORT_ERROR_NONE; } +static jdwpTransportError JNICALL +socketTransport_startListening(jdwpTransportEnv* env, const char* address, + char** actualAddress) +{ + int err; + struct addrinfo *addrInfo = NULL; + struct addrinfo *listenAddr = NULL; + + /* no address provided */ + if ((address == NULL) || (address[0] == '\0')) { + address = "0"; + } + + err = parseAddress(address, &addrInfo); + if (err != JDWPTRANSPORT_ERROR_NONE) { + return err; + } + + /* 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest */ + for (int pass = 0; pass < 2 && listenAddr == NULL; pass++) { + for (struct addrinfo *ai = addrInfo; ai != NULL; ai = ai->ai_next) { + if ((pass == 0 && ai->ai_family == preferredAddressFamily) || + (pass == 1 && ai->ai_family != preferredAddressFamily)) + { + listenAddr = ai; + break; + } + } + } + + if (listenAddr == NULL) { + dbgsysFreeAddrInfo(addrInfo); + RETURN_ERROR(JDWPTRANSPORT_ERROR_INTERNAL, "listen failed: wrong address"); + } + + err = startListening(listenAddr, &serverSocketFD, actualAddress); + + dbgsysFreeAddrInfo(addrInfo); + + if (err != JDWPTRANSPORT_ERROR_NONE) { + if (serverSocketFD >= 0) { + dbgsysSocketClose(serverSocketFD); + serverSocketFD = -1; + } + return err; + } + + return JDWPTRANSPORT_ERROR_NONE; +} + static jdwpTransportError JNICALL socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handshakeTimeout) { - socklen_t socketLen; int err = JDWPTRANSPORT_ERROR_NONE; - struct sockaddr_in socket; - jlong startTime = (jlong)0; + struct sockaddr_storage clientAddr; + socklen_t clientAddrLen; + jlong startTime = 0; /* * Use a default handshake timeout if not specified - this avoids an indefinite @@ -605,11 +724,10 @@ socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handsha /* * Accept the connection */ - memset((void *)&socket,0,sizeof(struct sockaddr_in)); - socketLen = sizeof(socket); + clientAddrLen = sizeof(clientAddr); socketFD = dbgsysAccept(serverSocketFD, - (struct sockaddr *)&socket, - &socketLen); + (struct sockaddr *)&clientAddr, + &clientAddrLen); /* set the last error here as could be overridden by configureBlocking */ if (socketFD < 0) { setLastError(JDWPTRANSPORT_ERROR_IO_ERROR, "accept failed"); @@ -632,12 +750,14 @@ socketTransport_accept(jdwpTransportEnv* env, jlong acceptTimeout, jlong handsha * Verify that peer is allowed to connect. */ if (_peers_cnt > 0) { - if (!isPeerAllowed(&socket)) { + if (!isPeerAllowed(&clientAddr)) { char ebuf[64] = { 0 }; - char buf[INET_ADDRSTRLEN] = { 0 }; - const char* addr_str = inet_ntop(AF_INET, &(socket.sin_addr), buf, INET_ADDRSTRLEN); + char addrStr[INET_ADDRSTRLEN] = { 0 }; + int err2 = getnameinfo((struct sockaddr *)&clientAddr, clientAddrLen, + addrStr, sizeof(addrStr), NULL, 0, + NI_NUMERICHOST); sprintf(ebuf, "ERROR: Peer not allowed to connect: %s\n", - (addr_str == NULL) ? "" : addr_str); + (err2 != 0) ? "" : addrStr); dbgsysSocketClose(socketFD); socketFD = -1; err = JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT; @@ -686,28 +806,19 @@ socketTransport_stopListening(jdwpTransportEnv *env) return JDWPTRANSPORT_ERROR_NONE; } -static jdwpTransportError JNICALL -socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout, - jlong handshakeTimeout) -{ - struct sockaddr_in sa; +/* + * Tries to connect to the specified addrinfo, returns connected socket. + * If the function fails and returned socket != -1, the socket should be closed. + */ +static jdwpTransportError connectToAddr(struct addrinfo *ai, jlong timeout, int *socket) { int err; - if (addressString == NULL || addressString[0] == '\0') { - RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing"); - } - - err = parseAddress(addressString, &sa); - if (err != JDWPTRANSPORT_ERROR_NONE) { - return err; - } - - socketFD = dbgsysSocket(AF_INET, SOCK_STREAM, 0); - if (socketFD < 0) { + *socket = dbgsysSocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (*socket < 0) { RETURN_IO_ERROR("unable to create socket"); } - err = setOptionsCommon(socketFD); + err = setOptionsCommon(ai->ai_family, socketFD); if (err) { return err; } @@ -722,13 +833,13 @@ socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong a * To do a timed connect we make the socket non-blocking * and poll with a timeout; */ - if (attachTimeout > 0) { + if (timeout > 0) { dbgsysConfigureBlocking(socketFD, JNI_FALSE); } - err = dbgsysConnect(socketFD, (struct sockaddr *)&sa, sizeof(sa)); - if (err == DBG_EINPROGRESS && attachTimeout > 0) { - err = dbgsysFinishConnect(socketFD, (long)attachTimeout); + err = dbgsysConnect(socketFD, ai->ai_addr, (socklen_t)ai->ai_addrlen); + if (err == DBG_EINPROGRESS && timeout > 0) { + err = dbgsysFinishConnect(socketFD, (long)timeout); if (err == DBG_ETIMEOUT) { dbgsysConfigureBlocking(socketFD, JNI_TRUE); @@ -736,10 +847,55 @@ socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong a } } - if (err < 0) { + if (err) { RETURN_IO_ERROR("connect failed"); } + return err; +} + + +static jdwpTransportError JNICALL +socketTransport_attach(jdwpTransportEnv* env, const char* addressString, jlong attachTimeout, + jlong handshakeTimeout) +{ + int err; + struct addrinfo *addrInfo = NULL; + + if (addressString == NULL || addressString[0] == '\0') { + RETURN_ERROR(JDWPTRANSPORT_ERROR_ILLEGAL_ARGUMENT, "address is missing"); + } + + err = parseAddress(addressString, &addrInfo); + if (err) { + return err; + } + + /* 1st pass - preferredAddressFamily (by default IPv4), 2nd pass - the rest */ + for (int pass = 0; pass < 2 && socketFD < 0; pass++) { + for (struct addrinfo *ai = addrInfo; ai != NULL; ai = ai->ai_next) { + if ((pass == 0 && ai->ai_family == preferredAddressFamily) || + (pass == 1 && ai->ai_family != preferredAddressFamily)) + { + err = connectToAddr(ai, attachTimeout, &socketFD); + if (err == JDWPTRANSPORT_ERROR_NONE) { + break; + } + if (socketFD >= 0) { + dbgsysSocketClose(socketFD); + socketFD = -1; + } + } + } + } + + freeaddrinfo(addrInfo); + + /* err from the last connectToAddr() call */ + if (err != 0) { + return err; + } + if (attachTimeout > 0) { dbgsysConfigureBlocking(socketFD, JNI_TRUE); } @@ -1010,7 +1166,7 @@ socketTransport_setConfiguration(jdwpTransportEnv* env, jdwpTransportConfigurati "allow option '*' cannot be expanded"); } } else { - int err = parseAllowedPeers(allowed_peers); + int err = parseAllowedPeers(allowed_peers, len); if (err != JDWPTRANSPORT_ERROR_NONE) { return err; } @@ -1019,10 +1175,46 @@ socketTransport_setConfiguration(jdwpTransportEnv* env, jdwpTransportConfigurati return JDWPTRANSPORT_ERROR_NONE; } +/* + * Reads boolean system value, sets *result to + * - trueValue if the property is "true"; + * - falseValue if the property is "false". + * Doesn't change *result if the property is not set or failed to read. + */ +static int readBooleanSysProp(int *result, int trueValue, int falseValue, + JNIEnv* jniEnv, jclass sysClass, jmethodID getPropMethod, const char *propName) +{ + jstring value; + jstring name = (*jniEnv)->NewStringUTF(jniEnv, propName); + + if (name == NULL) { + return JNI_ERR; + } + value = (jstring)(*jniEnv)->CallStaticObjectMethod(jniEnv, sysClass, getPropMethod, name); + if ((*jniEnv)->ExceptionCheck(jniEnv)) { + return JNI_ERR; + } + if (value != NULL) { + const char *theValue = (*jniEnv)->GetStringUTFChars(jniEnv, value, NULL); + if (theValue == NULL) { + return JNI_ERR; + } + if (strcmp(theValue, "true") == 0) { + *result = trueValue; + } else if (strcmp(theValue, "false") == 0) { + *result = falseValue; + } + (*jniEnv)->ReleaseStringUTFChars(jniEnv, value, theValue); + } + return JNI_OK; +} + JNIEXPORT jint JNICALL jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr, jint version, jdwpTransportEnv** env) { + JNIEnv* jniEnv = NULL; + if (version < JDWPTRANSPORT_VERSION_1_0 || version > JDWPTRANSPORT_VERSION_1_1) { return JNI_EVERSION; @@ -1055,5 +1247,33 @@ jdwpTransport_OnLoad(JavaVM *vm, jdwpTransportCallback* cbTablePtr, /* initialized TLS */ tlsIndex = dbgsysTlsAlloc(); + + // retrieve network-related system properties + do { + jclass sysClass; + jmethodID getPropMethod; + if ((*vm)->GetEnv(vm, (void **)&jniEnv, JNI_VERSION_9) != JNI_OK) { + break; + } + sysClass = (*jniEnv)->FindClass(jniEnv, "java/lang/System"); + if (sysClass == NULL) { + break; + } + getPropMethod = (*jniEnv)->GetStaticMethodID(jniEnv, sysClass, + "getProperty", "(Ljava/lang/String;)Ljava/lang/String;"); + if (getPropMethod == NULL) { + break; + } + readBooleanSysProp(&allowOnlyIPv4, 1, 0, + jniEnv, sysClass, getPropMethod, "java.net.preferIPv4Stack"); + readBooleanSysProp(&preferredAddressFamily, AF_INET6, AF_INET, + jniEnv, sysClass, getPropMethod, "java.net.preferIPv6Addresses"); + } while (0); + + if (jniEnv != NULL && (*jniEnv)->ExceptionCheck(jniEnv)) { + (*jniEnv)->ExceptionClear(jniEnv); + } + + return JNI_OK; } diff --git a/src/jdk.jdwp.agent/share/native/libdt_socket/sysSocket.h b/src/jdk.jdwp.agent/share/native/libdt_socket/sysSocket.h index faffdf14cc6..340ebd0b3fa 100644 --- a/src/jdk.jdwp.agent/share/native/libdt_socket/sysSocket.h +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/sysSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -47,11 +47,11 @@ int dbgsysRecvFrom(int fd, char *buf, size_t nBytes, int flags, struct sockaddr int dbgsysListen(int fd, int backlog); int dbgsysRecv(int fd, char *buf, size_t nBytes, int flags); int dbgsysSend(int fd, char *buf, size_t nBytes, int flags); -int dbgsysGetAddrInfo(char *hostname, char *service, struct addrinfo *hints, struct addrinfo **results); +int dbgsysGetAddrInfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **results); +void dbgsysFreeAddrInfo(struct addrinfo *info); int dbgsysSocket(int domain, int type, int protocol); int dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen); int dbgsysSetSocketOption(int fd, jint cmd, jboolean on, jvalue value); -uint32_t dbgsysInetAddr(const char* cp); uint32_t dbgsysHostToNetworkLong(uint32_t hostlong); unsigned short dbgsysHostToNetworkShort(unsigned short hostshort); uint32_t dbgsysNetworkToHostLong(uint32_t netlong); diff --git a/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c b/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c index 193a8631431..05cb3116abb 100644 --- a/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c +++ b/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -127,12 +127,17 @@ dbgsysSend(int fd, char *buf, size_t nBytes, int flags) { } int -dbgsysGetAddrInfo(char *hostname, char *service, - struct addrinfo *hints, +dbgsysGetAddrInfo(const char *hostname, const char *service, + const struct addrinfo *hints, struct addrinfo **results) { return getaddrinfo(hostname, service, hints, results); } +void +dbgsysFreeAddrInfo(struct addrinfo *info) { + freeaddrinfo(info); +} + unsigned short dbgsysHostToNetworkShort(unsigned short hostshort) { return htons(hostshort); @@ -163,11 +168,6 @@ dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) { return bind(fd, name, namelen); } -uint32_t -dbgsysInetAddr(const char* cp) { - return (uint32_t)inet_addr(cp); -} - uint32_t dbgsysHostToNetworkLong(uint32_t hostlong) { return htonl(hostlong); diff --git a/src/jdk.jdwp.agent/windows/native/libdt_socket/socket_md.c b/src/jdk.jdwp.agent/windows/native/libdt_socket/socket_md.c index 6524ff9522a..63f4bce61f7 100644 --- a/src/jdk.jdwp.agent/windows/native/libdt_socket/socket_md.c +++ b/src/jdk.jdwp.agent/windows/native/libdt_socket/socket_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -199,10 +199,15 @@ dbgsysSend(int fd, char *buf, size_t nBytes, int flags) { } int -dbgsysGetAddrInfo(char *hostname, char *service, - struct addrinfo *hints, +dbgsysGetAddrInfo(const char *hostname, const char *service, + const struct addrinfo *hints, struct addrinfo **result) { - return getaddrinfo(hostname, service, hints, result); + return getaddrinfo(hostname, service, hints, result); +} + +void +dbgsysFreeAddrInfo(struct addrinfo *info) { + freeaddrinfo(info); } unsigned short @@ -214,7 +219,7 @@ int dbgsysSocket(int domain, int type, int protocol) { int fd = (int)socket(domain, type, protocol); if (fd != SOCKET_ERROR) { - SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); + SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE); } return fd; } @@ -240,15 +245,6 @@ dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) { } -uint32_t -dbgsysInetAddr(const char* cp) { - uint32_t addr; - if (inet_pton(AF_INET, cp, &addr) < 1) { - return -1; - } - return addr; -} - uint32_t dbgsysHostToNetworkLong(uint32_t hostlong) { return (uint32_t)htonl((u_long)hostlong); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ListeningConnector/startListening/startlis001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ListeningConnector/startListening/startlis001.java index 3efc60b46e0..877b17cd7f9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ListeningConnector/startListening/startlis001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ListeningConnector/startListening/startlis001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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,9 +32,12 @@ import java.io.*; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Arrays; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import nsk.share.*; import nsk.share.jpda.*; @@ -85,7 +88,6 @@ public class startlis001 { private int runIt(String argv[], PrintStream out) { String port; String addr; - InetAddress inetAddr = null; ArgumentHandler argHandler = new ArgumentHandler(argv); // pass if CONNECTOR_NAME is not implemented @@ -97,34 +99,40 @@ public class startlis001 { long timeout = argHandler.getWaitTime() * 60 * 1000; -/* Check that listening address returned by ListeningConnector.startListening() - matches the address which was set via connector's arguments */ + /* Check that listening address returned by ListeningConnector.startListening() + * matches the address which was set via connector's arguments. + * Empty host address causes listening for local connections only (loopback interface). + * */ + String hostname = "localhost"; + List validAddresses = new LinkedList<>(); + validAddresses.add(hostname); try { - inetAddr = InetAddress.getLocalHost(); + Arrays.stream(InetAddress.getAllByName(hostname)) + .forEach(address -> validAddresses.add(address.getHostAddress())); } catch (UnknownHostException e) { log.complain("FAILURE: caught UnknownHostException " + - e.getMessage()); + e.getMessage()); totalRes = false; } - String hostname = inetAddr.getHostName(); - String ip = inetAddr.getHostAddress(); + port = argHandler.getTransportPortIfNotDynamic(); initConnector(port); if ((addr = startListen()) == null) { log.complain("Test case #1 FAILED: unable to start listening"); totalRes = false; - } - else { + } else { + String validAddrList = validAddresses.stream() + .map(value -> value + ":" + port) + .collect(Collectors.joining(" or ")); log.display("Test case #1: start listening the address " + addr); - log.display("Expected address: "+ hostname + ":" + port + - "\n\tor "+ ip + ":" + port); - if ( (!addr.startsWith(hostname) && !addr.startsWith(ip)) || - (port != null && !addr.endsWith(port)) ) { + log.display("Expected addresses: " + validAddrList); + final String listenAddr = addr; + boolean isValid = validAddresses.stream() + .anyMatch(value -> listenAddr.startsWith(value) && (port == null || listenAddr.endsWith(port))); + if (!isValid) { log.complain("Test case #1 FAILED: listening address " + addr + - "\ndoes not match expected address:\n" + - hostname + ":" + port + " or " + - ip + ":" + port); + "\ndoes not match expected address:\n" + validAddrList); totalRes = false; } if (!stopListen()) { @@ -135,8 +143,8 @@ public class startlis001 { log.display("Test case #1 PASSED: listening address matches expected address"); } -/* Check that an address generated by ListeningConnector.startListening() - is valid i.e. debugee VM is accessible via this address */ + /* Check that an address generated by ListeningConnector.startListening() + is valid i.e. debugee VM is accessible via this address */ initConnector(null); if ((addr = startListen()) == null) { log.complain("Test case #2 FAILED: unable to start listening"); diff --git a/test/jdk/com/sun/jdi/BasicJDWPConnectionTest.java b/test/jdk/com/sun/jdi/JdwpAllowTest.java similarity index 60% rename from test/jdk/com/sun/jdi/BasicJDWPConnectionTest.java rename to test/jdk/com/sun/jdi/JdwpAllowTest.java index a26cfb1ca51..561df2d6e6e 100644 --- a/test/jdk/com/sun/jdi/BasicJDWPConnectionTest.java +++ b/test/jdk/com/sun/jdi/JdwpAllowTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019, 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,11 +25,12 @@ * @test * @summary Smoke test for JDWP hardening * @library /test/lib - * @run driver BasicJDWPConnectionTest + * @run driver JdwpAllowTest */ import java.io.IOException; +import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; @@ -37,24 +38,28 @@ import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class BasicJDWPConnectionTest { +public class JdwpAllowTest { public static int handshake(int port) throws IOException { // Connect to the debuggee and handshake int res = -1; Socket s = null; try { - s = new Socket("localhost", port); + s = new Socket(localAddr, port); s.getOutputStream().write("JDWP-Handshake".getBytes("UTF-8")); byte[] buffer = new byte[24]; res = s.getInputStream().read(buffer); } catch (SocketException ex) { + ex.printStackTrace(); // pass } finally { if (s != null) { @@ -68,7 +73,8 @@ public class BasicJDWPConnectionTest { ArrayList cmd = new ArrayList<>(); String jdwpArgs = "-agentlib:jdwp=transport=dt_socket,server=y," + - "suspend=n,address=*:0" + allowOpt; + "suspend=n,address=*:0" + + (allowOpt == null ? "" : ",allow=" + allowOpt); cmd.add(jdwpArgs); return cmd; } @@ -153,68 +159,102 @@ public class BasicJDWPConnectionTest { throw new RuntimeException(testName + " FAILED"); } - public static void DefaultTest() throws InterruptedException, IOException { - // No allow option is the same as the allow option ',allow=*' is passed - String allowOpt = ""; - positiveTest("DefaultTest", allowOpt); + /* + * Generate allow address by changing random bit in the local address + * and calculate 2 masks (prefix length) - one is matches original local address + * and another doesn't. + */ + private static class MaskTest { + public final String localAddress; + public final String allowAddress; + public final int prefixLengthGood; + public final int prefixLengthBad; + + public MaskTest(InetAddress addr) throws Exception { + localAddress = addr.getHostAddress(); + byte[] bytes = addr.getAddress(); + Random r = new Random(); + // prefix length must be >= 1, so bitToChange must be >= 2 + int bitToChange = r.nextInt(bytes.length * 8 - 3) + 2; + setBit(bytes, bitToChange, !getBit(bytes, bitToChange)); + // clear rest of the bits for mask address + for (int i = bitToChange + 1; i < bytes.length * 8; i++) { + setBit(bytes, i, false); + } + allowAddress = InetAddress.getByAddress(bytes).getHostAddress(); + + prefixLengthBad = bitToChange; + prefixLengthGood = bitToChange - 1; + } + + private static boolean getBit(byte[] bytes, int pos) { + return (bytes[pos / 8] & (1 << (7 - (pos % 8)))) != 0; + } + + private static void setBit(byte[] bytes, int pos, boolean value) { + byte byteValue = (byte)(1 << (7 - (pos % 8))); + if (value) { + bytes[pos / 8] = (byte)(bytes[pos / 8] | byteValue); + } else { + bytes[pos / 8] &= (~byteValue); + } + } } - static void ExplicitDefaultTest() throws InterruptedException, IOException { - // Explicit permission for connections from everywhere - String allowOpt = ",allow=*"; - positiveTest("ExplicitDefaultTest" ,allowOpt); - } + private static String localAddr; + private static List maskTests = new LinkedList<>(); - public static void AllowTest() throws InterruptedException, IOException { - String allowOpt = ",allow=127.0.0.1"; - positiveTest("AllowTest", allowOpt); - } + private static void init() throws Exception { + InetAddress addrs[] = InetAddress.getAllByName("localhost"); + if (addrs.length == 0) { + throw new RuntimeException("No addresses is returned for 'localhost'"); + } + localAddr = addrs[0].getHostAddress(); + System.err.println("localhost address: " + localAddr); - public static void MultiAllowTest() throws InterruptedException, IOException { - String allowOpt = ",allow=127.0.0.1+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24"; - positiveTest("MultiAllowTest", allowOpt); - } - - public static void DenyTest() throws InterruptedException, IOException { - // Bad allow address - String allowOpt = ",allow=0.0.0.0"; - negativeTest("DenyTest", allowOpt); - } - - public static void MultiDenyTest() throws InterruptedException, IOException { - // Wrong separator ';' is used for allow option - String allowOpt = ",allow=127.0.0.1;192.168.0.0/24"; - badAllowOptionTest("MultiDenyTest", allowOpt); - } - - public static void EmptyAllowOptionTest() throws InterruptedException, IOException { - // Empty allow option - String allowOpt = ",allow="; - badAllowOptionTest("EmptyAllowOptionTest", allowOpt); - } - - public static void ExplicitMultiDefault1Test() throws InterruptedException, IOException { - // Bad mix of allow option '*' with address value - String allowOpt = ",allow=*+allow=127.0.0.1"; - badAllowOptionTest("ExplicitMultiDefault1Test", allowOpt); - } - - public static void ExplicitMultiDefault2Test() throws InterruptedException, IOException { - // Bad mix of allow address value with '*' - String allowOpt = ",allow=allow=127.0.0.1+*"; - badAllowOptionTest("ExplicitMultiDefault2Test", allowOpt); + for (int i = 0; i < addrs.length; i++) { + maskTests.add(new MaskTest(addrs[i])); + } } public static void main(String[] args) throws Exception { - DefaultTest(); - ExplicitDefaultTest(); - AllowTest(); - MultiAllowTest(); - DenyTest(); - MultiDenyTest(); - EmptyAllowOptionTest(); - ExplicitMultiDefault1Test(); - ExplicitMultiDefault2Test(); + init(); + + // No allow option is the same as the allow option ',allow=*' is passed + positiveTest("DefaultTest", null); + + // Explicit permission for connections from everywhere + positiveTest("ExplicitDefaultTest", "*"); + + positiveTest("AllowTest", localAddr); + + positiveTest("MultiAllowTest", localAddr + "+10.0.0.0/8+172.16.0.0/12+192.168.0.0/24"); + + // Bad allow address + negativeTest("DenyTest", "0.0.0.0"); + + // Wrong separator ';' is used for allow option + badAllowOptionTest("MultiDenyTest", localAddr + ";192.168.0.0/24"); + + // Empty allow option + badAllowOptionTest("EmptyAllowOptionTest", ""); + + // Bad mix of allow option '*' with address value + badAllowOptionTest("ExplicitMultiDefault1Test", "*+" + localAddr); + + // Bad mix of allow address value with '*' + badAllowOptionTest("ExplicitMultiDefault2Test", localAddr + "+*"); + + for (MaskTest test: maskTests) { + // override localAddr (to connect to required IPv4 or IPv6 address) + localAddr = test.localAddress; + positiveTest("PositiveMaskTest(" + test.localAddress + ")", + test.allowAddress + "/" + test.prefixLengthGood); + positiveTest("NegativeMaskTest(" + test.localAddress + ")", + test.allowAddress + "/" + test.prefixLengthBad); + } + System.err.println("\nTest PASSED"); } + } diff --git a/test/jdk/com/sun/jdi/JdwpAttachTest.java b/test/jdk/com/sun/jdi/JdwpAttachTest.java new file mode 100644 index 00000000000..a76ff6569c9 --- /dev/null +++ b/test/jdk/com/sun/jdi/JdwpAttachTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2019, 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 com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.ListeningConnector; +import jdk.test.lib.apps.LingeredApp; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @bug 8184770 + * @summary Tests for JDWP agent attach functionality (including IPv6 support) + * @library /test/lib + * + * @build HelloWorld JdwpAttachTest + * @run main/othervm JdwpAttachTest + */ +public class JdwpAttachTest { + + public static void main(String[] args) throws Exception { + List addresses = getAddresses(); + + boolean ipv4EnclosedTested = false; + boolean ipv6EnclosedTested = false; + for (InetAddress addr: addresses) { + // also test that addresses enclosed in square brackets are supported + attachTest(addr.getHostAddress(), addr.getHostAddress()); + // listening on "*" should accept connections from all addresses + attachTest("*", addr.getHostAddress()); + + // test that addresses enclosed in square brackets are supported. + if (addr instanceof Inet4Address && !ipv4EnclosedTested) { + attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]"); + ipv4EnclosedTested = true; + } + if (addr instanceof Inet6Address && !ipv6EnclosedTested) { + attachTest("[" + addr.getHostAddress() + "]", "[" + addr.getHostAddress() + "]"); + ipv6EnclosedTested = true; + } + } + + // by using "localhost" or empty hostname + // we should be able to attach to both IPv4 and IPv6 addresses (127.0.0.1 & ::1) + InetAddress localAddresses[] = InetAddress.getAllByName("localhost"); + for (int i = 0; i < localAddresses.length; i++) { + attachTest(localAddresses[i].getHostAddress(), ""); + } + } + + private static void attachTest(String listenAddress, String connectAddresses) + throws Exception { + log("Starting listening at " + listenAddress); + ListeningConnector connector = getListenConnector(); + Map args = connector.defaultArguments(); + setConnectorArg(args, "localAddress", listenAddress); + setConnectorArg(args, "port", "0"); + + String actualAddress = connector.startListening(args); + String actualPort = actualAddress.substring(actualAddress.lastIndexOf(':') + 1); + String port = args.get("port").value(); + // port from connector.startListening must be the same as values from arguments + if (!port.equals(actualPort)) { + throw new RuntimeException("values from connector.startListening (" + actualPort + + " is not equal to values from arguments (" + port + ")"); + } + log("Listening port: " + port); + + log("Attaching from " + connectAddresses); + try { + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.submit((Callable)() -> { + VirtualMachine vm = connector.accept(args); + log("ACCEPTED."); + vm.dispose(); + return null; + }); + executor.shutdown(); + + LingeredApp debuggee = LingeredApp.startApp( + Arrays.asList("-agentlib:jdwp=transport=dt_socket" + +",address=" + connectAddresses + ":" + port + + ",server=n,suspend=n")); + debuggee.stopApp(); + + executor.awaitTermination(20, TimeUnit.SECONDS); + } finally { + connector.stopListening(args); + } + } + + private static List getAddresses() { + List result = new LinkedList<>(); + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface iface = networkInterfaces.nextElement(); + try { + if (iface.isUp()) { + Enumeration addresses = iface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress addr = addresses.nextElement(); + // Java reports link local addresses with named scope, + // but Windows sockets routines support only numeric scope id. + // skip such addresses. + if (addr instanceof Inet6Address) { + Inet6Address addr6 = (Inet6Address)addr; + if (addr6.getScopedInterface() != null) { + continue; + } + } + log(" - (" + addr.getClass().getSimpleName() + ") " + addr.getHostAddress()); + result.add(addr); + } + } + } catch (SocketException e) { + log("Interface " + iface.getDisplayName() + ": failed to get addresses"); + } + } + } catch (SocketException e) { + log("Interface enumeration error: " + e); + } + return result; + } + + private static String LISTEN_CONNECTOR = "com.sun.jdi.SocketListen"; + + private static ListeningConnector getListenConnector() { + return (ListeningConnector)getConnector(LISTEN_CONNECTOR); + } + + private static Connector getConnector(String name) { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + for (Iterator iter = connectors.iterator(); iter.hasNext(); ) { + Connector connector = iter.next(); + if (connector.name().equalsIgnoreCase(name)) { + return connector; + } + } + throw new IllegalArgumentException("Connector " + name + " not found"); + } + + private static void setConnectorArg(Map args, String name, String value) { + Connector.Argument arg = args.get(name); + if (arg == null) { + throw new IllegalArgumentException("Argument " + name + " is not defined"); + } + arg.setValue(value); + } + + private static void log(Object o) { + System.out.println(String.valueOf(o)); + } + +} diff --git a/test/jdk/com/sun/jdi/JdwpListenTest.java b/test/jdk/com/sun/jdi/JdwpListenTest.java new file mode 100644 index 00000000000..a0e52638b0c --- /dev/null +++ b/test/jdk/com/sun/jdi/JdwpListenTest.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2019, 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 com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import lib.jdb.Debuggee; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/* + * @test + * @bug 8184770 + * @summary Tests for JDWP agent listen functionality (including IPv6 support) + * @library /test/lib + * + * @build HelloWorld JdwpListenTest + * @run main/othervm JdwpListenTest + */ +public class JdwpListenTest { + + public static void main(String[] args) throws Exception { + List addresses = getAddresses(); + + boolean ipv4EnclosedTested = false; + boolean ipv6EnclosedTested = false; + for (InetAddress listen: addresses) { + for (InetAddress attach: addresses) { + // can connect only from the same address + // IPv6 cannot connect to IPv4 (::1 to 127.0.0.1) and vice versa. + listenTest(listen.getHostAddress(), attach.getHostAddress(), attach.equals(listen)); + } + // test that addresses enclosed in square brackets are supported. + if (listen instanceof Inet4Address && !ipv4EnclosedTested) { + listenTest("[" + listen.getHostAddress() + "]", "[" + listen.getHostAddress() + "]", true); + ipv4EnclosedTested = true; + } + if (listen instanceof Inet6Address && !ipv6EnclosedTested) { + listenTest("[" + listen.getHostAddress() + "]", "[" + listen.getHostAddress() + "]", true); + ipv6EnclosedTested = true; + } + } + // listen on "*" - should be accessible from any address + for (InetAddress attach: addresses) { + listenTest("*", attach.getHostAddress(), true); + } + } + + private static void listenTest(String listenAddress, String connectAddress, boolean expectedResult) + throws IOException { + log("Starting listening debuggee at " + listenAddress); + try (Debuggee debuggee = Debuggee.launcher("HelloWorld").setAddress(listenAddress + ":0").launch()) { + log("Debuggee is listening on " + listenAddress + ":" + debuggee.getAddress()); + log("Connecting from " + connectAddress + ", expected: " + (expectedResult ? "SUCCESS" : "FAILURE")); + try { + VirtualMachine vm = attach(connectAddress, debuggee.getAddress()); + vm.dispose(); + if (!expectedResult) { + throw new RuntimeException("ERROR: attached successfully"); + } + } catch (IOException ex) { + if (expectedResult) { + throw new RuntimeException("ERROR: failed to attach", ex); + } + } + } + } + + private static List getAddresses() { + List result = new LinkedList<>(); + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface iface = networkInterfaces.nextElement(); + try { + if (iface.isUp()) { + Enumeration addresses = iface.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress addr = addresses.nextElement(); + // Java reports link local addresses with named scope, + // but Windows sockets routines support only numeric scope id. + // skip such addresses. + if (addr instanceof Inet6Address) { + Inet6Address addr6 = (Inet6Address)addr; + if (addr6.getScopedInterface() != null) { + continue; + } + } + log(" - (" + addr.getClass().getSimpleName() + ") " + addr.getHostAddress()); + result.add(addr); + } + } + } catch (SocketException e) { + log("Interface " + iface.getDisplayName() + ": failed to get addresses"); + } + } + } catch (SocketException e) { + log("Interface enumeration error: " + e); + } + return result; + } + + private static String ATTACH_CONNECTOR = "com.sun.jdi.SocketAttach"; + // cache socket attaching connector + private static AttachingConnector attachingConnector; + + private static VirtualMachine attach(String address, String port) throws IOException { + if (attachingConnector == null) { + attachingConnector = (AttachingConnector)getConnector(ATTACH_CONNECTOR); + } + Map args = attachingConnector.defaultArguments(); + setConnectorArg(args, "hostname", address); + setConnectorArg(args, "port", port); + try { + return attachingConnector.attach(args); + } catch (IllegalConnectorArgumentsException e) { + // unexpected.. wrap in RuntimeException + throw new RuntimeException(e); + } + } + + private static Connector getConnector(String name) { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + for (Iterator iter = connectors.iterator(); iter.hasNext(); ) { + Connector connector = iter.next(); + if (connector.name().equalsIgnoreCase(name)) { + return connector; + } + } + throw new IllegalArgumentException("Connector " + name + " not found"); + } + + private static void setConnectorArg(Map args, String name, String value) { + Connector.Argument arg = args.get(name); + if (arg == null) { + throw new IllegalArgumentException("Argument " + name + " is not defined"); + } + arg.setValue(value); + } + + private static void log(Object o) { + System.out.println(String.valueOf(o)); + } + +} diff --git a/test/jdk/com/sun/jdi/JdwpNetProps.java b/test/jdk/com/sun/jdi/JdwpNetProps.java new file mode 100644 index 00000000000..27769278b0c --- /dev/null +++ b/test/jdk/com/sun/jdi/JdwpNetProps.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2019, 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 com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import lib.jdb.Debuggee; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/* + * @test + * @bug 8184770 + * @summary Tests that JDWP agent honors jdk net properties + * @library /test/lib + * + * @build HelloWorld JdwpNetProps + * @run main/othervm JdwpNetProps + */ +public class JdwpNetProps { + + public static void main(String[] args) throws Exception { + InetAddress addrs[] = InetAddress.getAllByName("localhost"); + InetAddress ipv4Address = null; + InetAddress ipv6Address = null; + for (int i = 0; i < addrs.length; i++) { + if (addrs[i] instanceof Inet4Address) { + ipv4Address = addrs[i]; + } else if (addrs[i] instanceof Inet6Address) { + ipv6Address = addrs[i]; + } + } + + if (ipv4Address != null) { + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(true) + .run(TestResult.Success); + new ListenTest("localhost", ipv4Address) + .preferIPv4Stack(false) + .run(TestResult.Success); + if (ipv6Address != null) { + // - only IPv4, so connection prom IPv6 should fail + new ListenTest("localhost", ipv6Address) + .preferIPv4Stack(true) + .preferIPv6Addresses(true) + .run(TestResult.AttachFailed); + // - listen on IPv4 + new ListenTest("localhost", ipv6Address) + .preferIPv6Addresses(false) + .run(TestResult.AttachFailed); + // - listen on IPv6 + new ListenTest("localhost", ipv6Address) + .preferIPv6Addresses(true) + .run(TestResult.Success); + } + } else { + // IPv6-only system - expected to fail on IPv4 address + new ListenTest("localhost", ipv6Address) + .preferIPv4Stack(true) + .run(TestResult.ListenFailed); + } + } + + private enum TestResult { + Success, + ListenFailed, + AttachFailed + } + + private static class ListenTest { + private final String listenAddress; + private final InetAddress connectAddress; + private Boolean preferIPv4Stack; + private Boolean preferIPv6Addresses; + public ListenTest(String listenAddress, InetAddress connectAddress) { + this.listenAddress = listenAddress; + this.connectAddress = connectAddress; + } + public ListenTest preferIPv4Stack(Boolean value) { + preferIPv4Stack = value; + return this; + } + public ListenTest preferIPv6Addresses(Boolean value) { + preferIPv6Addresses = value; + return this; + } + + public void run(TestResult expectedResult) throws Exception { + List options = new LinkedList<>(); + if (preferIPv4Stack != null) { + options.add("-Djava.net.preferIPv4Stack=" + preferIPv4Stack.toString()); + } + if (preferIPv6Addresses != null) { + options.add("-Djava.net.preferIPv6Addresses=" + preferIPv6Addresses.toString()); + } + log("Starting listening debuggee at " + listenAddress + + (expectedResult == TestResult.ListenFailed ? ": expected to fail" : "")); + Exception error = null; + try (Debuggee debuggee = Debuggee.launcher("HelloWorld") + .setAddress(listenAddress + ":0") + .addOptions(options).launch()) { + log("Debuggee is listening on " + listenAddress + ":" + debuggee.getAddress()); + log("Connecting from " + connectAddress.getHostAddress() + + ", expected: " + (expectedResult == TestResult.Success ? "Success" : "Failure")); + try { + VirtualMachine vm = attach(connectAddress.getHostAddress(), debuggee.getAddress()); + vm.dispose(); + if (expectedResult == TestResult.Success) { + log("Attached successfully (as expected)"); + } else { + error = new RuntimeException("ERROR: attached successfully"); + } + } catch (Exception ex) { + if (expectedResult == TestResult.AttachFailed) { + log("Attach failed (as expected)"); + } else { + error = new RuntimeException("ERROR: failed to attach", ex); + } + } + } catch (Exception ex) { + if (expectedResult == TestResult.ListenFailed) { + log("Listen failed (as expected)"); + } else { + error = new RuntimeException("ERROR: listen failed", ex); + } + } + if (error != null) { + throw error; + } + } + } + + private static String ATTACH_CONNECTOR = "com.sun.jdi.SocketAttach"; + // cache socket attaching connector + private static AttachingConnector attachingConnector; + + private static VirtualMachine attach(String address, String port) throws IOException { + if (attachingConnector == null) { + attachingConnector = (AttachingConnector)getConnector(ATTACH_CONNECTOR); + } + Map args = attachingConnector.defaultArguments(); + setConnectorArg(args, "hostname", address); + setConnectorArg(args, "port", port); + try { + return attachingConnector.attach(args); + } catch (IllegalConnectorArgumentsException e) { + // unexpected.. wrap in RuntimeException + throw new RuntimeException(e); + } + } + + private static Connector getConnector(String name) { + List connectors = Bootstrap.virtualMachineManager().allConnectors(); + for (Iterator iter = connectors.iterator(); iter.hasNext(); ) { + Connector connector = iter.next(); + if (connector.name().equalsIgnoreCase(name)) { + return connector; + } + } + throw new IllegalArgumentException("Connector " + name + " not found"); + } + + private static void setConnectorArg(Map args, String name, String value) { + Connector.Argument arg = args.get(name); + if (arg == null) { + throw new IllegalArgumentException("Argument " + name + " is not defined"); + } + arg.setValue(value); + } + + private static void log(Object o) { + System.out.println(String.valueOf(o)); + } + +} From e0a87ef8fcf35df77c3a4578723611cab32db07d Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 15 May 2019 19:09:54 +0100 Subject: [PATCH 006/263] 8223716: sun/net/www/http/HttpClient/MultiThreadTest.java should be more resilient to unexpected traffic Reviewed-by: chegar --- .../www/http/HttpClient/MultiThreadTest.java | 56 +++++++++++++++---- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/test/jdk/sun/net/www/http/HttpClient/MultiThreadTest.java b/test/jdk/sun/net/www/http/HttpClient/MultiThreadTest.java index 784e6d61187..97304867f66 100644 --- a/test/jdk/sun/net/www/http/HttpClient/MultiThreadTest.java +++ b/test/jdk/sun/net/www/http/HttpClient/MultiThreadTest.java @@ -42,6 +42,7 @@ import java.io.*; import java.time.Duration; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; public class MultiThreadTest extends Thread { @@ -60,13 +61,11 @@ public class MultiThreadTest extends Thread { System.out.println(msg); } - static int reqnum = 0; + static final AtomicInteger reqnum = new AtomicInteger(); void doRequest(String uri) throws Exception { - URL url = new URL(uri + "?foo="+reqnum); - reqnum ++; + URL url = new URL(uri + "?foo="+reqnum.getAndIncrement()); HttpURLConnection http = (HttpURLConnection)url.openConnection(); - InputStream in = http.getInputStream(); byte b[] = new byte[100]; int total = 0; @@ -159,12 +158,37 @@ public class MultiThreadTest extends Thread { int reqs = Worker.getRequests (); MultiThreadTest.debug("Requests = " + reqs); System.out.println ("Connection count = " + cnt + " Request count = " + reqs); - if (cnt > threads) { // could be less - throw new RuntimeException ("Expected "+threads + " connections: used " +cnt); + + // We may have received traffic from something else than + // our client. We should only count those workers for which + // the expected header has been found. + int validConnections = 0; + for (Worker w : svr.workers()) { + if (w.headerFound) validConnections++; } - if (reqs != threads*requests) { + + if (validConnections > threads + 1 || validConnections == 0) { // could be less + throw new RuntimeException ("Expected " + threads + " connections: used " + validConnections); + } + + // Sometimes the client drops a connection after a while and + // spawns a new one. Why this is happening is not clear, + // and JDK-8223783 is logged to follow up on this. For the sake + // of test stabilization we don't fail on `threads + 1` connections + // but log a warning instead. + if (validConnections == threads + 1) { + debug("WARNING: " + validConnections + + " have been used, where only " + threads + + " were expected!"); + } + + if (validConnections != cnt) { + debug("WARNING: got " + (cnt - validConnections) + " unexpected connections!"); + } + if (validConnections == cnt && reqs != threads*requests) { throw new RuntimeException ("Expected "+ threads*requests+ " requests: got " +reqs); } + for (Thread worker : svr.workers()) { worker.join(60_000); } @@ -181,7 +205,7 @@ public class MultiThreadTest extends Thread { ServerSocket ss; int connectionCount; boolean shutdown = false; - private Queue workers = new ConcurrentLinkedQueue<>(); + private final Queue workers = new ConcurrentLinkedQueue<>(); Server(ServerSocket ss) { this.ss = ss; @@ -258,8 +282,10 @@ public class MultiThreadTest extends Thread { class Worker extends Thread { Socket s; int id; + volatile boolean headerFound; Worker(Socket s, int id) { + super("Worker-" + id); this.s = s; this.id = id; } @@ -272,18 +298,20 @@ public class MultiThreadTest extends Thread { return requests; } } + public static void incRequests () { synchronized (rlock) { requests++; } } - int readUntil(InputStream in, char[] seq) throws IOException { + int readUntil(InputStream in, StringBuilder headers, char[] seq) throws IOException { int i=0, count=0; while (true) { int c = in.read(); if (c == -1) return -1; + headers.append((char)c); count++; if (c == seq[i]) { i++; @@ -312,14 +340,18 @@ public class MultiThreadTest extends Thread { // read entire request from client int n=0; - - n = readUntil(in, new char[] {'\r','\n', '\r','\n'}); - + StringBuilder headers = new StringBuilder(); + n = readUntil(in, headers, new char[] {'\r','\n', '\r','\n'}); if (n <= 0) { MultiThreadTest.debug("worker: " + id + ": Shutdown"); s.close(); return; } + if (headers.toString().contains("/foo.html?foo=")) { + headerFound = true; + } else { + MultiThreadTest.debug("worker: " + id + ": Unexpected request received: " + headers); + } MultiThreadTest.debug("worker " + id + ": Read request from client " + From 9e686ef2d19bfec76dd8c7e2638622cea6b366a5 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 15 May 2019 19:34:34 +0100 Subject: [PATCH 007/263] 8223880: Update sun/net/ftp/FtpURL.java and sun/net/ftp/FtpURLConnectionLeak.java to work with IPv6 addresses This fix updates three tests: sun/net/ftp/FtpURL.java, sun/net/ftp/FtpURLConnectionLeak.java, and sun/net/ftp/FtpGetContent.java, to work with IPv6 addresses Reviewed-by: chegar, aeubanks, vtewari --- test/jdk/sun/net/ftp/FtpGetContent.java | 71 ++++++++++++++++--- test/jdk/sun/net/ftp/FtpURL.java | 48 +++++++++++-- .../jdk/sun/net/ftp/FtpURLConnectionLeak.java | 3 +- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/test/jdk/sun/net/ftp/FtpGetContent.java b/test/jdk/sun/net/ftp/FtpGetContent.java index 8f712b41565..2e234d2a8a2 100644 --- a/test/jdk/sun/net/ftp/FtpGetContent.java +++ b/test/jdk/sun/net/ftp/FtpGetContent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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,6 +28,8 @@ import java.net.*; * @test * @bug 4255280 * @summary URL.getContent() loses first six bytes for ftp URLs + * @run main FtpGetContent + * @run main/othervm -Djava.net.preferIPv6Addresses=true FtpGetContent */ public class FtpGetContent { @@ -38,11 +40,12 @@ public class FtpGetContent { */ private class FtpServer extends Thread { - private ServerSocket server; + private final ServerSocket server; private int port; private boolean done = false; private boolean portEnabled = true; private boolean pasvEnabled = true; + private boolean extendedEnabled = true; private String username; private String password; private String cwd; @@ -77,9 +80,10 @@ public class FtpGetContent { private final int NLST = 15; private final int RNFR = 16; private final int RNTO = 17; + private final int EPSV = 18; String[] cmds = { "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE", "NOOP", "RETR", "PASV", "PORT", "LIST", "REIN", - "QUIT", "STOR", "NLST", "RNFR", "RNTO" }; + "QUIT", "STOR", "NLST", "RNFR", "RNTO", "EPSV"}; private String arg = null; private ServerSocket pasv = null; private int data_port = 0; @@ -91,6 +95,7 @@ public class FtpGetContent { */ private int parseCmd(String cmd) { + System.out.println("FTP server received command: " + cmd); if (cmd == null || cmd.length() < 3) return ERROR; int blank = cmd.indexOf(' '); @@ -248,14 +253,42 @@ public class FtpGetContent { case PWD: out.println("257 \"" + cwd + "\" is current directory"); break; + case EPSV: + if (!extendedEnabled || !pasvEnabled) { + out.println("500 EPSV is disabled, " + + "use PORT instead."); + continue; + } + if (!(server.getInetAddress() instanceof Inet6Address)) { + // pretend EPSV is not implemented + out.println("500 '" + str + "': command not understood."); + break; + } + if ("all".equalsIgnoreCase(arg)) { + out.println("200 EPSV ALL command successful."); + continue; + } + try { + if (pasv == null) + pasv = new ServerSocket(0, 0, server.getInetAddress()); + int port = pasv.getLocalPort(); + out.println("229 Entering Extended" + + " Passive Mode (|||" + port + "|)"); + } catch (IOException ssex) { + out.println("425 Can't build data connection:" + + " Connection refused."); + } + break; case PASV: if (!pasvEnabled) { out.println("500 PASV is disabled, use PORT instead."); continue; } try { - if (pasv == null) - pasv = new ServerSocket(0); + if (pasv == null) { + pasv = new ServerSocket(); + pasv.bind(new InetSocketAddress("127.0.0.1", 0)); + } int port = pasv.getLocalPort(); out.println("227 Entering Passive Mode (127,0,0,1," + (port >> 8) + "," + (port & 0xff) +")"); @@ -367,10 +400,16 @@ public class FtpGetContent { } public FtpServer(int port) { + this(null, 0); + } + + public FtpServer(InetAddress address, int port) { this.port = port; try { - server = new ServerSocket(port); + server = new ServerSocket(); + server.bind(new InetSocketAddress(address, port)); } catch (IOException e) { + throw new RuntimeException(e); } } @@ -384,6 +423,16 @@ public class FtpGetContent { return 0; } + public String getAuthority() { + InetAddress address = server.getInetAddress(); + String hostaddr = address.isAnyLocalAddress() + ? "localhost" : address.getHostAddress(); + if (hostaddr.indexOf(':') > -1) { + hostaddr = "[" + hostaddr +"]"; + } + return hostaddr + ":" + getPort(); + } + /** * A way to tell the server that it can stop. */ @@ -452,14 +501,16 @@ public class FtpGetContent { public FtpGetContent() throws Exception { FtpServer server = null; try { - server = new FtpServer(0); + InetAddress loopback = InetAddress.getLoopbackAddress(); + server = new FtpServer(loopback, 0); server.start(); - int port = server.getPort(); + String authority = server.getAuthority(); // Now let's check the URL handler - URL url = new URL("ftp://localhost:" + port + "/pub/BigFile"); - InputStream stream = (InputStream)url.getContent(); + URL url = new URL("ftp://" + authority + "/pub/BigFile"); + InputStream stream = (InputStream)url.openConnection(Proxy.NO_PROXY) + .getContent(); byte[] buffer = new byte[1024]; int totalBytes = 0; int bytesRead = stream.read(buffer); diff --git a/test/jdk/sun/net/ftp/FtpURL.java b/test/jdk/sun/net/ftp/FtpURL.java index c94516bde37..220eac13112 100644 --- a/test/jdk/sun/net/ftp/FtpURL.java +++ b/test/jdk/sun/net/ftp/FtpURL.java @@ -23,11 +23,16 @@ import java.io.*; import java.net.*; +import jdk.test.lib.net.IPSupport; /* * @test * @bug 4398880 * @summary FTP URL processing modified to conform to RFC 1738 + * @library /test/lib + * @run main/othervm FtpURL + * @run main/othervm -Djava.net.preferIPv4Stack=true FtpURL + * @run main/othervm -Djava.net.preferIPv6Addresses=true FtpURL */ public class FtpURL { @@ -41,6 +46,7 @@ public class FtpURL { private boolean done = false; private boolean portEnabled = true; private boolean pasvEnabled = true; + private boolean extendedEnabled = true; private String username; private String password; private String cwd; @@ -75,9 +81,10 @@ public class FtpURL { private final int NLST = 15; private final int RNFR = 16; private final int RNTO = 17; + private final int EPSV = 18; String[] cmds = { "USER", "PASS", "CWD", "CDUP", "PWD", "TYPE", "NOOP", "RETR", "PASV", "PORT", "LIST", "REIN", - "QUIT", "STOR", "NLST", "RNFR", "RNTO" }; + "QUIT", "STOR", "NLST", "RNFR", "RNTO", "EPSV" }; private String arg = null; private ServerSocket pasv = null; private int data_port = 0; @@ -89,6 +96,7 @@ public class FtpURL { */ private int parseCmd(String cmd) { + System.out.println("Received command: " + cmd); if (cmd == null || cmd.length() < 3) return ERROR; int blank = cmd.indexOf(' '); @@ -127,7 +135,7 @@ public class FtpURL { /** * Open the data socket with the client. This can be the - * result of a "PASV" or "PORT" command. + * result of a "EPSV", "PASV" or "PORT" command. */ protected OutputStream getOutDataStream() { @@ -247,6 +255,33 @@ public class FtpURL { case PWD: out.println("257 \"" + cwd + "\" is current directory"); break; + case EPSV: + if (!extendedEnabled || !pasvEnabled) { + out.println("500 EPSV is disabled, " + + "use PORT instead."); + continue; + } + if (!(server.getInetAddress() instanceof Inet6Address)) { + // pretend EPSV is not implemented + out.println("500 '" + str + "': command not understood."); + break; + } + if ("all".equalsIgnoreCase(arg)) { + out.println("200 EPSV ALL command successful."); + continue; + } + try { + if (pasv == null) + pasv = new ServerSocket(0, 0, server.getInetAddress()); + int port = pasv.getLocalPort(); + out.println("229 Entering Extended" + + " Passive Mode (|||" + port + "|)"); + } catch (IOException ssex) { + out.println("425 Can't build data connection:" + + " Connection refused."); + } + break; + case PASV: if (!pasvEnabled) { out.println("500 PASV is disabled, use PORT instead."); @@ -467,6 +502,7 @@ public class FtpURL { } } public static void main(String[] args) throws Exception { + IPSupport.throwSkippedExceptionIfNonOperational(); FtpURL test = new FtpURL(); } @@ -482,7 +518,7 @@ public class FtpURL { // Now let's check the URL handler URL url = new URL("ftp://user:password@" + authority + "/%2Fetc/motd;type=a"); - URLConnection con = url.openConnection(); + URLConnection con = url.openConnection(Proxy.NO_PROXY); in = new BufferedReader(new InputStreamReader(con.getInputStream())); String s; do { @@ -507,7 +543,7 @@ public class FtpURL { // Now let's check the URL handler url = new URL("ftp://user2@" + authority + "/%2Fusr/bin;type=d"); - con = url.openConnection(); + con = url.openConnection(Proxy.NO_PROXY); in = new BufferedReader(new InputStreamReader(con.getInputStream())); do { s = in.readLine(); @@ -523,9 +559,9 @@ public class FtpURL { // We're done! } catch (Exception e) { - throw new RuntimeException("FTP support error: " + e.getMessage()); + throw new RuntimeException("FTP support error: " + e.getMessage(), e); } finally { - try { in.close(); } catch (IOException unused) {} + try { in.close(); } catch (Exception unused) {} server.terminate(); server.server.close(); } diff --git a/test/jdk/sun/net/ftp/FtpURLConnectionLeak.java b/test/jdk/sun/net/ftp/FtpURLConnectionLeak.java index 570c4fccc33..91e258c86cc 100644 --- a/test/jdk/sun/net/ftp/FtpURLConnectionLeak.java +++ b/test/jdk/sun/net/ftp/FtpURLConnectionLeak.java @@ -34,6 +34,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.URL; +import java.net.Proxy; public class FtpURLConnectionLeak { @@ -48,7 +49,7 @@ public class FtpURLConnectionLeak { try (server) { for (int i = 0; i < 3; i++) { try { - InputStream stream = url.openStream(); + InputStream stream = url.openConnection(Proxy.NO_PROXY).getInputStream(); } catch (FileNotFoundException expected) { // should always reach this point since the path does not exist System.out.println("caught expected " + expected); From c9cdfad6ffb92fef2a9266942500c8904d1b1f5b Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Wed, 15 May 2019 19:47:28 +0100 Subject: [PATCH 008/263] 8223798: Replace wildcard address with loopback or local host in tests - part 7 Reviewed-by: dfuchs, vtewari --- test/jdk/java/net/Socket/DeadlockTest.java | 6 +- test/jdk/java/net/Socket/SocketGrowth.java | 9 +- .../asyncClose/DatagramSocket_receive.java | 14 ++- .../Socket_getInputStream_read.java | 6 +- .../Socket_getOutputStream_write.java | 4 +- .../HttpContinueStackOverflow.java | 19 +++- .../net/URLConnection/ResendPostBody.java | 16 ++- test/jdk/sun/net/ftp/MarkResetTest.java | 61 +++++++---- .../www/http/ChunkedOutputStream/Test.java | 100 +++++++++--------- .../sun/net/www/protocol/http/B6518816.java | 17 ++- .../www/protocol/http/ProxyTunnelServer.java | 13 ++- .../www/protocol/http/TunnelThroughProxy.java | 14 ++- 12 files changed, 176 insertions(+), 103 deletions(-) diff --git a/test/jdk/java/net/Socket/DeadlockTest.java b/test/jdk/java/net/Socket/DeadlockTest.java index 4378b698005..40b001171f1 100644 --- a/test/jdk/java/net/Socket/DeadlockTest.java +++ b/test/jdk/java/net/Socket/DeadlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2019, 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 @@ -39,7 +39,7 @@ public class DeadlockTest { public static void main(String [] argv) throws Exception { IPSupport.throwSkippedExceptionIfNonOperational(); - ServerSocket ss = new ServerSocket(0); + ServerSocket ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); Socket clientSocket = new Socket(); try { @@ -154,7 +154,7 @@ class ClientThread implements Runnable { try { System.out.println("About to connect the client socket"); this.sock = sock; - this.sock.connect(new InetSocketAddress("localhost", serverPort)); + this.sock.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), serverPort)); System.out.println("connected"); out = new ObjectOutputStream(sock.getOutputStream()); diff --git a/test/jdk/java/net/Socket/SocketGrowth.java b/test/jdk/java/net/Socket/SocketGrowth.java index 0290f81dec0..c01952483e8 100644 --- a/test/jdk/java/net/Socket/SocketGrowth.java +++ b/test/jdk/java/net/Socket/SocketGrowth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -29,15 +29,16 @@ */ import java.io.IOException; +import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; public class SocketGrowth { public static void main(String[] args) throws IOException { - - try (ServerSocket ss = new ServerSocket(0)) { - try (Socket s = new Socket("localhost", ss.getLocalPort()); + InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); + try (ServerSocket ss = new ServerSocket(0, 0, loopbackAddress)) { + try (Socket s = new Socket(loopbackAddress, ss.getLocalPort()); Socket peer = ss.accept()) { for (int i=0; i<1000000; i++) { // buggy JDK will run out of memory in this loop diff --git a/test/jdk/java/net/Socket/asyncClose/DatagramSocket_receive.java b/test/jdk/java/net/Socket/asyncClose/DatagramSocket_receive.java index 9094659d514..8182f0b77e5 100644 --- a/test/jdk/java/net/Socket/asyncClose/DatagramSocket_receive.java +++ b/test/jdk/java/net/Socket/asyncClose/DatagramSocket_receive.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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 @@ -27,11 +27,13 @@ */ import java.net.*; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; public class DatagramSocket_receive extends AsyncCloseTest implements Runnable { private final DatagramSocket s; private final int timeout; private final CountDownLatch latch; + private final AtomicBoolean readyToClose = new AtomicBoolean(false); public DatagramSocket_receive() throws SocketException { this(0); @@ -59,8 +61,13 @@ public class DatagramSocket_receive extends AsyncCloseTest implements Runnable { s.setSoTimeout(timeout); } latch.countDown(); - s.receive(p); - failed("DatagramSocket.receive(DatagramPacket) returned unexpectly!!" + " - " + p.getAddress()); + do { + // if readyToClose is still false it means some other + // process on the system attempted to send datagram packet: + // just ignore it, and go back to accept again. + s.receive(p); + } while (!readyToClose.get()); + failed("DatagramSocket.receive(DatagramPacket) returned unexpectedly!!" + " - " + p.getAddress()); } catch (SocketException se) { if (latch.getCount() != 1) { closed(); @@ -80,6 +87,7 @@ public class DatagramSocket_receive extends AsyncCloseTest implements Runnable { thr.start(); latch.await(); Thread.sleep(5000); //sleep, so receive(DatagramPacket) can block + readyToClose.set(true); s.close(); thr.join(); diff --git a/test/jdk/java/net/Socket/asyncClose/Socket_getInputStream_read.java b/test/jdk/java/net/Socket/asyncClose/Socket_getInputStream_read.java index 25f85898583..f2082fcf374 100644 --- a/test/jdk/java/net/Socket/asyncClose/Socket_getInputStream_read.java +++ b/test/jdk/java/net/Socket/asyncClose/Socket_getInputStream_read.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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 @@ -60,7 +60,7 @@ public class Socket_getInputStream_read extends AsyncCloseTest implements Runnab } latch.countDown(); int n = in.read(); - failed("Socket.getInputStream().read() returned unexpectly!!"); + failed("Socket.getInputStream().read() returned unexpectedly!!"); } catch (SocketException se) { if (latch.getCount() != 1) { closed(); @@ -76,8 +76,8 @@ public class Socket_getInputStream_read extends AsyncCloseTest implements Runnab public AsyncCloseTest go() { try { - ServerSocket ss = new ServerSocket(0); InetAddress lh = InetAddress.getLocalHost(); + ServerSocket ss = new ServerSocket(0, 0, lh); s.connect( new InetSocketAddress(lh, ss.getLocalPort()) ); Socket s2 = ss.accept(); Thread thr = new Thread(this); diff --git a/test/jdk/java/net/Socket/asyncClose/Socket_getOutputStream_write.java b/test/jdk/java/net/Socket/asyncClose/Socket_getOutputStream_write.java index 78cbf45014a..dc5eda06078 100644 --- a/test/jdk/java/net/Socket/asyncClose/Socket_getOutputStream_write.java +++ b/test/jdk/java/net/Socket/asyncClose/Socket_getOutputStream_write.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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,8 +65,8 @@ public class Socket_getOutputStream_write extends AsyncCloseTest implements Runn public AsyncCloseTest go() { try { - ServerSocket ss = new ServerSocket(0); InetAddress lh = InetAddress.getLocalHost(); + ServerSocket ss = new ServerSocket(0, 0, lh); s.connect( new InetSocketAddress(lh, ss.getLocalPort()) ); Socket s2 = ss.accept(); Thread thr = new Thread(this); diff --git a/test/jdk/java/net/URLConnection/HttpContinueStackOverflow.java b/test/jdk/java/net/URLConnection/HttpContinueStackOverflow.java index 5fe11730616..0e9759577b6 100644 --- a/test/jdk/java/net/URLConnection/HttpContinueStackOverflow.java +++ b/test/jdk/java/net/URLConnection/HttpContinueStackOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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,6 +23,7 @@ /* @test * @bug 4258697 + * @library /test/lib * @summary Make sure that http CONTINUE status followed by invalid * response doesn't cause HttpClient to recursively loop and * eventually StackOverflow. @@ -32,19 +33,21 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.PrintStream; +import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; import java.net.HttpURLConnection; +import jdk.test.lib.net.URIBuilder; + public class HttpContinueStackOverflow { static class Server implements Runnable { - int port; ServerSocket serverSock ; Server() throws IOException { - serverSock = new ServerSocket(0); + serverSock = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); } int getLocalPort() { @@ -82,8 +85,14 @@ public class HttpContinueStackOverflow { Server s = new Server(); (new Thread(s)).start(); - /* connect to server, connect to server and get response code */ - URL url = new URL("http", "localhost", s.getLocalPort(), "anything.html"); + /* connect to server and get response code */ + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(s.getLocalPort()) + .path("/anything.html") + .toURL(); + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.getResponseCode(); System.out.println("TEST PASSED"); diff --git a/test/jdk/java/net/URLConnection/ResendPostBody.java b/test/jdk/java/net/URLConnection/ResendPostBody.java index 771ccd6926a..a8fec538ebb 100644 --- a/test/jdk/java/net/URLConnection/ResendPostBody.java +++ b/test/jdk/java/net/URLConnection/ResendPostBody.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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,12 +25,15 @@ * @test * @bug 4361492 * @summary HTTPUrlConnection does not receive binary data correctly + * @library /test/lib * @run main/timeout=20 ResendPostBody */ import java.io.*; import java.net.*; +import jdk.test.lib.net.URIBuilder; + /* * This test does the following: * 1. client opens HTTP connection to server @@ -139,13 +142,16 @@ public class ResendPostBody { byte b[] = "X=ABCDEFGHZZZ".getBytes(); - ss = new ServerSocket (0); + ss = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); server = new Server (ss); server.start (); /* Get the URL */ - - String s = "http://localhost:"+ss.getLocalPort()+"/test"; - URL url = new URL(s); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(ss.getLocalPort()) + .path("/test") + .toURL(); HttpURLConnection conURL = (HttpURLConnection)url.openConnection(); conURL.setDoOutput(true); diff --git a/test/jdk/sun/net/ftp/MarkResetTest.java b/test/jdk/sun/net/ftp/MarkResetTest.java index d3236fe5544..1ff1c8b9a60 100644 --- a/test/jdk/sun/net/ftp/MarkResetTest.java +++ b/test/jdk/sun/net/ftp/MarkResetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2019, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 4673103 + * @library /test/lib * @run main/othervm/timeout=140 MarkResetTest * @summary URLConnection.getContent() hangs over FTP for DOC, PPT, XLS files */ @@ -36,7 +37,10 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; +import java.io.UncheckedIOException; import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; @@ -44,6 +48,8 @@ import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Paths; +import jdk.test.lib.net.URIBuilder; + public class MarkResetTest { private static final String FILE_NAME = "EncDec.doc"; @@ -51,9 +57,8 @@ public class MarkResetTest { * A class that simulates, on a separate, an FTP server. */ private class FtpServer extends Thread { - private ServerSocket server; - private int port; - private boolean done = false; + private final ServerSocket server; + private volatile boolean done = false; private boolean pasvEnabled = true; private boolean portEnabled = true; private boolean extendedEnabled = true; @@ -173,7 +178,7 @@ public class MarkResetTest { */ public void run() { - boolean done = false; + done = false; String str; int res; boolean logged = false; @@ -244,8 +249,10 @@ public class MarkResetTest { continue; } try { - if (pasv == null) - pasv = new ServerSocket(0); + if (pasv == null) { + pasv = new ServerSocket(); + pasv.bind(new InetSocketAddress(server.getInetAddress(), 0)); + } int port = pasv.getLocalPort(); out.println("229 Entering Extended" + " Passive Mode (|||" + port + "|)"); @@ -262,8 +269,10 @@ public class MarkResetTest { continue; } try { - if (pasv == null) - pasv = new ServerSocket(0); + if (pasv == null) { + pasv = new ServerSocket(); + pasv.bind(new InetSocketAddress("127.0.0.1", 0)); + } int port = pasv.getLocalPort(); // Parenthesis are optional, so let's be @@ -364,17 +373,28 @@ public class MarkResetTest { } public FtpServer(int port) { - this.port = port; + this(InetAddress.getLoopbackAddress(), port); + } + + public FtpServer(InetAddress address, int port) { + try { + if (address == null) { + server = new ServerSocket(port); + } else { + server = new ServerSocket(); + server.bind(new InetSocketAddress(address, port)); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } } public FtpServer() { - this(21); + this(null, 21); } public int getPort() { - if (server != null) - return server.getLocalPort(); - return 0; + return server.getLocalPort(); } /** @@ -392,7 +412,8 @@ public class MarkResetTest { */ public void run() { try { - server = new ServerSocket(port); + System.out.println("FTP server waiting for connections at: " + + server.getLocalSocketAddress()); Socket client; client = server.accept(); (new FtpServerHandler(client)).start(); @@ -419,10 +440,14 @@ public class MarkResetTest { port = server.getPort(); } + URL url = URIBuilder.newBuilder() + .scheme("ftp") + .loopback() + .port(port) + .path("/" + FILE_NAME) + .toURL(); - URL url = new URL("ftp://localhost:" + port + "/" + FILE_NAME); - - URLConnection con = url.openConnection(); + URLConnection con = url.openConnection(Proxy.NO_PROXY); System.out.println("getContent: " + con.getContent()); System.out.println("getContent-length: " + con.getContentLength()); diff --git a/test/jdk/sun/net/www/http/ChunkedOutputStream/Test.java b/test/jdk/sun/net/www/http/ChunkedOutputStream/Test.java index 82b4e36d01c..a3bc95ca972 100644 --- a/test/jdk/sun/net/www/http/ChunkedOutputStream/Test.java +++ b/test/jdk/sun/net/www/http/ChunkedOutputStream/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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,6 +25,7 @@ * @test * @bug 5026745 6631048 * @modules jdk.httpserver + * @library /test/lib * @run main/othervm/timeout=500 Test * @summary Cannot flush output stream when writing to an HttpUrlConnection */ @@ -33,6 +34,8 @@ import java.io.*; import java.net.*; import com.sun.net.httpserver.*; +import jdk.test.lib.net.URIBuilder; + public class Test implements HttpHandler { static volatile int count = 0; @@ -272,9 +275,8 @@ public class Test implements HttpHandler { /* basic chunked test (runs twice) */ - static void test1 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test1(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (20); urlc.setDoOutput(true); @@ -289,9 +291,8 @@ public class Test implements HttpHandler { /* basic fixed length test */ - static void test3 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test3(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setFixedLengthStreamingMode (str2.length()); urlc.setDoOutput(true); @@ -306,9 +307,8 @@ public class Test implements HttpHandler { /* write too few bytes */ - static void test4 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test4(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setFixedLengthStreamingMode (str2.length()+1); urlc.setDoOutput(true); @@ -323,9 +323,8 @@ public class Test implements HttpHandler { /* write too many bytes */ - static void test5 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test5(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setFixedLengthStreamingMode (str2.length()-1); urlc.setDoOutput(true); @@ -339,9 +338,8 @@ public class Test implements HttpHandler { /* check for HttpRetryException on redirection */ - static void test6 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test6(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (20); urlc.setDoOutput(true); @@ -364,9 +362,8 @@ public class Test implements HttpHandler { /* next two tests send zero length posts */ - static void test7 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test7(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (20); urlc.setDoOutput(true); @@ -379,9 +376,8 @@ public class Test implements HttpHandler { } } - static void test8 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test8(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setFixedLengthStreamingMode (0); urlc.setDoOutput(true); @@ -396,9 +392,8 @@ public class Test implements HttpHandler { /* calling setChunkedStreamingMode with -1 should entail using the default chunk size */ - static void test9 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test9(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (-1); urlc.setDoOutput(true); @@ -411,9 +406,8 @@ public class Test implements HttpHandler { is.close(); } - static void test10 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test10(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (4 * 1024); urlc.setDoOutput(true); @@ -435,9 +429,8 @@ public class Test implements HttpHandler { } } - static void test11 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test11(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (36 * 1024); urlc.setDoOutput(true); @@ -462,9 +455,8 @@ public class Test implements HttpHandler { } } - static void test12 (String u) throws Exception { - URL url = new URL (u); - System.out.println ("client opening connection to: " + u); + static void test12(URL url) throws Exception { + System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); urlc.setChunkedStreamingMode (36 * 1024); urlc.setDoOutput(true); @@ -485,29 +477,39 @@ public class Test implements HttpHandler { } - static com.sun.net.httpserver.HttpServer httpserver; + static HttpServer httpserver; + + private static URL buildTestURL(int port, String path) + throws MalformedURLException, URISyntaxException { + return URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(port) + .path(path) + .toURL(); + } public static void main (String[] args) throws Exception { try { - httpserver = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(0), 0); - HttpContext ctx = httpserver.createContext("/test/", new Test() ); + httpserver = HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + httpserver.createContext("/test/", new Test()); httpserver.start(); int port = httpserver.getAddress().getPort(); System.out.println ("Server started: listening on port: " + port); - test1("http://localhost:"+ port + "/test/test1"); - test1("http://localhost:"+ port + "/test/test2"); - test3("http://localhost:"+ port + "/test/test3"); - test4("http://localhost:"+ port + "/test/test4"); - test5("http://localhost:"+ port + "/test/test5"); - test6("http://localhost:"+ port + "/test/test6"); - test7("http://localhost:"+ port + "/test/test7"); - test8("http://localhost:"+ port + "/test/test8"); - test9("http://localhost:"+ port + "/test/test9"); - test10("http://localhost:"+ port + "/test/test10"); - test11("http://localhost:"+ port + "/test/test11"); - test12("http://localhost:"+ port + "/test/test12"); + test1(buildTestURL(port, "/test/test1")); + test1(buildTestURL(port, "/test/test2")); + test3(buildTestURL(port, "/test/test3")); + test4(buildTestURL(port, "/test/test4")); + test5(buildTestURL(port, "/test/test5")); + test6(buildTestURL(port, "/test/test6")); + test7(buildTestURL(port, "/test/test7")); + test8(buildTestURL(port, "/test/test8")); + test9(buildTestURL(port, "/test/test9")); + test10(buildTestURL(port, "/test/test10")); + test11(buildTestURL(port, "/test/test11")); + test12(buildTestURL(port, "/test/test12")); } finally { if (httpserver != null) httpserver.stop(0); diff --git a/test/jdk/sun/net/www/protocol/http/B6518816.java b/test/jdk/sun/net/www/protocol/http/B6518816.java index 929387c3e7b..68c1000a47a 100644 --- a/test/jdk/sun/net/www/protocol/http/B6518816.java +++ b/test/jdk/sun/net/www/protocol/http/B6518816.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 6518816 + * @library /test/lib * @modules jdk.httpserver * @run main/othervm B6518816 */ @@ -35,6 +36,8 @@ import com.sun.net.httpserver.*; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; +import jdk.test.lib.net.URIBuilder; + public class B6518816 { com.sun.net.httpserver.HttpServer httpServer; @@ -79,8 +82,12 @@ public class B6518816 byte [] buf = new byte [TEN_MB]; for (int j=0; j diff --git a/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java b/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java index 78e98609362..a2fee75ac3d 100644 --- a/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java +++ b/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java @@ -60,13 +60,14 @@ public class TunnelThroughProxy { ProxyTunnelServer proxy = setupProxy(true); try { int proxyPort = proxy.getPort(); - ServerSocket server = new ServerSocket(0); + InetAddress proxyAddress = proxy.getInetAddress(); + ServerSocket server = new ServerSocket(0, 0, InetAddress.getLoopbackAddress()); int serverPort = server.getLocalPort(); Socket sock; sock = new Socket(new Proxy(Proxy.Type.HTTP, - new InetSocketAddress(InetAddress.getLoopbackAddress(), proxyPort))); - InetSocketAddress dest = new InetSocketAddress(InetAddress.getLoopbackAddress(), serverPort); + new InetSocketAddress(proxyAddress, proxyPort))); + InetSocketAddress dest = new InetSocketAddress(server.getInetAddress(), serverPort); sock.connect(dest); int localPort = sock.getLocalPort(); if (localPort == proxyPort) @@ -84,14 +85,17 @@ public class TunnelThroughProxy { } static ProxyTunnelServer setupProxy(boolean makeTunnel) throws IOException { - ProxyTunnelServer pserver = new ProxyTunnelServer(); + InetAddress proxyAddress = InetAddress.getLoopbackAddress(); + ProxyTunnelServer pserver = new ProxyTunnelServer(proxyAddress); pserver.doTunnel(makeTunnel); int proxyPort = pserver.getPort(); // disable proxy authentication pserver.needUserAuth(false); pserver.start(); - System.setProperty("https.proxyHost", "localhost"); + System.out.printf("Setting https.proxyHost='%s'%n", proxyAddress.getHostAddress()); + System.setProperty("https.proxyHost", proxyAddress.getHostAddress()); + System.out.printf("Setting https.proxyPort='%s'%n", String.valueOf(proxyPort)); System.setProperty("https.proxyPort", String.valueOf(proxyPort)); return pserver; } From 47a39418faf1dd664db6c27e08d4a09d56b9861b Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Wed, 15 May 2019 13:22:29 -0700 Subject: [PATCH 009/263] 8222136: Remove two Comodo root CA certificates that are expiring Reviewed-by: mullan --- src/java.base/share/lib/security/cacerts | Bin 102705 -> 100258 bytes .../security/lib/cacerts/VerifyCACerts.java | 12 ++---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/lib/security/cacerts b/src/java.base/share/lib/security/cacerts index c27ffd1807871f6474c578c88dadf8a13602e1b4..a83bf49ee1b24fd79517c1e134c7d8c56e0ab0d1 100644 GIT binary patch delta 59 zcmdnEh;30n8_&PD|K2h%Ffaje)JC4A+0By+wofi#+`zK^LnWiGxX9Q3$p$`agkCZi PntXU$J=M=T^yYs6)`c05 delta 1840 zcmbW$dovLR<9PTt~WNgsdpJ)iBIuYHcL6%yAioETLRxE%mrI zJj$(;OAK>&pFQ@-*Z0SbAG?i`<(ClyoAYcu@EjlH##>8 z0)ZfsG4@oq3Gq6-cKsSX4I4j}}Cw2YOL8UH!cS+(97l z;pKfmG)T%>&k!JiK(Ks(3ljodXo3I=0Ye~)yKc%SI)K(ztmraYx6b!2k3SHM;crF< zx)=claHtaus;ukeXs_$E&tk9TLXhsx#U#z`3sDRf-HXbi2QxIO3~x<~g=7GWMvzE= zF+d_16HN>O7c_$K{i<(dXyO7ymGBAZP^161p1=CB7N?99BbtaT+-~M+XDatGN zFSxGf%P~w08^qG%pTD$h7hHaObJ_h6(-R68-_G`FyP6-<(0WOxHrYo`4d~9CK$&XgFd((CYbXX4!=7GwwDNg`-T6NUl8(0nEaG>tHAV375gc!BSGvP{`5*<45t49B~lUJztd*QD`#+%&gAJ$_~I8GptX1qyXsfhEm`N4|Ql#H^@OJ_Ta zr*dLeDlxb+tkvHjdFn0oRKHz`w(&>OY(GqcXiisZ83h z7>$npz<6AOktM2SiTaf$`Fr3` z22BWn0r7`H69S1ylo(vxqxoNZ_-A*o=7>Kvm~5@M%IP3+DZZUSxew=^Ctu~_-ywL8 znN=p4s87#UhmmjBP+3anF`NCF-J2DCO-ZA8<#wNuG+BL7V7mBq)4O_hSeB*7nZi#0 zuT?lFw4!6V%J_w;_hR?TD?u~Qj-msE@iU--IaNZa`~~m{G4TZ+EN#MQxa_fpQ)_WC z+@bz1ko;sAf1=BEMt>Vt(4B#cb-4?Y$_fgmlIZd9#xK0plQP+KJz4#W8xWSu zPq$ecT%%L!KEvDnihXQrw-iz9kj8%}Ql?KdUJ-y>zx%$Ag_TqU$?m zACB*ppP%Z#=OmOHv~{HM4+rEbWfglwZya$cxizHw0px|baVv15!@92)0yG0AL7PNb=cDUz(zG;_sF^$dc$P5L!VCMAz| zPsM>V(5eou#lTd;6+_a^#!^yR?Fl| z?@G*X{y7u`j*=7g`H`8&5hacyF$-IhJq_`>dfn{^n21K=v8&!szcF_8zn1>wg5vBp J*VZq@zW_(9?s@ Date: Tue, 7 May 2019 16:18:21 -0700 Subject: [PATCH 010/263] 8223532: Don't try creating IPv4 sockets in NetworkInterface.c if IPv4 is not supported Reviewed-by: dfuchs, chegar --- .../unix/native/libnet/NetworkInterface.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index ed93bd1ff11..6d890081bf1 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -807,17 +807,19 @@ static netif *enumInterfaces(JNIEnv *env) { int sock; sock = openSocket(env, AF_INET); - if (sock < 0) { + if (sock < 0 && (*env)->ExceptionOccurred(env)) { return NULL; } // enumerate IPv4 addresses - ifs = enumIPv4Interfaces(env, sock, NULL); - close(sock); + if (sock >= 0) { + ifs = enumIPv4Interfaces(env, sock, ifs); + close(sock); - // return partial list if an exception occurs in the middle of process ??? - if (ifs == NULL && (*env)->ExceptionOccurred(env)) { - return NULL; + if ((*env)->ExceptionOccurred(env)) { + freeif(ifs); + return NULL; + } } // If IPv6 is available then enumerate IPv6 addresses. @@ -1076,9 +1078,9 @@ static int openSocket(JNIEnv *env, int proto) { int sock; if ((sock = socket(proto, SOCK_DGRAM, 0)) < 0) { - // If EPROTONOSUPPORT is returned it means we don't have - // support for this proto so don't throw an exception. - if (errno != EPROTONOSUPPORT) { + // If we lack support for this address family or protocol, + // don't throw an exception. + if (errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "Socket creation failed"); } @@ -1099,7 +1101,7 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - if (errno == EPROTONOSUPPORT) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); @@ -1336,7 +1338,7 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - if (errno == EPROTONOSUPPORT) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); @@ -1614,7 +1616,7 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { struct lifreq if2; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - if (errno == EPROTONOSUPPORT) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); @@ -1965,7 +1967,7 @@ static int openSocketWithFallback(JNIEnv *env, const char *ifname) { int sock; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - if (errno == EPROTONOSUPPORT) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { JNU_ThrowByNameWithMessageAndLastError (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); From f13e5970554e303638e930c9b411b993565348fb Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 15 May 2019 22:45:54 +0200 Subject: [PATCH 011/263] 8223980: Shenandoah: Refactor and fix ObjArrayChunkedTask verification Reviewed-by: rkennke --- .../gc/shenandoah/shenandoahArguments.cpp | 12 ---- .../share/gc/shenandoah/shenandoahHeap.cpp | 13 ++++ .../gc/shenandoah/shenandoahTaskqueue.hpp | 59 ++++++++++++++----- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index 3c3a1403119..b30d13dc902 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -29,7 +29,6 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahHeapRegion.hpp" -#include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "utilities/defaultStream.hpp" void ShenandoahArguments::initialize() { @@ -54,17 +53,6 @@ void ShenandoahArguments::initialize() { FLAG_SET_DEFAULT(ShenandoahVerifyOptoBarriers, false); #endif -#ifdef _LP64 - // The optimized ObjArrayChunkedTask takes some bits away from the full 64 addressable - // bits, fail if we ever attempt to address more than we can. Only valid on 64bit. - if (MaxHeapSize >= ObjArrayChunkedTask::max_addressable()) { - jio_fprintf(defaultStream::error_stream(), - "Shenandoah GC cannot address more than " SIZE_FORMAT " bytes, and " SIZE_FORMAT " bytes heap requested.", - ObjArrayChunkedTask::max_addressable(), MaxHeapSize); - vm_exit(1); - } -#endif - if (UseLargePages && (MaxHeapSize / os::large_page_size()) < ShenandoahHeapRegion::MIN_NUM_REGIONS) { warning("Large pages size (" SIZE_FORMAT "K) is too large to afford page-sized regions, disabling uncommit", os::large_page_size() / K); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 68650bdae75..23b122b503d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -54,6 +54,7 @@ #include "gc/shenandoah/shenandoahPacer.inline.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahStringDedup.hpp" +#include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" @@ -186,6 +187,18 @@ jint ShenandoahHeap::initialize() { assert((((size_t) base()) & ShenandoahHeapRegion::region_size_bytes_mask()) == 0, "Misaligned heap: " PTR_FORMAT, p2i(base())); +#if SHENANDOAH_OPTIMIZED_OBJTASK + // The optimized ObjArrayChunkedTask takes some bits away from the full object bits. + // Fail if we ever attempt to address more than we can. + if ((uintptr_t)heap_rs.end() >= ObjArrayChunkedTask::max_addressable()) { + FormatBuffer<512> buf("Shenandoah reserved [" PTR_FORMAT ", " PTR_FORMAT") for the heap, \n" + "but max object address is " PTR_FORMAT ". Try to reduce heap size, or try other \n" + "VM options that allocate heap at lower addresses (HeapBaseMinAddress, AllocateHeapAt, etc).", + p2i(heap_rs.base()), p2i(heap_rs.end()), ObjArrayChunkedTask::max_addressable()); + vm_exit_during_initialization("Fatal Error", buf); + } +#endif + ReservedSpace sh_rs = heap_rs.first_part(max_byte_size); if (!_heap_region_special) { os::commit_memory_or_exit(sh_rs.base(), _initial_size, heap_alignment, false, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 6ce6dbedebd..872d438485b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -109,7 +109,7 @@ private: // some bits back if chunks are counted in ObjArrayMarkingStride units. // // There is also a fallback version that uses plain fields, when we don't have enough space to steal the -// bits from the native pointer. It is useful to debug the _LP64 version. +// bits from the native pointer. It is useful to debug the optimized version. // #ifdef _MSC_VER @@ -119,6 +119,12 @@ private: #endif #ifdef _LP64 +#define SHENANDOAH_OPTIMIZED_OBJTASK 1 +#else +#define SHENANDOAH_OPTIMIZED_OBJTASK 0 +#endif + +#if SHENANDOAH_OPTIMIZED_OBJTASK class ObjArrayChunkedTask { public: @@ -135,17 +141,14 @@ public: public: ObjArrayChunkedTask(oop o = NULL) { - _obj = ((uintptr_t)(void*) o) << oop_shift; + assert(oopDesc::equals_raw(decode_oop(encode_oop(o)), o), "oop can be encoded: " PTR_FORMAT, p2i(o)); + _obj = encode_oop(o); } - ObjArrayChunkedTask(oop o, int chunk, int mult) { - assert(0 <= chunk && chunk < nth_bit(chunk_bits), "chunk is sane: %d", chunk); - assert(0 <= mult && mult < nth_bit(pow_bits), "pow is sane: %d", mult); - uintptr_t t_b = ((uintptr_t) chunk) << chunk_shift; - uintptr_t t_m = ((uintptr_t) mult) << pow_shift; - uintptr_t obj = (uintptr_t)(void*)o; - assert(obj < nth_bit(oop_bits), "obj ref is sane: " PTR_FORMAT, obj); - intptr_t t_o = obj << oop_shift; - _obj = t_o | t_m | t_b; + ObjArrayChunkedTask(oop o, int chunk, int pow) { + assert(oopDesc::equals_raw(decode_oop(encode_oop(o)), o), "oop can be encoded: " PTR_FORMAT, p2i(o)); + assert(decode_chunk(encode_chunk(chunk)) == chunk, "chunk can be encoded: %d", chunk); + assert(decode_pow(encode_pow(pow)) == pow, "pow can be encoded: %d", pow); + _obj = encode_oop(o) | encode_chunk(chunk) | encode_pow(pow); } ObjArrayChunkedTask(const ObjArrayChunkedTask& t): _obj(t._obj) { } @@ -159,14 +162,38 @@ public: return *this; } - inline oop obj() const { return (oop) reinterpret_cast((_obj >> oop_shift) & right_n_bits(oop_bits)); } - inline int chunk() const { return (int) (_obj >> chunk_shift) & right_n_bits(chunk_bits); } - inline int pow() const { return (int) ((_obj >> pow_shift) & right_n_bits(pow_bits)); } + inline oop decode_oop(uintptr_t val) const { + return (oop) reinterpret_cast((val >> oop_shift) & right_n_bits(oop_bits)); + } + + inline int decode_chunk(uintptr_t val) const { + return (int) ((val >> chunk_shift) & right_n_bits(chunk_bits)); + } + + inline int decode_pow(uintptr_t val) const { + return (int) ((val >> pow_shift) & right_n_bits(pow_bits)); + } + + inline uintptr_t encode_oop(oop obj) const { + return ((uintptr_t)(void*) obj) << oop_shift; + } + + inline uintptr_t encode_chunk(int chunk) const { + return ((uintptr_t) chunk) << chunk_shift; + } + + inline uintptr_t encode_pow(int pow) const { + return ((uintptr_t) pow) << pow_shift; + } + + inline oop obj() const { return decode_oop(_obj); } + inline int chunk() const { return decode_chunk(_obj); } + inline int pow() const { return decode_pow(_obj); } inline bool is_not_chunked() const { return (_obj & ~right_n_bits(oop_bits + pow_bits)) == 0; } DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid. - static size_t max_addressable() { + static uintptr_t max_addressable() { return nth_bit(oop_bits); } @@ -229,7 +256,7 @@ private: int _chunk; int _pow; }; -#endif +#endif // SHENANDOAH_OPTIMIZED_OBJTASK #ifdef _MSC_VER #pragma warning(pop) From dfe97ffa437387d2f23746b08521b5beff1e7879 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Thu, 16 May 2019 02:34:53 +0200 Subject: [PATCH 012/263] Added tag jdk-13+21 for changeset f2f11d7f7f4e --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index d164bf1be26..fc5d8fdf01a 100644 --- a/.hgtags +++ b/.hgtags @@ -558,3 +558,4 @@ f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15 bebb82ef3434a25f8142edafec20165f07ac562d jdk-13+18 a43d6467317d8f1e160f67aadec37919c9d64443 jdk-13+19 6ccc7cd7931e34129f6b7e04988fc9a63958dde0 jdk-13+20 +f2f11d7f7f4e7128f8aba6ffa576cfa76fbf7d1a jdk-13+21 From d95f5a3ec0cbb1579582ba2b0927d1d4ebec2060 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Wed, 15 May 2019 20:33:17 -0400 Subject: [PATCH 013/263] 8224010: Incorrect string interning Revert jvmci change Reviewed-by: dholmes, jiangli --- src/hotspot/share/jvmci/compilerRuntime.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/jvmci/compilerRuntime.cpp b/src/hotspot/share/jvmci/compilerRuntime.cpp index 315d020552f..f30ff6d48e5 100644 --- a/src/hotspot/share/jvmci/compilerRuntime.cpp +++ b/src/hotspot/share/jvmci/compilerRuntime.cpp @@ -45,7 +45,8 @@ JRT_BLOCK_ENTRY(void, CompilerRuntime::resolve_string_by_symbol(JavaThread *thre // First 2 bytes of name contains length (number of bytes). int len = Bytes::get_Java_u2((address)name); name += 2; - str = StringTable::intern(name, CHECK); + TempNewSymbol sym = SymbolTable::new_symbol(name, len); + str = StringTable::intern(sym, CHECK); assert(java_lang_String::is_instance(str), "must be string"); *(oop*)string_result = str; // Store result } From 6e7ff5e656201d97a8bbd42752ea9ca7c11f4d30 Mon Sep 17 00:00:00 2001 From: Ralf Schmelter Date: Mon, 13 May 2019 07:41:32 -0700 Subject: [PATCH 014/263] 8223770: code_size2 still too small in some compressed oops configurations Reviewed-by: mdoerr, stuefe --- src/hotspot/cpu/x86/stubRoutines_x86.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index cbe89581593..be64c39652e 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -33,7 +33,7 @@ static bool returns_to_call_stub(address return_pc) { return return_pc == _call_ enum platform_dependent_constants { code_size1 = 20000 LP64_ONLY(+10000), // simply increase if too small (assembler will crash if too small) - code_size2 = 35300 LP64_ONLY(+11200) // simply increase if too small (assembler will crash if too small) + code_size2 = 35300 LP64_ONLY(+11400) // simply increase if too small (assembler will crash if too small) }; class x86 { From b32a840e53f3ee2d0093c6a8912aa9e467968763 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 16 May 2019 10:52:36 +0200 Subject: [PATCH 015/263] 8222169: java.lang.AssertionError switch expression in ternary operator - ? Ensure the stack size recoded at the begining of the let expression is the correct one. Co-authored-by: Vicente Romero Reviewed-by: vromero --- .../classes/com/sun/tools/javac/jvm/Gen.java | 2 + .../ConditionalAndPostfixOperator.java | 58 +++++++++++++++++++ .../javac/switchexpr/ExpressionSwitch-old.out | 6 +- .../javac/switchexpr/ExpressionSwitch.java | 15 +++-- 4 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 test/langtools/tools/javac/T8222795/ConditionalAndPostfixOperator.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index ed0dc1c2725..010c088b1ce 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -2309,6 +2309,8 @@ public class Gen extends JCTree.Visitor { } public void visitLetExpr(LetExpr tree) { + code.resolvePending(); + int limit = code.nextreg; int prevLetExprStart = code.setLetExprStackPos(code.state.stacksize); try { diff --git a/test/langtools/tools/javac/T8222795/ConditionalAndPostfixOperator.java b/test/langtools/tools/javac/T8222795/ConditionalAndPostfixOperator.java new file mode 100644 index 00000000000..81570e245a3 --- /dev/null +++ b/test/langtools/tools/javac/T8222795/ConditionalAndPostfixOperator.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019, 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 8222169 + * @summary post inc operator inside compute function of HashMap results in Exception + * @compile ConditionalAndPostfixOperator.java + * @run main ConditionalAndPostfixOperator + */ + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class ConditionalAndPostfixOperator { + public static void main(String... args) { + Map m = new HashMap<>(); + String key = "a"; + m.put(key, val()); + assertEquals(2, m.compute(key, (k, v) -> (v > 5) ? v-- : v++)); + + Integer v = val(); + + assertEquals(2, (v > 5) ? v-- : v++); + assertEquals(3, v); + } + + static void assertEquals(Integer expected, Integer actual) { + if (!Objects.equals(expected, actual)) { + throw new AssertionError("Expected: " + expected + ", " + + "actual: " + actual); + } + } + + static int val() { return 2; } + +} diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out index ba89e764dd2..13d4df20108 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out @@ -1,4 +1,4 @@ -ExpressionSwitch.java:38:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions) -ExpressionSwitch.java:39:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules) -ExpressionSwitch.java:89:21: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels) +ExpressionSwitch.java:39:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions) +ExpressionSwitch.java:40:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules) +ExpressionSwitch.java:92:31: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels) 3 errors diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java index 8acb340a9ab..cd7e408a48b 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 + * @bug 8206986 8222169 * @summary Check expression switch works. * @compile/fail/ref=ExpressionSwitch-old.out -source 9 -Xlint:-options -XDrawDiagnostics ExpressionSwitch.java * @compile --enable-preview -source ${jdk.version} ExpressionSwitch.java @@ -27,6 +27,7 @@ public class ExpressionSwitch { assertEquals(convert1("B"), 0); assertEquals(convert1("C"), 1); assertEquals(convert1(""), -1); + assertEquals(convert1(null), -2); assertEquals(convert2("A"), 0); assertEquals(convert2("B"), 0); assertEquals(convert2("C"), 1); @@ -85,11 +86,13 @@ public class ExpressionSwitch { } private int convert1(String s) { - return switch (s) { - case "A", "B" -> 0; - case "C" -> { break 1; } - default -> -1; - }; + return s == null + ? -2 + : switch (s) { + case "A", "B" -> 0; + case "C" -> { break 1; } + default -> -1; + }; } private int convert2(String s) { From 5fc3474639f501e78bd2757d46f06dac5f0751a4 Mon Sep 17 00:00:00 2001 From: Priya Lakshmi Muthuswamy Date: Thu, 16 May 2019 16:40:48 +0530 Subject: [PATCH 016/263] 8222548: Upgrading JDK 13 with the latest available jQuery 3.4.1 Reviewed-by: hannesw --- .../doclets/formats/html/HtmlDoclet.java | 3 +- .../doclets/formats/html/markup/Head.java | 3 +- .../script-dir/external/jquery/jquery.js | 602 ++++++++++++----- .../{jquery-3.3.1.js => jquery-3.4.1.js} | 602 ++++++++++++----- .../script-dir/jquery-migrate-3.0.1.js | 628 ------------------ .../doclets/toolkit/util/DocPaths.java | 5 +- src/jdk.javadoc/share/legal/jquery-migrate.md | 41 -- src/jdk.javadoc/share/legal/jquery.md | 6 +- .../javadoc/doclet/testSearch/TestSearch.java | 8 +- .../jdk/javadoc/tool/api/basic/APITest.java | 3 +- 10 files changed, 846 insertions(+), 1055 deletions(-) rename src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/{jquery-3.3.1.js => jquery-3.4.1.js} (94%) delete mode 100644 src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-migrate-3.0.1.js delete mode 100644 src/jdk.javadoc/share/legal/jquery-migrate.md diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java index d3b457104d1..5c249a1513c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java @@ -199,8 +199,7 @@ public class HtmlDoclet extends AbstractDoclet { private void copyJqueryFiles() throws DocletException { List files = Arrays.asList( - "jquery-3.3.1.js", - "jquery-migrate-3.0.1.js", + "jquery-3.4.1.js", "jquery-ui.js", "jquery-ui.css", "jquery-ui.min.js", diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java index 26dfb27ce1e..47cddc7db0b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java @@ -325,8 +325,7 @@ public class Head { tree.add(new RawHtml("")); - addJQueryFile(tree, DocPaths.JQUERY_JS_3_3); - addJQueryFile(tree, DocPaths.JQUERY_MIGRATE); + addJQueryFile(tree, DocPaths.JQUERY_JS_3_4); addJQueryFile(tree, DocPaths.JQUERY_JS); } for (Script script : scripts) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/external/jquery/jquery.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/external/jquery/jquery.js index 9b5206bcc60..5b16efa11d4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/external/jquery/jquery.js +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/external/jquery/jquery.js @@ -1,5 +1,5 @@ /*! - * jQuery JavaScript Library v3.3.1 + * jQuery JavaScript Library v3.4.1 * https://jquery.com/ * * Includes Sizzle.js @@ -9,7 +9,7 @@ * Released under the MIT license * https://jquery.org/license * - * Date: 2018-01-20T17:24Z + * Date: 2019-05-01T21:04Z */ ( function( global, factory ) { @@ -91,20 +91,33 @@ var isWindow = function isWindow( obj ) { var preservedScriptAttributes = { type: true, src: true, + nonce: true, noModule: true }; - function DOMEval( code, doc, node ) { + function DOMEval( code, node, doc ) { doc = doc || document; - var i, + var i, val, script = doc.createElement( "script" ); script.text = code; if ( node ) { for ( i in preservedScriptAttributes ) { - if ( node[ i ] ) { - script[ i ] = node[ i ]; + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); } } } @@ -129,7 +142,7 @@ function toType( obj ) { var - version = "3.3.1", + version = "3.4.1", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -258,25 +271,28 @@ jQuery.extend = jQuery.fn.extend = function() { // Extend the base object for ( name in options ) { - src = target[ name ]; copy = options[ name ]; + // Prevent Object.prototype pollution // Prevent never-ending loop - if ( target === copy ) { + if ( name === "__proto__" || target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject( copy ) || ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; + clone = src; } + copyIsArray = false; // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); @@ -329,9 +345,6 @@ jQuery.extend( { }, isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 var name; for ( name in obj ) { @@ -341,8 +354,8 @@ jQuery.extend( { }, // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); + globalEval: function( code, options ) { + DOMEval( code, { nonce: options && options.nonce } ); }, each: function( obj, callback ) { @@ -498,14 +511,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.3 + * Sizzle CSS Selector Engine v2.3.4 * https://sizzlejs.com/ * - * Copyright jQuery Foundation and other contributors + * Copyright JS Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://js.foundation/ * - * Date: 2016-08-08 + * Date: 2019-04-08 */ (function( window ) { @@ -539,6 +552,7 @@ var i, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), + nonnativeSelectorCache = createCache(), sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; @@ -600,8 +614,7 @@ var i, rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + rdescend = new RegExp( whitespace + "|>" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), @@ -622,6 +635,7 @@ var i, whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, + rhtml = /HTML$/i, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, @@ -676,9 +690,9 @@ var i, setDocument(); }, - disabledAncestor = addCombinator( + inDisabledFieldset = addCombinator( function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; }, { dir: "parentNode", next: "legend" } ); @@ -791,18 +805,22 @@ function Sizzle( selector, context, results, seed ) { // Take advantage of querySelectorAll if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + !nonnativeSelectorCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) && - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 + // Support: IE 8 only // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { + (nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && rdescend.test( selector ) ) { // Capture the context ID, setting it first if necessary if ( (nid = context.getAttribute( "id" )) ) { @@ -824,17 +842,16 @@ function Sizzle( selector, context, results, seed ) { context; } - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); } } } @@ -998,7 +1015,7 @@ function createDisabledPseudo( disabled ) { // Where there is no isDisabled, check manually /* jshint -W018 */ elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; + inDisabledFieldset( elem ) === disabled; } return elem.disabled === disabled; @@ -1055,10 +1072,13 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; + var namespace = elem.namespaceURI, + docElem = (elem.ownerDocument || elem).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); }; /** @@ -1480,11 +1500,8 @@ Sizzle.matchesSelector = function( elem, expr ) { setDocument( elem ); } - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && + !nonnativeSelectorCache[ expr + " " ] && ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { @@ -1498,7 +1515,9 @@ Sizzle.matchesSelector = function( elem, expr ) { elem.document && elem.document.nodeType !== 11 ) { return ret; } - } catch (e) {} + } catch (e) { + nonnativeSelectorCache( expr, true ); + } } return Sizzle( expr, document, null, [ elem ] ).length > 0; @@ -1957,7 +1976,7 @@ Expr = Sizzle.selectors = { "contains": markFunction(function( text ) { text = text.replace( runescape, funescape ); return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; }; }), @@ -2096,7 +2115,11 @@ Expr = Sizzle.selectors = { }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } @@ -3146,18 +3169,18 @@ jQuery.each( { return siblings( elem.firstChild ); }, contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } + if ( typeof elem.contentDocument !== "undefined" ) { + return elem.contentDocument; + } - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } - return jQuery.merge( [], elem.childNodes ); + return jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { @@ -4466,6 +4489,26 @@ var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } var isHiddenWithinTree = function( elem, el ) { // isHiddenWithinTree might be called from jQuery#filter function; @@ -4480,7 +4523,7 @@ var isHiddenWithinTree = function( elem, el ) { // Support: Firefox <=43 - 45 // Disconnected elements can have computed display: none, so first confirm that elem is // in the document. - jQuery.contains( elem.ownerDocument, elem ) && + isAttached( elem ) && jQuery.css( elem, "display" ) === "none"; }; @@ -4522,7 +4565,8 @@ function adjustCSS( elem, prop, valueParts, tween ) { unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && rcssNum.exec( jQuery.css( elem, prop ) ); if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { @@ -4669,7 +4713,7 @@ jQuery.fn.extend( { } ); var rcheckableType = ( /^(?:checkbox|radio)$/i ); -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); @@ -4741,7 +4785,7 @@ function setGlobalEval( elems, refElements ) { var rhtml = /<|&#?\w+;/; function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, + var elem, tmp, tag, wrap, attached, j, fragment = context.createDocumentFragment(), nodes = [], i = 0, @@ -4805,13 +4849,13 @@ function buildFragment( elems, context, scripts, selection, ignored ) { continue; } - contains = jQuery.contains( elem.ownerDocument, elem ); + attached = isAttached( elem ); // Append to fragment tmp = getAll( fragment.appendChild( elem ), "script" ); // Preserve script evaluation history - if ( contains ) { + if ( attached ) { setGlobalEval( tmp ); } @@ -4854,8 +4898,6 @@ function buildFragment( elems, context, scripts, selection, ignored ) { div.innerHTML = ""; support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; } )(); -var documentElement = document.documentElement; - var @@ -4871,8 +4913,19 @@ function returnFalse() { return false; } +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + // Support: IE <=9 only -// See #13393 for more info +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 function safeActiveElement() { try { return document.activeElement; @@ -5172,9 +5225,10 @@ jQuery.event = { while ( ( handleObj = matched.handlers[ j++ ] ) && !event.isImmediatePropagationStopped() ) { - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; @@ -5298,39 +5352,51 @@ jQuery.event = { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; }, - // For cross-browser consistency, don't fire native .click() on links + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack _default: function( event ) { - return nodeName( event.target, "a" ); + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); } }, @@ -5347,6 +5413,93 @@ jQuery.event = { } }; +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + jQuery.removeEvent = function( elem, type, handle ) { // This "if" is needed for plain objects @@ -5459,6 +5612,7 @@ jQuery.each( { shiftKey: true, view: true, "char": true, + code: true, charCode: true, key: true, keyCode: true, @@ -5505,6 +5659,33 @@ jQuery.each( { } }, jQuery.event.addProp ); +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + // Create mouseenter/leave events using mouseover/out and event-time checks // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout @@ -5755,11 +5936,13 @@ function domManip( collection, args, callback, ignored ) { if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + } ); } } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node ); + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); } } } @@ -5781,7 +5964,7 @@ function remove( elem, selector, keepData ) { } if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + if ( keepData && isAttached( node ) ) { setGlobalEval( getAll( node, "script" ) ); } node.parentNode.removeChild( node ); @@ -5799,7 +5982,7 @@ jQuery.extend( { clone: function( elem, dataAndEvents, deepDataAndEvents ) { var i, l, srcElements, destElements, clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); + inPage = isAttached( elem ); // Fix IE cloning issues if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && @@ -6095,8 +6278,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); // Support: IE 9 only // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) div.style.position = "absolute"; - scrollboxSizeVal = div.offsetWidth === 36 || "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; documentElement.removeChild( container ); @@ -6167,7 +6352,7 @@ function curCSS( elem, name, computed ) { if ( computed ) { ret = computed.getPropertyValue( name ) || computed[ name ]; - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + if ( ret === "" && !isAttached( elem ) ) { ret = jQuery.style( elem, name ); } @@ -6223,30 +6408,13 @@ function addGetHookIf( conditionFn, hookFn ) { } -var +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property +// Return a vendor-prefixed property or undefined function vendorPropName( name ) { - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - // Check for vendor prefixed names var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), i = cssPrefixes.length; @@ -6259,16 +6427,33 @@ function vendorPropName( name ) { } } -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; } - return ret; + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; } + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + function setPositiveNumber( elem, value, subtract ) { // Any relative (+/-) values have already been @@ -6340,7 +6525,10 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed delta - extra - 0.5 - ) ); + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; } return delta; @@ -6350,9 +6538,16 @@ function getWidthOrHeight( elem, dimension, extra ) { // Start with computed style var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + val = curCSS( elem, dimension, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox; + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); // Support: Firefox <=54 // Return a confounding non-pixel value or feign ignorance, as appropriate. @@ -6363,22 +6558,29 @@ function getWidthOrHeight( elem, dimension, extra ) { val = "auto"; } - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = valueIsBorderBox && - ( support.boxSizingReliable() || val === elem.style[ dimension ] ); // Fall back to offsetWidth/offsetHeight when value is "auto" // This happens for inline elements with no explicit setting (gh-3571) // Support: Android <=4.1 - 4.3 only // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - if ( val === "auto" || - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) { + // Support: IE 9-11 only + // Also use offsetWidth/offsetHeight for when box sizing is unreliable + // We use getClientRects() to check for hidden/disconnected. + // In those cases, the computed value can be trusted to be border-box + if ( ( !support.boxSizingReliable() && isBorderBox || + val === "auto" || + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + elem.getClientRects().length ) { - val = elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ]; + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - // offsetWidth/offsetHeight provide border-box values - valueIsBorderBox = true; + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } } // Normalize "" and auto @@ -6424,6 +6626,13 @@ jQuery.extend( { "flexGrow": true, "flexShrink": true, "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, "lineHeight": true, "opacity": true, "order": true, @@ -6479,7 +6688,9 @@ jQuery.extend( { } // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); } @@ -6579,18 +6790,29 @@ jQuery.each( [ "height", "width" ], function( i, dimension ) { set: function( elem, value, extra ) { var matches, styles = getStyles( elem ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra && boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ); + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; // Account for unreliable border-box dimensions by comparing offset* to computed and // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && support.scrollboxSize() === styles.position ) { + if ( isBorderBox && scrollboxSizeBuggy ) { subtract -= Math.ceil( elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - parseFloat( styles[ dimension ] ) - @@ -6758,9 +6980,9 @@ Tween.propHooks = { // Use .style if available and use plain properties where available. if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { tween.elem[ tween.prop ] = tween.now; @@ -8467,6 +8689,10 @@ jQuery.param = function( a, traditional ) { encodeURIComponent( value == null ? "" : value ); }; + if ( a == null ) { + return ""; + } + // If an array was passed in, assume that it is an array of form elements. if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { @@ -8969,12 +9195,14 @@ jQuery.extend( { if ( !responseHeaders ) { responseHeaders = {}; while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); } } - match = responseHeaders[ key.toLowerCase() ]; + match = responseHeaders[ key.toLowerCase() + " " ]; } - return match == null ? null : match; + return match == null ? null : match.join( ", " ); }, // Raw string @@ -9363,7 +9591,7 @@ jQuery.each( [ "get", "post" ], function( i, method ) { } ); -jQuery._evalUrl = function( url ) { +jQuery._evalUrl = function( url, options ) { return jQuery.ajax( { url: url, @@ -9373,7 +9601,16 @@ jQuery._evalUrl = function( url ) { cache: true, async: false, global: false, - "throws": true + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options ); + } } ); }; @@ -9656,24 +9893,21 @@ jQuery.ajaxPrefilter( "script", function( s ) { // Bind script tag hack transport jQuery.ajaxTransport( "script", function( s ) { - // This transport only deals with cross domain requests - if ( s.crossDomain ) { + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { var script, callback; return { send: function( _, complete ) { - script = jQuery( "\n", - "\n", + "\n", "", "var pathtoroot = \"./\";\n" + "loadScripts(document, 'script');", @@ -568,8 +567,7 @@ public class TestSearch extends JavadocTester { void checkJqueryAndImageFiles(boolean expectedOutput) { checkFiles(expectedOutput, "search.js", - "script-dir/jquery-3.3.1.js", - "script-dir/jquery-migrate-3.0.1.js", + "script-dir/jquery-3.4.1.js", "script-dir/jquery-ui.js", "script-dir/jquery-ui.css", "script-dir/jquery-ui.min.js", diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index 369344bb536..72a99d81f0e 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -197,8 +197,7 @@ class APITest { "help-doc.html", "index-all.html", "index.html", - "script-dir/jquery-3.3.1.js", - "script-dir/jquery-migrate-3.0.1.js", + "script-dir/jquery-3.4.1.js", "script-dir/jquery-ui.js", "script-dir/jquery-ui.css", "script-dir/jquery-ui.min.js", From 4915cf9b71eb5344d036d691be789ec55444cd5d Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 16 May 2019 07:09:17 -0400 Subject: [PATCH 017/263] 8223956: Make SymbolTable and StringTable AllStatic Removed superfluous and confusing _the_table pointer. Reviewed-by: gziemski, rehn --- src/hotspot/share/classfile/stringTable.cpp | 94 ++++++------ src/hotspot/share/classfile/stringTable.hpp | 98 +++++-------- src/hotspot/share/classfile/symbolTable.cpp | 134 +++++++++--------- src/hotspot/share/classfile/symbolTable.hpp | 89 +++++------- .../share/jfr/periodic/jfrPeriodic.cpp | 4 +- .../share/prims/resolvedMethodTable.cpp | 22 ++- .../share/prims/resolvedMethodTable.hpp | 15 +- 7 files changed, 186 insertions(+), 270 deletions(-) diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 3208e733c7c..46ca59e90f5 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -30,7 +30,6 @@ #include "classfile/systemDictionary.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/oopStorage.inline.hpp" -#include "gc/shared/oopStorageParState.inline.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" @@ -79,9 +78,21 @@ static CompactHashtable< #endif // -------------------------------------------------------------------------- -StringTable* StringTable::_the_table = NULL; -volatile bool StringTable::_alt_hash = false; +typedef ConcurrentHashTable, + StringTableConfig, mtSymbol> StringTableHash; +static StringTableHash* _local_table = NULL; + +volatile bool StringTable::_has_work = false; +volatile bool StringTable::_needs_rehashing = false; + +volatile size_t StringTable::_uncleaned_items_count = 0; +OopStorage* StringTable::_weak_handles = NULL; + +static size_t _current_size = 0; +static volatile size_t _items_count = 0; + +volatile bool _alt_hash = false; static juint murmur_seed = 0; uintx hash_string(const jchar* s, int len, bool useAlt) { @@ -107,7 +118,7 @@ class StringTableConfig : public StringTableHash::BaseConfig { int length; jchar* chars = java_lang_String::as_unicode_string(val_oop, length, THREAD); if (chars != NULL) { - return hash_string(chars, length, StringTable::_alt_hash); + return hash_string(chars, length, _alt_hash); } vm_exit_out_of_memory(length, OOM_MALLOC_ERROR, "get hash from oop"); return 0; @@ -196,8 +207,7 @@ static size_t ceil_log2(size_t val) { return ret; } -StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0), - _needs_rehashing(false), _weak_handles(NULL), _items_count(0), _uncleaned_items_count(0) { +void StringTable::create_table() { _weak_handles = new OopStorage("StringTable weak", StringTableWeakAlloc_lock, StringTableWeakActive_lock); @@ -208,33 +218,27 @@ StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0), _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN); } -void StringTable::update_needs_rehash(bool rehash) { - if (rehash) { - _needs_rehashing = true; - } -} - size_t StringTable::item_added() { - return Atomic::add((size_t)1, &(the_table()->_items_count)); + return Atomic::add((size_t)1, &_items_count); } size_t StringTable::add_items_to_clean(size_t ndead) { - size_t total = Atomic::add((size_t)ndead, &(the_table()->_uncleaned_items_count)); + size_t total = Atomic::add((size_t)ndead, &_uncleaned_items_count); log_trace(stringtable)( "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT, - the_table()->_uncleaned_items_count, ndead, total); + _uncleaned_items_count, ndead, total); return total; } void StringTable::item_removed() { - Atomic::add((size_t)-1, &(the_table()->_items_count)); + Atomic::add((size_t)-1, &_items_count); } -double StringTable::get_load_factor() const { +double StringTable::get_load_factor() { return (double)_items_count/_current_size; } -double StringTable::get_dead_factor() const { +double StringTable::get_dead_factor() { return (double)_uncleaned_items_count/_current_size; } @@ -244,7 +248,7 @@ size_t StringTable::table_size() { void StringTable::trigger_concurrent_work() { MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); - the_table()->_has_work = true; + _has_work = true; Service_lock->notify_all(); } @@ -258,14 +262,14 @@ oop StringTable::lookup(Symbol* symbol) { oop StringTable::lookup(const jchar* name, int len) { unsigned int hash = java_lang_String::hash_code(name, len); - oop string = StringTable::the_table()->lookup_shared(name, len, hash); + oop string = lookup_shared(name, len, hash); if (string != NULL) { return string; } - if (StringTable::_alt_hash) { + if (_alt_hash) { hash = hash_string(name, len, true); } - return StringTable::the_table()->do_lookup(name, len, hash); + return do_lookup(name, len, hash); } class StringTableGet : public StackObj { @@ -329,19 +333,18 @@ oop StringTable::intern(const char* utf8_string, TRAPS) { oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) { // shared table always uses java_lang_String::hash_code unsigned int hash = java_lang_String::hash_code(name, len); - oop found_string = StringTable::the_table()->lookup_shared(name, len, hash); + oop found_string = lookup_shared(name, len, hash); if (found_string != NULL) { return found_string; } - if (StringTable::_alt_hash) { + if (_alt_hash) { hash = hash_string(name, len, true); } - found_string = StringTable::the_table()->do_lookup(name, len, hash); + found_string = do_lookup(name, len, hash); if (found_string != NULL) { return found_string; } - return StringTable::the_table()->do_intern(string_or_null_h, name, len, - hash, CHECK_NULL); + return do_intern(string_or_null_h, name, len, hash, CHECK_NULL); } oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, @@ -384,15 +387,7 @@ oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, void StringTable::oops_do(OopClosure* f) { assert(f != NULL, "No closure"); - StringTable::the_table()->_weak_handles->oops_do(f); -} - -void StringTable::possibly_parallel_oops_do( - OopStorage::ParState* - _par_state_string, OopClosure* f) -{ - assert(f != NULL, "No closure"); - _par_state_string->oops_do(f); + _weak_handles->oops_do(f); } // Concurrent work @@ -480,7 +475,7 @@ void StringTable::check_concurrent_work() { } } -void StringTable::concurrent_work(JavaThread* jt) { +void StringTable::do_concurrent_work(JavaThread* jt) { _has_work = false; double load_factor = get_load_factor(); log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor); @@ -492,10 +487,6 @@ void StringTable::concurrent_work(JavaThread* jt) { } } -void StringTable::do_concurrent_work(JavaThread* jt) { - StringTable::the_table()->concurrent_work(jt); -} - // Rehash bool StringTable::do_rehash() { if (!_local_table->is_safepoint_safe()) { @@ -519,7 +510,7 @@ bool StringTable::do_rehash() { return true; } -void StringTable::try_rehash_table() { +void StringTable::rehash_table() { static bool rehashed = false; log_debug(stringtable)("Table imbalanced, rehashing called."); @@ -550,10 +541,6 @@ void StringTable::try_rehash_table() { _needs_rehashing = false; } -void StringTable::rehash_table() { - StringTable::the_table()->try_rehash_table(); -} - // Statistics static int literal_size(oop obj) { // NOTE: this would over-count if (pre-JDK8) @@ -609,7 +596,7 @@ class VerifyStrings : StackObj { void StringTable::verify() { Thread* thr = Thread::current(); VerifyStrings vs; - if (!the_table()->_local_table->try_scan(thr, vs)) { + if (!_local_table->try_scan(thr, vs)) { log_info(stringtable)("verify unavailable at this moment"); } } @@ -642,10 +629,10 @@ size_t StringTable::verify_and_compare_entries() { Thread* thr = Thread::current(); GrowableArray* oops = new (ResourceObj::C_HEAP, mtInternal) - GrowableArray((int)the_table()->_current_size, true); + GrowableArray((int)_current_size, true); VerifyCompStrings vcs(oops); - if (!the_table()->_local_table->try_scan(thr, vcs)) { + if (!_local_table->try_scan(thr, vcs)) { log_info(stringtable)("verify unavailable at this moment"); } delete oops; @@ -692,13 +679,13 @@ class PrintString : StackObj { void StringTable::dump(outputStream* st, bool verbose) { if (!verbose) { - the_table()->print_table_statistics(st, "StringTable"); + print_table_statistics(st, "StringTable"); } else { Thread* thr = Thread::current(); ResourceMark rm(thr); st->print_cr("VERSION: 1.1"); PrintString ps(thr, st); - if (!the_table()->_local_table->try_scan(thr, ps)) { + if (!_local_table->try_scan(thr, ps)) { st->print_cr("dump unavailable at this moment"); } } @@ -785,15 +772,14 @@ void StringTable::copy_shared_string_table(CompactHashtableWriter* writer) { assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); CopyToArchive copy(writer); - StringTable::the_table()->_local_table->do_safepoint_scan(copy); + _local_table->do_safepoint_scan(copy); } void StringTable::write_to_archive() { assert(HeapShared::is_heap_object_archiving_allowed(), "must be"); _shared_table.reset(); - int num_buckets = CompactHashtableWriter::default_num_buckets( - StringTable::the_table()->_items_count); + int num_buckets = CompactHashtableWriter::default_num_buckets(_items_count); CompactHashtableWriter writer(num_buckets, &MetaspaceShared::stats()->string); diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 679a16b4a5c..538499917e3 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -26,21 +26,17 @@ #define SHARE_CLASSFILE_STRINGTABLE_HPP #include "gc/shared/oopStorage.hpp" -#include "gc/shared/oopStorageParState.hpp" #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/oop.hpp" #include "oops/weakHandle.hpp" -#include "utilities/concurrentHashTable.hpp" +#include "utilities/tableStatistics.hpp" class CompactHashtableWriter; class SerializeClosure; class StringTable; class StringTableConfig; -typedef ConcurrentHashTable, - StringTableConfig, mtSymbol> StringTableHash; - class StringTableCreateEntry; class StringTable : public CHeapObj{ @@ -49,94 +45,64 @@ class StringTable : public CHeapObj{ friend class StringTableConfig; friend class StringTableCreateEntry; -private: - void grow(JavaThread* jt); - void clean_dead_entries(JavaThread* jt); + static volatile bool _has_work; + static volatile size_t _uncleaned_items_count; - // The string table - static StringTable* _the_table; - static volatile bool _alt_hash; - -private: - - StringTableHash* _local_table; - size_t _current_size; - volatile bool _has_work; // Set if one bucket is out of balance due to hash algorithm deficiency - volatile bool _needs_rehashing; + static volatile bool _needs_rehashing; - OopStorage* _weak_handles; + static OopStorage* _weak_handles; - volatile size_t _items_count; - DEFINE_PAD_MINUS_SIZE(1, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t)); - volatile size_t _uncleaned_items_count; - DEFINE_PAD_MINUS_SIZE(2, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t)); + static void grow(JavaThread* jt); + static void clean_dead_entries(JavaThread* jt); - double get_load_factor() const; - double get_dead_factor() const; + static double get_load_factor(); + static double get_dead_factor(); - void check_concurrent_work(); - void trigger_concurrent_work(); + static void check_concurrent_work(); + static void trigger_concurrent_work(); static size_t item_added(); static void item_removed(); - size_t add_items_to_clean(size_t ndead); - - StringTable(); + static size_t add_items_to_clean(size_t ndead); static oop intern(Handle string_or_null_h, const jchar* name, int len, TRAPS); - oop do_intern(Handle string_or_null, const jchar* name, int len, uintx hash, TRAPS); - oop do_lookup(const jchar* name, int len, uintx hash); + static oop do_intern(Handle string_or_null, const jchar* name, int len, uintx hash, TRAPS); + static oop do_lookup(const jchar* name, int len, uintx hash); - void concurrent_work(JavaThread* jt); - void print_table_statistics(outputStream* st, const char* table_name); + static void print_table_statistics(outputStream* st, const char* table_name); - void try_rehash_table(); - bool do_rehash(); - inline void update_needs_rehash(bool rehash); + static bool do_rehash(); public: - // The string table - static StringTable* the_table() { return _the_table; } - size_t table_size(); - TableStatistics get_table_statistics(); + static size_t table_size(); + static TableStatistics get_table_statistics(); - static OopStorage* weak_storage() { return the_table()->_weak_handles; } + static OopStorage* weak_storage() { return _weak_handles; } - static void create_table() { - assert(_the_table == NULL, "One string table allowed."); - _the_table = new StringTable(); - } + static void create_table(); static void do_concurrent_work(JavaThread* jt); - static bool has_work() { return the_table()->_has_work; } + static bool has_work() { return _has_work; } // GC support // Must be called before a parallel walk where strings might die. - static void reset_dead_counter() { - the_table()->_uncleaned_items_count = 0; - } + static void reset_dead_counter() { _uncleaned_items_count = 0; } + // After the parallel walk this method must be called to trigger // cleaning. Note it might trigger a resize instead. - static void finish_dead_counter() { - the_table()->check_concurrent_work(); - } + static void finish_dead_counter() { check_concurrent_work(); } // If GC uses ParState directly it should add the number of cleared // strings to this method. - static void inc_dead_counter(size_t ndead) { - the_table()->add_items_to_clean(ndead); - } + static void inc_dead_counter(size_t ndead) { add_items_to_clean(ndead); } // Serially invoke "f->do_oop" on the locations of all oops in the table. + // Used by JFR leak profiler. TODO: it should find these oops through + // the WeakProcessor. static void oops_do(OopClosure* f); - // Possibly parallel versions of the above - static void possibly_parallel_oops_do( - OopStorage::ParState* par_state_string, - OopClosure* f); - // Probing static oop lookup(Symbol* symbol); static oop lookup(const jchar* chars, int length); @@ -148,12 +114,16 @@ private: // Rehash the string table if it gets out of balance static void rehash_table(); - static bool needs_rehashing() - { return StringTable::the_table()->_needs_rehashing; } + static bool needs_rehashing() { return _needs_rehashing; } + static inline void update_needs_rehash(bool rehash) { + if (rehash) { + _needs_rehashing = true; + } + } // Sharing private: - oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL); + static oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL); static void copy_shared_string_table(CompactHashtableWriter* ch_table) NOT_CDS_JAVA_HEAP_RETURN; public: static oop create_archived_string(oop s, Thread* THREAD) NOT_CDS_JAVA_HEAP_RETURN_(NULL); diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index fd65bc1e05b..a23cf440b4f 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -70,9 +70,26 @@ static OffsetCompactHashtable< > _shared_table; // -------------------------------------------------------------------------- -SymbolTable* SymbolTable::_the_table = NULL; -volatile bool SymbolTable::_alt_hash = false; -volatile bool SymbolTable::_lookup_shared_first = false; + +typedef ConcurrentHashTable SymbolTableHash; +static SymbolTableHash* _local_table = NULL; + +volatile bool SymbolTable::_has_work = 0; +volatile bool SymbolTable::_needs_rehashing = false; + +// For statistics +static size_t _symbols_removed = 0; +static size_t _symbols_counted = 0; +static size_t _current_size = 0; + +static volatile size_t _items_count = 0; +static volatile bool _has_items_to_clean = false; + + +static volatile bool _alt_hash = false; +static volatile bool _lookup_shared_first = false; + // Static arena for symbols that are not deallocated Arena* SymbolTable::_arena = NULL; @@ -104,7 +121,7 @@ public: if (*is_dead) { return 0; } else { - return hash_symbol((const char*)value->bytes(), value->utf8_length(), SymbolTable::_alt_hash); + return hash_symbol((const char*)value->bytes(), value->utf8_length(), _alt_hash); } } // We use default allocation/deallocation but counted @@ -136,16 +153,19 @@ static size_t ceil_log2(size_t value) { return ret; } -SymbolTable::SymbolTable() : - _symbols_removed(0), _symbols_counted(0), _local_table(NULL), - _current_size(0), _has_work(0), _needs_rehashing(false), - _items_count(0), _has_items_to_clean(false) { - +void SymbolTable::create_table () { size_t start_size_log_2 = ceil_log2(SymbolTableSize); _current_size = ((size_t)1) << start_size_log_2; log_trace(symboltable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", _current_size, start_size_log_2); _local_table = new SymbolTableHash(start_size_log_2, END_SIZE, REHASH_LEN); + + // Initialize the arena for global symbols, size passed in depends on CDS. + if (symbol_alloc_arena_size == 0) { + _arena = new (mtSymbol) Arena(mtSymbol); + } else { + _arena = new (mtSymbol) Arena(mtSymbol, symbol_alloc_arena_size); + } } void SymbolTable::delete_symbol(Symbol* sym) { @@ -162,26 +182,20 @@ void SymbolTable::delete_symbol(Symbol* sym) { } } -void SymbolTable::update_needs_rehash(bool rehash) { - if (rehash) { - _needs_rehashing = true; - } -} - void SymbolTable::reset_has_items_to_clean() { Atomic::store(false, &_has_items_to_clean); } void SymbolTable::mark_has_items_to_clean() { Atomic::store(true, &_has_items_to_clean); } -bool SymbolTable::has_items_to_clean() const { return Atomic::load(&_has_items_to_clean); } +bool SymbolTable::has_items_to_clean() { return Atomic::load(&_has_items_to_clean); } void SymbolTable::item_added() { - Atomic::inc(&(SymbolTable::the_table()->_items_count)); + Atomic::inc(&_items_count); } void SymbolTable::item_removed() { - Atomic::inc(&(SymbolTable::the_table()->_symbols_removed)); - Atomic::dec(&(SymbolTable::the_table()->_items_count)); + Atomic::inc(&(_symbols_removed)); + Atomic::dec(&_items_count); } -double SymbolTable::get_load_factor() const { +double SymbolTable::get_load_factor() { return (double)_items_count/_current_size; } @@ -191,7 +205,7 @@ size_t SymbolTable::table_size() { void SymbolTable::trigger_cleanup() { MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); - SymbolTable::the_table()->_has_work = true; + _has_work = true; Service_lock->notify_all(); } @@ -214,15 +228,6 @@ Symbol* SymbolTable::allocate_symbol(const char* name, int len, bool c_heap) { return sym; } -void SymbolTable::initialize_symbols(int arena_alloc_size) { - // Initialize the arena for global symbols, size passed in depends on CDS. - if (arena_alloc_size == 0) { - _arena = new (mtSymbol) Arena(mtSymbol); - } else { - _arena = new (mtSymbol) Arena(mtSymbol, arena_alloc_size); - } -} - class SymbolsDo : StackObj { SymbolClosure *_cl; public: @@ -252,7 +257,7 @@ void SymbolTable::symbols_do(SymbolClosure *cl) { // all symbols from the dynamic table SymbolsDo sd(cl); - if (!SymbolTable::the_table()->_local_table->try_scan(Thread::current(), sd)) { + if (!_local_table->try_scan(Thread::current(), sd)) { log_info(stringtable)("symbols_do unavailable at this moment"); } } @@ -272,12 +277,12 @@ public: void SymbolTable::metaspace_pointers_do(MetaspaceClosure* it) { assert(DumpSharedSpaces, "called only during dump time"); MetaspacePointersDo mpd(it); - SymbolTable::the_table()->_local_table->do_safepoint_scan(mpd); + _local_table->do_safepoint_scan(mpd); } Symbol* SymbolTable::lookup_dynamic(const char* name, int len, unsigned int hash) { - Symbol* sym = SymbolTable::the_table()->do_lookup(name, len, hash); + Symbol* sym = do_lookup(name, len, hash); assert((sym == NULL) || sym->refcount() != 0, "refcount must not be zero"); return sym; } @@ -285,7 +290,7 @@ Symbol* SymbolTable::lookup_dynamic(const char* name, Symbol* SymbolTable::lookup_shared(const char* name, int len, unsigned int hash) { if (!_shared_table.empty()) { - if (SymbolTable::_alt_hash) { + if (_alt_hash) { // hash_code parameter may use alternate hashing algorithm but the shared table // always uses the same original hash code. hash = hash_shared_symbol(name, len); @@ -318,10 +323,10 @@ Symbol* SymbolTable::lookup_common(const char* name, } Symbol* SymbolTable::new_symbol(const char* name, int len) { - unsigned int hash = hash_symbol(name, len, SymbolTable::_alt_hash); - Symbol* sym = SymbolTable::the_table()->lookup_common(name, len, hash); + unsigned int hash = hash_symbol(name, len, _alt_hash); + Symbol* sym = lookup_common(name, len, hash); if (sym == NULL) { - sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true); + sym = do_add_if_needed(name, len, hash, true); } assert(sym->refcount() != 0, "lookup should have incremented the count"); assert(sym->equals(name, len), "symbol must be properly initialized"); @@ -333,10 +338,10 @@ Symbol* SymbolTable::new_symbol(const Symbol* sym, int begin, int end) { assert(sym->refcount() != 0, "require a valid symbol"); const char* name = (const char*)sym->base() + begin; int len = end - begin; - unsigned int hash = hash_symbol(name, len, SymbolTable::_alt_hash); - Symbol* found = SymbolTable::the_table()->lookup_common(name, len, hash); + unsigned int hash = hash_symbol(name, len, _alt_hash); + Symbol* found = lookup_common(name, len, hash); if (found == NULL) { - found = SymbolTable::the_table()->do_add_if_needed(name, len, hash, true); + found = do_add_if_needed(name, len, hash, true); } return found; } @@ -400,8 +405,8 @@ Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) { } Symbol* SymbolTable::lookup_only(const char* name, int len, unsigned int& hash) { - hash = hash_symbol(name, len, SymbolTable::_alt_hash); - return SymbolTable::the_table()->lookup_common(name, len, hash); + hash = hash_symbol(name, len, _alt_hash); + return lookup_common(name, len, hash); } // Suggestion: Push unicode-based lookup all the way into the hashing @@ -446,8 +451,8 @@ void SymbolTable::new_symbols(ClassLoaderData* loader_data, const constantPoolHa const char *name = names[i]; int len = lengths[i]; unsigned int hash = hashValues[i]; - assert(SymbolTable::the_table()->lookup_shared(name, len, hash) == NULL, "must have checked already"); - Symbol* sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, c_heap); + assert(lookup_shared(name, len, hash) == NULL, "must have checked already"); + Symbol* sym = do_add_if_needed(name, len, hash, c_heap); assert(sym->refcount() != 0, "lookup should have incremented the count"); cp->symbol_at_put(cp_indices[i], sym); } @@ -466,7 +471,7 @@ Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, boo sym = stg.get_res_sym(); break; } - sym = SymbolTable::the_table()->allocate_symbol(name, len, heap); + sym = allocate_symbol(name, len, heap); if (_local_table->insert(THREAD, lookup, sym, &rehash_warning, &clean_hint)) { break; } @@ -488,7 +493,7 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) { int len = (int)strlen(name); Symbol* sym = SymbolTable::lookup_only(name, len, hash); if (sym == NULL) { - sym = SymbolTable::the_table()->do_add_if_needed(name, len, hash, false); + sym = do_add_if_needed(name, len, hash, false); } if (!sym->is_permanent()) { sym->make_permanent(); @@ -534,7 +539,7 @@ public: void SymbolTable::verify() { Thread* thr = Thread::current(); VerifySymbols vs; - if (!SymbolTable::the_table()->_local_table->try_scan(thr, vs)) { + if (!_local_table->try_scan(thr, vs)) { log_info(stringtable)("verify unavailable at this moment"); } } @@ -560,13 +565,13 @@ public: void SymbolTable::dump(outputStream* st, bool verbose) { if (!verbose) { - SymbolTable::the_table()->print_table_statistics(st, "SymbolTable"); + print_table_statistics(st, "SymbolTable"); } else { Thread* thr = Thread::current(); ResourceMark rm(thr); st->print_cr("VERSION: 1.1"); DumpSymbol ds(thr, st); - if (!SymbolTable::the_table()->_local_table->try_scan(thr, ds)) { + if (!_local_table->try_scan(thr, ds)) { log_info(symboltable)("dump unavailable at this moment"); } } @@ -590,14 +595,14 @@ struct CopyToArchive : StackObj { void SymbolTable::copy_shared_symbol_table(CompactHashtableWriter* writer) { CopyToArchive copy(writer); - SymbolTable::the_table()->_local_table->do_safepoint_scan(copy); + _local_table->do_safepoint_scan(copy); } void SymbolTable::write_to_archive() { _shared_table.reset(); int num_buckets = CompactHashtableWriter::default_num_buckets( - SymbolTable::the_table()->_items_count); + _items_count); CompactHashtableWriter writer(num_buckets, &MetaspaceShared::stats()->symbol); copy_shared_symbol_table(&writer); @@ -607,7 +612,7 @@ void SymbolTable::write_to_archive() { Symbol* sym = vmSymbols::java_lang_Object(); const char* name = (const char*)sym->bytes(); int len = sym->utf8_length(); - unsigned int hash = hash_symbol(name, len, SymbolTable::_alt_hash); + unsigned int hash = hash_symbol(name, len, _alt_hash); assert(sym == _shared_table.lookup(name, hash, len), "sanity"); } @@ -684,7 +689,7 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) { } bdt.cont(jt); } - SymbolTable::the_table()->reset_has_items_to_clean(); + reset_has_items_to_clean(); bdt.done(jt); } @@ -708,7 +713,7 @@ void SymbolTable::check_concurrent_work() { } } -void SymbolTable::concurrent_work(JavaThread* jt) { +void SymbolTable::do_concurrent_work(JavaThread* jt) { double load_factor = get_load_factor(); log_debug(symboltable, perf)("Concurrent work, live factor: %g", load_factor); // We prefer growing, since that also removes dead items @@ -720,10 +725,6 @@ void SymbolTable::concurrent_work(JavaThread* jt) { _has_work = false; } -void SymbolTable::do_concurrent_work(JavaThread* jt) { - SymbolTable::the_table()->concurrent_work(jt); -} - // Rehash bool SymbolTable::do_rehash() { if (!_local_table->is_safepoint_safe()) { @@ -747,7 +748,7 @@ bool SymbolTable::do_rehash() { return true; } -void SymbolTable::try_rehash_table() { +void SymbolTable::rehash_table() { static bool rehashed = false; log_debug(symboltable)("Table imbalanced, rehashing called."); @@ -779,10 +780,6 @@ void SymbolTable::try_rehash_table() { _needs_rehashing = false; } -void SymbolTable::rehash_table() { - SymbolTable::the_table()->try_rehash_table(); -} - //--------------------------------------------------------------------------- // Non-product code @@ -830,18 +827,17 @@ public: }; void SymbolTable::print_histogram() { - SymbolTable* st = SymbolTable::the_table(); HistogramIterator hi; - st->_local_table->do_scan(Thread::current(), hi); + _local_table->do_scan(Thread::current(), hi); tty->print_cr("Symbol Table Histogram:"); tty->print_cr(" Total number of symbols " SIZE_FORMAT_W(7), hi.total_count); tty->print_cr(" Total size in memory " SIZE_FORMAT_W(7) "K", (hi.total_size * wordSize) / 1024); - tty->print_cr(" Total counted " SIZE_FORMAT_W(7), st->_symbols_counted); - tty->print_cr(" Total removed " SIZE_FORMAT_W(7), st->_symbols_removed); - if (SymbolTable::the_table()->_symbols_counted > 0) { + tty->print_cr(" Total counted " SIZE_FORMAT_W(7), _symbols_counted); + tty->print_cr(" Total removed " SIZE_FORMAT_W(7), _symbols_removed); + if (_symbols_counted > 0) { tty->print_cr(" Percent removed %3.2f", - ((float)st->_symbols_removed / st->_symbols_counted) * 100); + ((float)_symbols_removed / _symbols_counted) * 100); } tty->print_cr(" Reference counts " SIZE_FORMAT_W(7), Symbol::_total_count); tty->print_cr(" Symbol arena used " SIZE_FORMAT_W(7) "K", arena()->used() / 1024); diff --git a/src/hotspot/share/classfile/symbolTable.hpp b/src/hotspot/share/classfile/symbolTable.hpp index 58100ba20a9..794c8e3b626 100644 --- a/src/hotspot/share/classfile/symbolTable.hpp +++ b/src/hotspot/share/classfile/symbolTable.hpp @@ -28,8 +28,7 @@ #include "memory/allocation.hpp" #include "memory/padded.hpp" #include "oops/symbol.hpp" -#include "utilities/concurrentHashTable.hpp" -#include "utilities/hashtable.hpp" +#include "utilities/tableStatistics.hpp" class JavaThread; @@ -90,58 +89,43 @@ class CompactHashtableWriter; class SerializeClosure; class SymbolTableConfig; -typedef ConcurrentHashTable SymbolTableHash; - class SymbolTableCreateEntry; -class SymbolTable : public CHeapObj { +class constantPoolHandle; +class SymbolClosure; + +class SymbolTable : public AllStatic { friend class VMStructs; friend class Symbol; friend class ClassFileParser; friend class SymbolTableConfig; friend class SymbolTableCreateEntry; -private: - static void delete_symbol(Symbol* sym); - void grow(JavaThread* jt); - void clean_dead_entries(JavaThread* jt); + private: + static volatile bool _has_work; - // The symbol table - static SymbolTable* _the_table; - static volatile bool _lookup_shared_first; - static volatile bool _alt_hash; - - // For statistics - volatile size_t _symbols_removed; - volatile size_t _symbols_counted; - - SymbolTableHash* _local_table; - size_t _current_size; - volatile bool _has_work; // Set if one bucket is out of balance due to hash algorithm deficiency - volatile bool _needs_rehashing; + static volatile bool _needs_rehashing; - volatile size_t _items_count; - volatile bool _has_items_to_clean; + static void delete_symbol(Symbol* sym); + static void grow(JavaThread* jt); + static void clean_dead_entries(JavaThread* jt); - double get_load_factor() const; + static double get_load_factor(); - void check_concurrent_work(); + static void check_concurrent_work(); static void item_added(); static void item_removed(); // For cleaning - void reset_has_items_to_clean(); - void mark_has_items_to_clean(); - bool has_items_to_clean() const; + static void reset_has_items_to_clean(); + static void mark_has_items_to_clean(); + static bool has_items_to_clean(); - SymbolTable(); - - Symbol* allocate_symbol(const char* name, int len, bool c_heap); // Assumes no characters larger than 0x7F - Symbol* do_lookup(const char* name, int len, uintx hash); - Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap); + static Symbol* allocate_symbol(const char* name, int len, bool c_heap); // Assumes no characters larger than 0x7F + static Symbol* do_lookup(const char* name, int len, uintx hash); + static Symbol* do_add_if_needed(const char* name, int len, uintx hash, bool heap); // lookup only, won't add. Also calculate hash. Used by the ClassfileParser. static Symbol* lookup_only(const char* name, int len, unsigned int& hash); @@ -154,27 +138,22 @@ private: int* cp_indices, unsigned int* hashValues); static Symbol* lookup_shared(const char* name, int len, unsigned int hash); - Symbol* lookup_dynamic(const char* name, int len, unsigned int hash); - Symbol* lookup_common(const char* name, int len, unsigned int hash); + static Symbol* lookup_dynamic(const char* name, int len, unsigned int hash); + static Symbol* lookup_common(const char* name, int len, unsigned int hash); // Arena for permanent symbols (null class loader) that are never unloaded static Arena* _arena; static Arena* arena() { return _arena; } // called for statistics - static void initialize_symbols(int arena_alloc_size = 0); + static void print_table_statistics(outputStream* st, const char* table_name); - void concurrent_work(JavaThread* jt); - void print_table_statistics(outputStream* st, const char* table_name); - - void try_rehash_table(); - bool do_rehash(); - inline void update_needs_rehash(bool rehash); + static void try_rehash_table(); + static bool do_rehash(); public: // The symbol table - static SymbolTable* the_table() { return _the_table; } - size_t table_size(); - TableStatistics get_table_statistics(); + static size_t table_size(); + static TableStatistics get_table_statistics(); enum { symbol_alloc_batch_size = 8, @@ -182,14 +161,10 @@ public: symbol_alloc_arena_size = 360*K // TODO (revisit) }; - static void create_table() { - assert(_the_table == NULL, "One symbol table allowed."); - _the_table = new SymbolTable(); - initialize_symbols(symbol_alloc_arena_size); - } + static void create_table(); static void do_concurrent_work(JavaThread* jt); - static bool has_work() { return the_table()->_has_work; } + static bool has_work() { return _has_work; } static void trigger_cleanup(); // Probing @@ -220,8 +195,12 @@ public: // Rehash the string table if it gets out of balance static void rehash_table(); - static bool needs_rehashing() - { return SymbolTable::the_table()->_needs_rehashing; } + static bool needs_rehashing() { return _needs_rehashing; } + static inline void update_needs_rehash(bool rehash) { + if (rehash) { + _needs_rehashing = true; + } + } // Heap dumper and CDS static void symbols_do(SymbolClosure *cl); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0d81c9c85ef..ef2b79d4599 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -525,12 +525,12 @@ static void emit_table_statistics(TableStatistics statistics) { } TRACE_REQUEST_FUNC(SymbolTableStatistics) { - TableStatistics statistics = SymbolTable::the_table()->get_table_statistics(); + TableStatistics statistics = SymbolTable::get_table_statistics(); emit_table_statistics(statistics); } TRACE_REQUEST_FUNC(StringTableStatistics) { - TableStatistics statistics = StringTable::the_table()->get_table_statistics(); + TableStatistics statistics = StringTable::get_table_statistics(); emit_table_statistics(statistics); } diff --git a/src/hotspot/share/prims/resolvedMethodTable.cpp b/src/hotspot/share/prims/resolvedMethodTable.cpp index 129c73b58e0..106f3b3b290 100644 --- a/src/hotspot/share/prims/resolvedMethodTable.cpp +++ b/src/hotspot/share/prims/resolvedMethodTable.cpp @@ -56,6 +56,10 @@ unsigned int method_hash(const Method* method) { return name_hash ^ signature_hash; } +typedef ConcurrentHashTable, + ResolvedMethodTableConfig, + mtClass> ResolvedMethodTableHash; + class ResolvedMethodTableConfig : public ResolvedMethodTableHash::BaseConfig { private: public: @@ -83,14 +87,14 @@ class ResolvedMethodTableConfig : public ResolvedMethodTableHash::BaseConfig { } }; -ResolvedMethodTableHash* ResolvedMethodTable::_local_table = NULL; -size_t ResolvedMethodTable::_current_size = (size_t)1 << ResolvedMethodTableSizeLog; +static ResolvedMethodTableHash* _local_table = NULL; +static size_t _current_size = (size_t)1 << ResolvedMethodTableSizeLog; OopStorage* ResolvedMethodTable::_weak_handles = NULL; - volatile bool ResolvedMethodTable::_has_work = false; -volatile size_t ResolvedMethodTable::_items_count = 0; -volatile size_t ResolvedMethodTable::_uncleaned_items_count = 0; + +volatile size_t _items_count = 0; +volatile size_t _uncleaned_items_count = 0; void ResolvedMethodTable::create_table() { _local_table = new ResolvedMethodTableHash(ResolvedMethodTableSizeLog, END_SIZE, GROW_HINT); @@ -209,14 +213,6 @@ void ResolvedMethodTable::item_removed() { log_trace(membername, table) ("ResolvedMethod entry removed"); } -bool ResolvedMethodTable::has_work() { - return _has_work; -} - -OopStorage* ResolvedMethodTable::weak_storage() { - return _weak_handles; -} - double ResolvedMethodTable::get_load_factor() { return (double)_items_count/_current_size; } diff --git a/src/hotspot/share/prims/resolvedMethodTable.hpp b/src/hotspot/share/prims/resolvedMethodTable.hpp index f7bf176ad66..3291156291d 100644 --- a/src/hotspot/share/prims/resolvedMethodTable.hpp +++ b/src/hotspot/share/prims/resolvedMethodTable.hpp @@ -26,28 +26,17 @@ #define SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP #include "gc/shared/oopStorage.hpp" -#include "gc/shared/oopStorageParState.hpp" #include "memory/allocation.hpp" #include "oops/symbol.hpp" #include "oops/weakHandle.hpp" -#include "utilities/concurrentHashTable.hpp" -#include "utilities/hashtable.hpp" class ResolvedMethodTable; class ResolvedMethodTableConfig; -typedef ConcurrentHashTable, ResolvedMethodTableConfig, mtClass> ResolvedMethodTableHash; class ResolvedMethodTable : public AllStatic { - static ResolvedMethodTableHash* _local_table; - static size_t _current_size; - static OopStorage* _weak_handles; static volatile bool _has_work; - - static volatile size_t _items_count; - static volatile size_t _uncleaned_items_count; - public: // Initialization static void create_table(); @@ -63,10 +52,10 @@ public: static void item_removed(); // Cleaning - static bool has_work(); + static bool has_work() { return _has_work; } // GC Support - Backing storage for the oop*s - static OopStorage* weak_storage(); + static OopStorage* weak_storage() { return _weak_handles; } // Cleaning and table management From a5b7966e815b11dd624b6da4bdf3fbbfe3a0fd15 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 16 May 2019 13:57:35 +0200 Subject: [PATCH 018/263] 8224023: Redo the fix for ErrorFile option does not handle pre-existing error files of the same name Reviewed-by: clanger, dholmes --- src/hotspot/share/utilities/vmError.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 64194085e50..dd3f5fbddfc 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1195,10 +1195,16 @@ void VMError::print_vm_info(outputStream* st) { volatile intptr_t VMError::first_error_tid = -1; /** Expand a pattern into a buffer starting at pos and open a file using constructed path */ -static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { +static int expand_and_open(const char* pattern, bool overwrite_existing, char* buf, size_t buflen, size_t pos) { int fd = -1; + int mode = O_RDWR | O_CREAT; + if (overwrite_existing) { + mode |= O_TRUNC; + } else { + mode |= O_EXCL; + } if (Arguments::copy_expand_pid(pattern, strlen(pattern), &buf[pos], buflen - pos)) { - fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666); + fd = open(buf, mode, 0666); } return fd; } @@ -1208,12 +1214,12 @@ static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t * Name and location depends on pattern, default_pattern params and access * permissions. */ -static int prepare_log_file(const char* pattern, const char* default_pattern, char* buf, size_t buflen) { +static int prepare_log_file(const char* pattern, const char* default_pattern, bool overwrite_existing, char* buf, size_t buflen) { int fd = -1; // If possible, use specified pattern to construct log file name if (pattern != NULL) { - fd = expand_and_open(pattern, buf, buflen, 0); + fd = expand_and_open(pattern, overwrite_existing, buf, buflen, 0); } // Either user didn't specify, or the user's location failed, @@ -1225,7 +1231,7 @@ static int prepare_log_file(const char* pattern, const char* default_pattern, ch int fsep_len = jio_snprintf(&buf[pos], buflen-pos, "%s", os::file_separator()); pos += fsep_len; if (fsep_len > 0) { - fd = expand_and_open(default_pattern, buf, buflen, pos); + fd = expand_and_open(default_pattern, overwrite_existing, buf, buflen, pos); } } } @@ -1236,7 +1242,7 @@ static int prepare_log_file(const char* pattern, const char* default_pattern, ch if (tmpdir != NULL && strlen(tmpdir) > 0) { int pos = jio_snprintf(buf, buflen, "%s%s", tmpdir, os::file_separator()); if (pos > 0) { - fd = expand_and_open(default_pattern, buf, buflen, pos); + fd = expand_and_open(default_pattern, overwrite_existing, buf, buflen, pos); } } } @@ -1471,7 +1477,8 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt } else if (ErrorFileToStderr) { fd_log = 2; } else { - fd_log = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer)); + fd_log = prepare_log_file(ErrorFile, "hs_err_pid%p.log", true, + buffer, sizeof(buffer)); if (fd_log != -1) { out.print_raw("# An error report file with more information is saved as:\n# "); out.print_raw_cr(buffer); @@ -1501,7 +1508,8 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt skip_replay = true; ciEnv* env = ciEnv::current(); if (env != NULL) { - int fd = prepare_log_file(ReplayDataFile, "replay_pid%p.log", buffer, sizeof(buffer)); + const bool overwrite = false; // We do not overwrite an existing replay file. + int fd = prepare_log_file(ReplayDataFile, "replay_pid%p.log", overwrite, buffer, sizeof(buffer)); if (fd != -1) { FILE* replay_data_file = os::open(fd, "w"); if (replay_data_file != NULL) { From 4e38fe2957cbe02f410898e5792452173c368250 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Wed, 15 May 2019 12:30:02 +0200 Subject: [PATCH 019/263] 8223572: ~ThreadInVMForHandshake() should call handle_special_runtime_exit_condition() Reviewed-by: dcubed, rehn, dholmes --- src/hotspot/share/runtime/interfaceSupport.inline.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index 054fd30d2ef..b0a59a37218 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -137,6 +137,12 @@ class ThreadInVMForHandshake : public ThreadStateTransition { SafepointMechanism::block_if_requested(_thread); _thread->set_thread_state(_original_state); + + if (_original_state != _thread_blocked_trans && _original_state != _thread_in_vm_trans && + _thread->has_special_runtime_exit_condition()) { + _thread->handle_special_runtime_exit_condition( + !_thread->is_at_poll_safepoint() && (_original_state != _thread_in_native_trans)); + } } public: From c39088c391bf884fdf8277f223fb898bae7c9200 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 16 May 2019 09:21:49 +0200 Subject: [PATCH 020/263] 8223438: add VirtualizationInformation JFR event Reviewed-by: clanger, egahlin --- src/hotspot/cpu/ppc/vm_version_ppc.cpp | 48 +++++++++++++++- src/hotspot/cpu/ppc/vm_version_ppc.hpp | 3 +- src/hotspot/share/jfr/metadata/metadata.xml | 4 ++ .../share/jfr/periodic/jfrOSInterface.cpp | 21 +++++++ .../share/jfr/periodic/jfrOSInterface.hpp | 1 + .../share/jfr/periodic/jfrPeriodic.cpp | 6 ++ src/hotspot/share/runtime/vm_version.hpp | 5 +- src/jdk.jfr/share/conf/jfr/default.jfc | 5 ++ src/jdk.jfr/share/conf/jfr/profile.jfc | 5 ++ .../jfr/event/os/TestVirtualizationInfo.java | 57 +++++++++++++++++++ test/lib/jdk/test/lib/jfr/EventNames.java | 3 +- 11 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 447c93f3eae..90504ad13bd 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018, SAP SE. All rights reserved. + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019 SAP SE. 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 @@ -382,6 +382,50 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } + + check_virtualizations(); +} + +void VM_Version::check_virtualizations() { +#if defined(_AIX) + int rc = 0; + perfstat_partition_total_t pinfo; + rc = perfstat_partition_total(NULL, &pinfo, sizeof(perfstat_partition_total_t), 1); + if (rc == 1) { + Abstract_VM_Version::_detected_virtualization = PowerVM; + } +#else + const char* info_file = "/proc/ppc64/lparcfg"; + // system_type=...qemu indicates PowerKVM + // e.g. system_type=IBM pSeries (emulated by qemu) + char line[500]; + FILE* fp = fopen(info_file, "r"); + if (fp == NULL) { + return; + } + const char* system_type="system_type="; // in case this line contains qemu, it is KVM + const char* num_lpars="NumLpars="; // in case of non-KVM : if this line is found it is PowerVM + bool num_lpars_found = false; + + while (fgets(line, sizeof(line), fp) != NULL) { + if (strncmp(line, system_type, strlen(system_type)) == 0) { + if (strstr(line, "qemu") != 0) { + Abstract_VM_Version::_detected_virtualization = PowerKVM; + fclose(fp); + return; + } + } + if (strncmp(line, num_lpars, strlen(num_lpars)) == 0) { + num_lpars_found = true; + } + } + if (num_lpars_found) { + Abstract_VM_Version::_detected_virtualization = PowerVM; + } else { + Abstract_VM_Version::_detected_virtualization = PowerFullPartitionMode; + } + fclose(fp); +#endif } void VM_Version::print_platform_virtualization_info(outputStream* st) { diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp index 5d4a7cea652..787e1474387 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2012, 2019 SAP SE. 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 @@ -87,6 +87,7 @@ protected: public: // Initialization static void initialize(); + static void check_virtualizations(); // Override Abstract_VM_Version implementation static void print_platform_virtualization_info(outputStream*); diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 208b0db9067..63323c8373a 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -615,6 +615,10 @@ + + + + diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp index 331b249a735..52337f121c6 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp @@ -215,6 +215,27 @@ int JfrOSInterface::os_version(char** os_version) { return instance()._impl->os_version(os_version); } +const char* JfrOSInterface::virtualization_name() { + VirtualizationType vrt = VM_Version::get_detected_virtualization(); + if (vrt == XenHVM) { + return "Xen hardware-assisted virtualization"; + } else if (vrt == KVM) { + return "KVM virtualization"; + } else if (vrt == VMWare) { + return "VMWare virtualization"; + } else if (vrt == HyperV) { + return "HyperV virtualization"; + } else if (vrt == PowerVM) { + return "PowerVM virtualization"; + } else if (vrt == PowerKVM) { + return "Power KVM virtualization"; + } else if (vrt == PowerFullPartitionMode) { + return "Power full partition"; + } + + return "No virtualization detected"; +} + int JfrOSInterface::generate_initial_environment_variable_events() { if (environ == NULL) { return OS_ERR; diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp index 43e8a894a5c..141e7505efb 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp @@ -52,6 +52,7 @@ class JfrOSInterface: public JfrCHeapObj { static int cpu_load_total_process(double* cpu_load); static int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); static int os_version(char** os_version); + static const char* virtualization_name(); static int generate_initial_environment_variable_events(); static int system_processes(SystemProcess** system_processes, int* no_of_sys_processes); static int network_utilization(NetworkInterface** network_interfaces); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index ef2b79d4599..87a1a57550f 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -95,6 +95,12 @@ TRACE_REQUEST_FUNC(OSInformation) { event.commit(); } +TRACE_REQUEST_FUNC(VirtualizationInformation) { + EventVirtualizationInformation event; + event.set_name(JfrOSInterface::virtualization_name()); + event.commit(); +} + TRACE_REQUEST_FUNC(ModuleRequire) { JfrModuleEvent::generate_module_dependency_events(); } diff --git a/src/hotspot/share/runtime/vm_version.hpp b/src/hotspot/share/runtime/vm_version.hpp index 2d5633ef63c..67552b28bd5 100644 --- a/src/hotspot/share/runtime/vm_version.hpp +++ b/src/hotspot/share/runtime/vm_version.hpp @@ -34,7 +34,10 @@ typedef enum { XenHVM, KVM, VMWare, - HyperV + HyperV, + PowerVM, // on AIX or Linux ppc64(le) + PowerFullPartitionMode, // on Linux ppc64(le) + PowerKVM } VirtualizationType; // VM_Version provides information about the VM. diff --git a/src/jdk.jfr/share/conf/jfr/default.jfc b/src/jdk.jfr/share/conf/jfr/default.jfc index d37c3dba2ec..7bc5ebd9fe5 100644 --- a/src/jdk.jfr/share/conf/jfr/default.jfc +++ b/src/jdk.jfr/share/conf/jfr/default.jfc @@ -513,6 +513,11 @@ beginChunk + + true + beginChunk + + true beginChunk diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index d1c8dcf2d8f..21612bb2fe1 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -513,6 +513,11 @@ beginChunk + + true + beginChunk + + true beginChunk diff --git a/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java b/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java new file mode 100644 index 00000000000..b3a09191873 --- /dev/null +++ b/test/jdk/jdk/jfr/event/os/TestVirtualizationInfo.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013, 2019, 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.jfr.event.os; + +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.os.TestVirtualizationInfo + */ +public class TestVirtualizationInfo { + private final static String EVENT_NAME = EventNames.VirtualizationInformation; + + public static void main(String[] args) throws Throwable { + Recording recording = new Recording(); + recording.enable(EVENT_NAME); + recording.start(); + recording.stop(); + List events = Events.fromRecording(recording); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + Events.assertField(event, "name").notEmpty(); + } + } +} diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index fb89ab566c4..9b1d20f6164 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -154,6 +154,7 @@ public class EventNames { // OS public final static String OSInformation = PREFIX + "OSInformation"; + public final static String VirtualizationInformation = PREFIX + "VirtualizationInformation"; public final static String CPUInformation = PREFIX + "CPUInformation"; public final static String CPULoad = PREFIX + "CPULoad"; public final static String ThreadCPULoad = PREFIX + "ThreadCPULoad"; From 08193be19cd86bb4bc25c484df7609288f2892fe Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 16 May 2019 16:42:14 +0200 Subject: [PATCH 021/263] 8224031: Cannot parse switch expressions after type cast Correctly categorize parentheses followed by the switch keyword as cast. Reviewed-by: mcimadamore --- .../com/sun/tools/javac/parser/JavacParser.java | 1 + .../tools/javac/switchexpr/ExpressionSwitch-old.out | 6 +++--- .../tools/javac/switchexpr/ExpressionSwitch.java | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index d15e5518bbb..16bc58594b6 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1655,6 +1655,7 @@ public class JavacParser implements Parser { case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL: case TRUE: case FALSE: case NULL: case NEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE: + case SWITCH: case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID: return ParensResult.CAST; diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out index 13d4df20108..9e2a1c732ca 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch-old.out @@ -1,4 +1,4 @@ -ExpressionSwitch.java:39:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions) -ExpressionSwitch.java:40:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules) -ExpressionSwitch.java:92:31: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels) +ExpressionSwitch.java:40:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.expressions) +ExpressionSwitch.java:41:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.switch.rules) +ExpressionSwitch.java:93:31: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.multiple.case.labels) 3 errors diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java index cd7e408a48b..0bb47dfa96a 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 8222169 + * @bug 8206986 8222169 8224031 * @summary Check expression switch works. * @compile/fail/ref=ExpressionSwitch-old.out -source 9 -Xlint:-options -XDrawDiagnostics ExpressionSwitch.java * @compile --enable-preview -source ${jdk.version} ExpressionSwitch.java @@ -33,6 +33,7 @@ public class ExpressionSwitch { assertEquals(convert2("C"), 1); assertEquals(convert2(""), -1); localClass(T.A); + assertEquals(castSwitchExpressions(T.A), "A"); } private String print(T t) { @@ -121,6 +122,13 @@ public class ExpressionSwitch { } } + private String castSwitchExpressions(T t) { + return (String) switch (t) { + case A -> "A"; + default -> 1; + }; + } + private void check(T t, String expected) { String result = print(t); assertEquals(result, expected); From bc264ba95b848c3d82f95a2af3b4ccc73c61452a Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 16 May 2019 11:07:09 -0400 Subject: [PATCH 022/263] 8223585: vmTestbase/runtime/pcl/* get SEGV in MetadataOnStackClosure::do_metadata(Metadata*)+0x0 Adjust old method table by only one thread. Reviewed-by: kvn, jcbeyler, sspitsyn --- src/hotspot/share/code/codeCache.cpp | 8 ++++++-- src/hotspot/share/code/nmethod.cpp | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 1a964f47a93..738fb5b4d8f 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1055,7 +1055,7 @@ static void reset_old_method_table() { // Remove this method when zombied or unloaded. void CodeCache::unregister_old_nmethod(CompiledMethod* c) { - assert_locked_or_safepoint(CodeCache_lock); + assert_lock_strong(CodeCache_lock); if (old_compiled_method_table != NULL) { int index = old_compiled_method_table->find(c); if (index != -1) { @@ -1070,7 +1070,11 @@ void CodeCache::old_nmethods_do(MetadataClosure* f) { if (old_compiled_method_table != NULL) { length = old_compiled_method_table->length(); for (int i = 0; i < length; i++) { - old_compiled_method_table->at(i)->metadata_do(f); + CompiledMethod* cm = old_compiled_method_table->at(i); + // Only walk alive nmethods, the dead ones will get removed by the sweeper. + if (cm->is_alive()) { + old_compiled_method_table->at(i)->metadata_do(f); + } } } log_debug(redefine, class, nmethod)("Walked %d nmethods for mark_on_stack", length); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 0c12eeac172..9d589246be6 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1143,7 +1143,6 @@ void nmethod::make_unloaded() { MutexLocker ml(SafepointSynchronize::is_at_safepoint() ? NULL : CodeCache_lock, Mutex::_no_safepoint_check_flag); Universe::heap()->unregister_nmethod(this); - CodeCache::unregister_old_nmethod(this); } // Clear the method of this dead nmethod @@ -1336,7 +1335,6 @@ bool nmethod::make_not_entrant_or_zombie(int state) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); if (nmethod_needs_unregister) { Universe::heap()->unregister_nmethod(this); - CodeCache::unregister_old_nmethod(this); } flush_dependencies(/*delete_immediately*/true); } @@ -1415,6 +1413,7 @@ void nmethod::flush() { } Universe::heap()->flush_nmethod(this); + CodeCache::unregister_old_nmethod(this); CodeBlob::flush(); CodeCache::free(this); From a817ac34562ffa3fcbc91e26552d5e4f7ff5ebcc Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 16 May 2019 17:06:53 +0100 Subject: [PATCH 023/263] 8223442: java/nio/channels/SocketChannel/AdaptorStreams.java testConcurrentTimedReadWrite3(): failure Reviewed-by: michaelm --- .../sun/nio/ch/DatagramDispatcher.java | 29 +++++++------- .../classes/sun/nio/ch/SocketDispatcher.java | 29 +++++++++----- src/java.base/windows/native/libnio/ch/Net.c | 3 +- .../native/libnio/ch/SocketDispatcher.c | 18 +-------- .../SocketChannel/AdaptorStreams.java | 38 +++++++++++-------- 5 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java b/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java index 2464350d49c..c59dfabbced 100644 --- a/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java +++ b/src/java.base/windows/classes/sun/nio/ch/DatagramDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2019, 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,19 +25,16 @@ package sun.nio.ch; -import java.io.*; -import java.net.*; +import java.io.FileDescriptor; +import java.io.IOException; /** * Allows different platforms to call different native methods * for read and write operations. */ -class DatagramDispatcher extends NativeDispatcher -{ - static { - IOUtil.load(); - } +class DatagramDispatcher extends NativeDispatcher { + DatagramDispatcher() { } int read(FileDescriptor fd, long address, int len) throws IOException { return read0(fd, address, len); @@ -56,18 +53,24 @@ class DatagramDispatcher extends NativeDispatcher } void close(FileDescriptor fd) throws IOException { - SocketDispatcher.close0(fd); + SocketDispatcher.invalidateAndClose(fd); } - static native int read0(FileDescriptor fd, long address, int len) + // -- Native methods -- + + private static native int read0(FileDescriptor fd, long address, int len) throws IOException; - static native long readv0(FileDescriptor fd, long address, int len) + private static native long readv0(FileDescriptor fd, long address, int len) throws IOException; - static native int write0(FileDescriptor fd, long address, int len) + private static native int write0(FileDescriptor fd, long address, int len) throws IOException; - static native long writev0(FileDescriptor fd, long address, int len) + private static native long writev0(FileDescriptor fd, long address, int len) throws IOException; + + static { + IOUtil.load(); + } } diff --git a/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java b/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java index cb7bdf4d613..6ce751bddf7 100644 --- a/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java +++ b/src/java.base/windows/classes/sun/nio/ch/SocketDispatcher.java @@ -28,12 +28,18 @@ package sun.nio.ch; import java.io.FileDescriptor; import java.io.IOException; +import jdk.internal.access.JavaIOFileDescriptorAccess; +import jdk.internal.access.SharedSecrets; + /** * Allows different platforms to call different native methods * for read and write operations. */ class SocketDispatcher extends NativeDispatcher { + private static final JavaIOFileDescriptorAccess fdAccess = + SharedSecrets.getJavaIOFileDescriptorAccess(); + SocketDispatcher() { } int read(FileDescriptor fd, long address, int len) throws IOException { @@ -53,30 +59,35 @@ class SocketDispatcher extends NativeDispatcher { } void preClose(FileDescriptor fd) throws IOException { - preClose0(fd); + throw new UnsupportedOperationException(); } void close(FileDescriptor fd) throws IOException { - close0(fd); + invalidateAndClose(fd); + } + + static void invalidateAndClose(FileDescriptor fd) throws IOException { + assert fd.valid(); + int fdVal = fdAccess.get(fd); + fdAccess.set(fd, -1); + close0(fdVal); } // -- Native methods -- - static native int read0(FileDescriptor fd, long address, int len) + private static native int read0(FileDescriptor fd, long address, int len) throws IOException; - static native long readv0(FileDescriptor fd, long address, int len) + private static native long readv0(FileDescriptor fd, long address, int len) throws IOException; - static native int write0(FileDescriptor fd, long address, int len) + private static native int write0(FileDescriptor fd, long address, int len) throws IOException; - static native long writev0(FileDescriptor fd, long address, int len) + private static native long writev0(FileDescriptor fd, long address, int len) throws IOException; - static native void preClose0(FileDescriptor fd) throws IOException; - - static native void close0(FileDescriptor fd) throws IOException; + private static native void close0(int fdVal) throws IOException; static { IOUtil.load(); diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c index 353fdd0259d..c4292d9405b 100644 --- a/src/java.base/windows/native/libnio/ch/Net.c +++ b/src/java.base/windows/native/libnio/ch/Net.c @@ -620,7 +620,6 @@ Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlo int rv; int revents = 0; struct timeval t; - int lastError = 0; fd_set rd, wr, ex; jint fd = fdval(env, fdo); @@ -643,7 +642,7 @@ Java_sun_nio_ch_Net_poll(JNIEnv* env, jclass this, jobject fdo, jint events, jlo /* save last winsock error */ if (rv == SOCKET_ERROR) { - handleSocketError(env, lastError); + handleSocketError(env, WSAGetLastError()); return IOS_THROWN; } else if (rv >= 0) { rv = 0; diff --git a/src/java.base/windows/native/libnio/ch/SocketDispatcher.c b/src/java.base/windows/native/libnio/ch/SocketDispatcher.c index b0c8a766e1f..ff74a0abf10 100644 --- a/src/java.base/windows/native/libnio/ch/SocketDispatcher.c +++ b/src/java.base/windows/native/libnio/ch/SocketDispatcher.c @@ -280,24 +280,8 @@ Java_sun_nio_ch_SocketDispatcher_writev0(JNIEnv *env, jclass clazz, } JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketDispatcher_preClose0(JNIEnv *env, jclass clazz, - jobject fdo) +Java_sun_nio_ch_SocketDispatcher_close0(JNIEnv *env, jclass clazz, jint fd) { - jint fd = fdval(env, fdo); - struct linger l; - int len = sizeof(l); - if (getsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&l, &len) == 0) { - if (l.l_onoff == 0) { - shutdown(fd, SD_SEND); - } - } -} - -JNIEXPORT void JNICALL -Java_sun_nio_ch_SocketDispatcher_close0(JNIEnv *env, jclass clazz, - jobject fdo) -{ - jint fd = fdval(env, fdo); if (closesocket(fd) == SOCKET_ERROR) { JNU_ThrowIOExceptionWithLastError(env, "Socket close failed"); } diff --git a/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java b/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java index 7be765c924e..24fbc0ea66b 100644 --- a/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java +++ b/test/jdk/java/nio/channels/SocketChannel/AdaptorStreams.java @@ -31,6 +31,8 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; @@ -55,7 +57,7 @@ public class AdaptorStreams { withConnection((sc, peer) -> { peer.getOutputStream().write(99); int n = sc.socket().getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -66,7 +68,7 @@ public class AdaptorStreams { withConnection((sc, peer) -> { scheduleWrite(peer.getOutputStream(), 99, 1000); int n = sc.socket().getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -77,7 +79,7 @@ public class AdaptorStreams { withConnection((sc, peer) -> { peer.close(); int n = sc.socket().getInputStream().read(); - assertTrue(n == -1); + assertEquals(n, -1); }); } @@ -88,7 +90,7 @@ public class AdaptorStreams { withConnection((sc, peer) -> { scheduleClose(peer, 1000); int n = sc.socket().getInputStream().read(); - assertTrue(n == -1); + assertEquals(n, -1); }); } @@ -158,7 +160,7 @@ public class AdaptorStreams { Socket s = sc.socket(); s.setSoTimeout(1000); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -171,7 +173,7 @@ public class AdaptorStreams { Socket s = sc.socket(); s.setSoTimeout(5000); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -326,7 +328,7 @@ public class AdaptorStreams { // test read when bytes are available peer.getOutputStream().write(99); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -350,7 +352,7 @@ public class AdaptorStreams { // test read blocking until bytes are available scheduleWrite(peer.getOutputStream(), 99, 500); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -370,7 +372,7 @@ public class AdaptorStreams { // test write s.getOutputStream().write(99); int n = peer.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -396,7 +398,7 @@ public class AdaptorStreams { peer.getOutputStream().write(99); s.setSoTimeout(60*1000); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -421,7 +423,7 @@ public class AdaptorStreams { scheduleWrite(peer.getOutputStream(), 99, 500); s.setSoTimeout(60*1000); int n = s.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -442,7 +444,7 @@ public class AdaptorStreams { // test write s.getOutputStream().write(99); int n = peer.getInputStream().read(); - assertTrue(n == 99); + assertEquals(n, 99); }); } @@ -462,10 +464,14 @@ public class AdaptorStreams { static void withConnection(ThrowingBiConsumer consumer) throws Exception { - try (ServerSocket ss = new ServerSocket(0); - SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress()); - Socket peer = ss.accept()) { - consumer.accept(sc, peer); + var loopback = InetAddress.getLoopbackAddress(); + try (ServerSocket ss = new ServerSocket()) { + ss.bind(new InetSocketAddress(loopback, 0)); + try (SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress())) { + try (Socket peer = ss.accept()) { + consumer.accept(sc, peer); + } + } } } From 244bdce994de6206e3e9af8c1906f5ac1a0e5ebb Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Wed, 15 May 2019 17:13:57 -0700 Subject: [PATCH 024/263] 8224018: test/jdk/java/net/ipv6tests/{Tcp,Udp}Test.java assume IPv4 is available Reviewed-by: dfuchs, chegar --- test/jdk/java/net/ipv6tests/TcpTest.java | 4 ++++ test/jdk/java/net/ipv6tests/UdpTest.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/jdk/java/net/ipv6tests/TcpTest.java b/test/jdk/java/net/ipv6tests/TcpTest.java index 81d618d9c72..d84ee9dc667 100644 --- a/test/jdk/java/net/ipv6tests/TcpTest.java +++ b/test/jdk/java/net/ipv6tests/TcpTest.java @@ -60,6 +60,10 @@ public class TcpTest extends Tests { public static void main (String[] args) throws Exception { checkDebug(args); + if (ia4addr == null) { + System.out.println ("No IPV4 addresses: exiting test"); + return; + } if (ia6addr == null) { System.out.println ("No IPV6 addresses: exiting test"); return; diff --git a/test/jdk/java/net/ipv6tests/UdpTest.java b/test/jdk/java/net/ipv6tests/UdpTest.java index 3b0e23176ee..9b55373c5db 100644 --- a/test/jdk/java/net/ipv6tests/UdpTest.java +++ b/test/jdk/java/net/ipv6tests/UdpTest.java @@ -70,6 +70,10 @@ public class UdpTest extends Tests { public static void main (String[] args) throws Exception { checkDebug(args); + if (ia4addr == null) { + System.out.println ("No local IPv4 addresses: exiting now"); + return; + } if (ia6addr == null) { System.out.println ("No local IPv6 addresses: exiting now"); return; From 772ad03cb519fba2a9f254b50e0ed747ee8f1790 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 16 May 2019 15:45:46 +0100 Subject: [PATCH 025/263] 8224042: Add private alignDown method to MappedByteBuffer Use alignDown method to round addresses down to page boundary Reviewed-by: stuefe, mikael, alanb --- .../share/classes/java/nio/MappedByteBuffer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java index 55223650b57..2c5a17b2878 100644 --- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java +++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java @@ -106,7 +106,7 @@ public abstract class MappedByteBuffer private long mappingOffset(int index) { int ps = Bits.pageSize(); long indexAddress = address + index; - long baseAddress = (indexAddress & ~(ps-1)); + long baseAddress = alignDown(indexAddress, ps); return indexAddress - baseAddress; } @@ -140,6 +140,12 @@ public abstract class MappedByteBuffer return length + mappingOffset; } + // align address down to page size + private static long alignDown(long address, int pageSize) { + // pageSize must be a power of 2 + return address & ~(pageSize - 1); + } + /** * Tells whether or not this buffer's content is resident in physical * memory. From 11b6437c01e4a1af2ea40e0f32551469f3c2427d Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Thu, 16 May 2019 19:07:31 +0200 Subject: [PATCH 026/263] 8224043: Shenandoah: Remove clear_claimed_marks() from start of concurrent_traversal() Reviewed-by: shade --- src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp index 900cbb80168..ec1cf39ef97 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp @@ -556,11 +556,6 @@ bool ShenandoahTraversalGC::check_and_handle_cancelled_gc(ShenandoahTaskTerminat } void ShenandoahTraversalGC::concurrent_traversal_collection() { - { - MutexLocker ml(ClassLoaderDataGraph_lock); - ClassLoaderDataGraph::clear_claimed_marks(); - } - ShenandoahGCPhase phase_work(ShenandoahPhaseTimings::conc_traversal); if (!_heap->cancelled_gc()) { uint nworkers = _heap->workers()->active_workers(); From fa2ea6a6d8625629cba6240b6a3bf64297bc51dd Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Thu, 16 May 2019 13:34:33 -0400 Subject: [PATCH 027/263] 8223726: j.l.c.MethodTypeDesc spec should contain precise assertions for one parameter's methods Reviewed-by: darcy --- .../java/lang/constant/MethodHandleDesc.java | 5 ++-- .../java/lang/constant/MethodTypeDesc.java | 6 ++--- .../lang/constant/MethodHandleDescTest.java | 27 ++++++++++++++++++- .../lang/constant/MethodTypeDescTest.java | 18 ++++++++++++- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java index f2d0eda96d3..e4b224fc817 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -177,7 +177,7 @@ public interface MethodHandleDesc * @param paramTypes {@link ClassDesc}s describing the parameter types of * the constructor * @return the {@linkplain MethodHandleDesc} - * @throws NullPointerException if any of the arguments are null + * @throws NullPointerException if any argument or its contents is {@code null} */ static DirectMethodHandleDesc ofConstructor(ClassDesc owner, ClassDesc... paramTypes) { @@ -191,6 +191,7 @@ public interface MethodHandleDesc * * @param type a {@link MethodHandleDesc} describing the new method type * @return a {@linkplain MethodHandleDesc} for the adapted method handle + * @throws NullPointerException if the argument is {@code null} */ default MethodHandleDesc asType(MethodTypeDesc type) { return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type); diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java index 128ae33e27f..d66bbde86d9 100644 --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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,7 +49,7 @@ public interface MethodTypeDesc * * @param descriptor a method descriptor string * @return a {@linkplain MethodTypeDesc} describing the desired method type - * @throws NullPointerException if any argument is {@code null} + * @throws NullPointerException if the argument is {@code null} * @throws IllegalArgumentException if the descriptor string is not a valid * method descriptor * @jvms 4.3.3 Method Descriptors @@ -116,7 +116,7 @@ public interface MethodTypeDesc * * @param returnType a {@link ClassDesc} describing the new return type * @return a {@linkplain MethodTypeDesc} describing the desired method type - * @throws NullPointerException if any argument is {@code null} + * @throws NullPointerException if the argument is {@code null} */ MethodTypeDesc changeReturnType(ClassDesc returnType); diff --git a/test/jdk/java/lang/constant/MethodHandleDescTest.java b/test/jdk/java/lang/constant/MethodHandleDescTest.java index c6a4be5297e..549d0660a93 100644 --- a/test/jdk/java/lang/constant/MethodHandleDescTest.java +++ b/test/jdk/java/lang/constant/MethodHandleDescTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -152,6 +152,24 @@ public class MethodHandleDescTest extends SymbolicDescTest { } catch (IllegalArgumentException ex) { // good } + + // null list of parameters + try { + MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList", null)); + fail("should have failed: null list of parameters"); + } catch (NullPointerException ex) { + // good + } + + // null elements in list of parameters + try { + ClassDesc[] paramList = new ClassDesc[1]; + paramList[0] = null; + MethodHandleDesc.ofConstructor(ClassDesc.of("java.util.ArrayList"), paramList); + fail("should have failed: null content in list of parameters"); + } catch (NullPointerException ex) { + // good + } } public void testAsType() throws Throwable { @@ -184,6 +202,13 @@ public class MethodHandleDescTest extends SymbolicDescTest { MethodHandleDesc same = mhr.asType(mhr.invocationType()); assertSame(mhr, same); + try { + mhr.asType(null); + fail("Expected NPE"); + } catch (NullPointerException ex) { + // good + } + // @@@ Test varargs adaptation // @@@ Test bad adaptations and assert runtime error on resolution // @@@ Test intrinsification of adapted MH diff --git a/test/jdk/java/lang/constant/MethodTypeDescTest.java b/test/jdk/java/lang/constant/MethodTypeDescTest.java index d5205f33cb1..888249e3772 100644 --- a/test/jdk/java/lang/constant/MethodTypeDescTest.java +++ b/test/jdk/java/lang/constant/MethodTypeDescTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, 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 @@ -103,6 +103,14 @@ public class MethodTypeDescTest extends SymbolicDescTest { testMethodTypeDesc(newDesc, mt.changeReturnType((Class)rc.resolveConstantDesc(LOOKUP))); } + // try with null parameter + try { + MethodTypeDesc newDesc = mtDesc.changeReturnType(null); + fail("should fail with NPE"); + } catch (NullPointerException ex) { + // good + } + // changeParamType for (int i=0; i Date: Thu, 16 May 2019 11:37:26 -0700 Subject: [PATCH 028/263] 8222422: vmTestbase/nsk/jdi/ClassLoaderReference/definedClasses tests failed with Unexpected Exception: null Reviewed-by: dholmes, jcbeyler, cjplummer --- .../tools/jdi/ClassLoaderReferenceImpl.java | 8 +++--- .../com/sun/tools/jdi/ClassTypeImpl.java | 9 +++---- .../com/sun/tools/jdi/InterfaceTypeImpl.java | 10 ++++---- .../com/sun/tools/jdi/ReferenceTypeImpl.java | 11 +++----- .../com/sun/tools/jdi/VirtualMachineImpl.java | 25 ++++++++++++++++++- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java index 2e21e14f72b..1dd112bdbad 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassLoaderReferenceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -59,12 +59,12 @@ public class ClassLoaderReferenceImpl extends ObjectReferenceImpl public List definedClasses() { ArrayList definedClasses = new ArrayList<>(); - for (ReferenceType type : vm.allClasses()) { + vm.forEachClass(type -> { if (type.isPrepared() && - equals(type.classLoader())) { + equals(type.classLoader())) { definedClasses.add(type); } - } + }); return definedClasses; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassTypeImpl.java index f458327a3c3..59936b1abc4 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ClassTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -110,16 +110,15 @@ final public class ClassTypeImpl extends InvokableTypeImpl public List subclasses() { List subs = new ArrayList<>(); - for (ReferenceType refType : vm.allClasses()) { + vm.forEachClass(refType -> { if (refType instanceof ClassType) { ClassType clazz = (ClassType)refType; ClassType superclass = clazz.superclass(); if ((superclass != null) && superclass.equals(this)) { - subs.add((ClassType)refType); + subs.add(clazz); } } - } - + }); return subs; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java index fefeac6e0bd..b543de0e9e5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -77,27 +77,27 @@ final public class InterfaceTypeImpl extends InvokableTypeImpl public List subinterfaces() { List subs = new ArrayList(); - for (ReferenceType refType : vm.allClasses()) { + vm.forEachClass(refType -> { if (refType instanceof InterfaceType) { InterfaceType interfaze = (InterfaceType)refType; if (interfaze.isPrepared() && interfaze.superinterfaces().contains(this)) { subs.add(interfaze); } } - } + }); return subs; } public List implementors() { List implementors = new ArrayList(); - for (ReferenceType refType : vm.allClasses()) { + vm.forEachClass(refType -> { if (refType instanceof ClassType) { ClassType clazz = (ClassType)refType; if (clazz.isPrepared() && clazz.interfaces().contains(this)) { implementors.add(clazz); } } - } + }); return implementors; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java index 80f0f81bdc9..ff443ae14c0 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, 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 @@ -607,23 +607,20 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp } public List nestedTypes() { - List all = vm.allClasses(); List nested = new ArrayList(); String outername = name(); int outerlen = outername.length(); - Iterator iter = all.iterator(); - while (iter.hasNext()) { - ReferenceType refType = iter.next(); + vm.forEachClass(refType -> { String name = refType.name(); int len = name.length(); /* The separator is historically '$' but could also be '#' */ if ( len > outerlen && name.startsWith(outername) ) { char c = name.charAt(outerlen); - if ( c =='$' || c== '#' ) { + if ( c == '$' || c == '#' ) { nested.add(refType); } } - } + }); return nested; } diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java index 50ba9d33e88..254b5847d43 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import com.sun.jdi.BooleanType; import com.sun.jdi.BooleanValue; @@ -57,6 +58,7 @@ import com.sun.jdi.InternalException; import com.sun.jdi.LongType; import com.sun.jdi.LongValue; import com.sun.jdi.ModuleReference; +import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.PathSearchingVirtualMachine; import com.sun.jdi.PrimitiveType; import com.sun.jdi.ReferenceType; @@ -338,6 +340,27 @@ class VirtualMachineImpl extends MirrorImpl return Collections.unmodifiableList(a); } + /** + * Performs an action for each loaded type. + */ + public void forEachClass(Consumer action) { + for (ReferenceType type : allClasses()) { + try { + action.accept(type); + } catch (ObjectCollectedException ex) { + // Some classes might be unloaded and garbage collected since + // we retrieved the copy of all loaded classes and started + // iterating over them. In this case calling methods on such types + // might result in com.sun.jdi.ObjectCollectedException + // being thrown. We ignore such classes and keep iterating. + if ((vm.traceFlags & VirtualMachine.TRACE_OBJREFS) != 0) { + vm.printTrace("ObjectCollectedException was thrown while " + + "accessing unloaded class " + type.name()); + } + } + } + } + public void redefineClasses(Map classToBytes) { From 954169d7d196cfe009eaa7e8adaa094159ff65ef Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Thu, 16 May 2019 11:30:32 -0700 Subject: [PATCH 029/263] 8223910: TestFloatJNIArgs and TestTrichotomyExpressions time out with Graal as JIT Reviewed-by: thartmann --- test/hotspot/jtreg/ProblemList-graal.txt | 1 + .../jtreg/compiler/floatingpoint/TestFloatJNIArgs.java | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-graal.txt b/test/hotspot/jtreg/ProblemList-graal.txt index a07047a2782..959aedc7947 100644 --- a/test/hotspot/jtreg/ProblemList-graal.txt +++ b/test/hotspot/jtreg/ProblemList-graal.txt @@ -226,6 +226,7 @@ compiler/c2/Test8062950.java 8207267 generic-all compiler/intrinsics/mathexact/LongMulOverflowTest.java 8207267 generic-all compiler/loopopts/TestOverunrolling.java 8207267 generic-all compiler/jsr292/NonInlinedCall/InvokeTest.java 8207267 generic-all +compiler/codegen/TestTrichotomyExpressions.java 8207267 generic-all runtime/exceptionMsgs/AbstractMethodError/AbstractMethodErrorTest.java 8222582 generic-all diff --git a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatJNIArgs.java b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatJNIArgs.java index e84d3855c8a..77d166f6857 100644 --- a/test/hotspot/jtreg/compiler/floatingpoint/TestFloatJNIArgs.java +++ b/test/hotspot/jtreg/compiler/floatingpoint/TestFloatJNIArgs.java @@ -28,6 +28,13 @@ * * @run main/othervm/native -Xint compiler.floatingpoint.TestFloatJNIArgs * @run main/othervm/native -XX:+TieredCompilation -Xcomp compiler.floatingpoint.TestFloatJNIArgs + */ + +/* @test + * @bug 8139258 8165673 + * @summary Regression test for passing float args to a jni function. + * + * @requires !vm.graal.enabled * @run main/othervm/native -XX:-TieredCompilation -Xcomp compiler.floatingpoint.TestFloatJNIArgs */ From 05736da72dd04626076853132a72319c09bac122 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Thu, 16 May 2019 12:36:08 -0700 Subject: [PATCH 030/263] 8223499: Remove two DocuSign root certificates that are expiring Reviewed-by: mullan --- src/java.base/share/lib/security/cacerts | Bin 100258 -> 98310 bytes .../security/lib/cacerts/VerifyCACerts.java | 11 ++--------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/lib/security/cacerts b/src/java.base/share/lib/security/cacerts index a83bf49ee1b24fd79517c1e134c7d8c56e0ab0d1..1db6c41b89d4d6186ac8ecde19b25f9465f17b36 100644 GIT binary patch delta 60 zcmZ3~&(_w!#`Ev(zqbqw3`{^AF+EV2QFx>L_5+)j9no*vzR-*Dt&K?Xya^9AH^%>e Q+LpoDB;L|=KKb$t0O0}}MgRZ+ delta 1884 zcmajeX*iU76aet|oh>F}W@Id5DT=7^GS;GOg+xPiL-8yabXFfme)ZTNGFk=`m9y`xTVLrGn#aq}mtMt+}cu{#S;fX|0_?0pC zC%4+YpXp<`EQbo(@Y&FW&)5Kp4C;8aWd3n6W1y1TeyY`a1M1eqborh8Ron?}A=Ayt zzxlS^_1{%VuZ#EQa7}2Nl%ki}or*c)9ci9B@3DRMPL5bS>?xo$P$JXW`|S%yl=%dN z1GvufJIxSoT~>sx`CWlmFV_}1TIn6*<{S)-Jt_U{5DX3i;I)W&DB|4L^+@3md=Lr* zmti0}jo}80IWY$YBK&GSv9suR;85dd{bqMYEQCSvJ2Fi{=0`&iL?GZW0EDzx7AYlz zP=!>W9ofp++n5UO0RhyVDk?!iLBwyjMs)G@Q8BVUpt5#!WTK0|H!FfALf=w2uvz~> zE<=}-L&=Dj2{F{rcEe-(t8XuE#H5RpMv#V4hYQRninDsOx<#$^F#+ziyvL=&Q5-2_ zAXtGgXNSUzscBR|X)cfQbtD_7_u-uzh@hv_g?Q3v_`$>#Z3^I4Ml*Y=JDY z{y~UFCBYv3ns}x$rlf^_1f0}+gTkrT74-hWU?8WFr>nD+8?(s1UJd%>s4o<$k)+GQ z?YWQcDN6K}e?(IYoBPOma7Is8OoJ(E2u^z?+N{|*oH-uUU7A|%dL2QLD_UTc9zSPw z!lAq6yq>|)zE9V9N?|6#GV^M>;Z$D#uN_3e5{bQcxY#L0JP#%fD{HM&kEBa|o7C3< zseKn^cj`YVQ&&)4SV0-`4P|t-`TMT!L67;1FB~4`8O!|}rQVNFQt7KGB_Z)Ol-M~bEQX4JlJ-fz#fJpf1E-}=QQ;l51qLShfGP1uWy1Zg*$zf_)wB4WR<(s7WsqrYi`qCnrPvfL-ZcN40{p#Q1_QIOV} zN(drC+q0Fj6`5Oqs#5K5l-Ccp#2AY=_5V%>`fW+h$CPcdSoRYdN<Yal}I>s zU2f{~7gG{?pf@ifDbwQB+0oI`XU7^nQ$FU+$JbNN@YRH(I?YBzL6_P3lp&p tQC>-Bg>XkzT5V1O?9Sl|Bk-NB$Xp@|I>5&A;C||Fr$SRKciFsL{u5Av^)&zh diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index b373ae8a851..1cafc024465 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -26,6 +26,7 @@ * @test * @bug 8189131 8198240 8191844 8189949 8191031 8196141 8204923 8195774 8199779 * 8209452 8209506 8210432 8195793 8216577 8222089 8222133 8222137 8222136 + * 8223499 * @summary Check root CA entries in cacerts file */ import java.io.File; @@ -49,7 +50,7 @@ public class VerifyCACerts { + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 90; + private static final int COUNT = 88; // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") @@ -143,10 +144,6 @@ public class VerifyCACerts { "69:DD:D7:EA:90:BB:57:C9:3E:13:5D:C8:5E:A6:FC:D5:48:0B:60:32:39:BD:C4:54:FC:75:8B:2A:26:CF:7F:79"); put("verisignclass3g5ca [jdk]", "9A:CF:AB:7E:43:C8:D8:80:D0:6B:26:2A:94:DE:EE:E4:B4:65:99:89:C3:D0:CA:F1:9B:AF:64:05:E4:1A:B7:DF"); - put("certplusclass2primaryca [jdk]", - "0F:99:3C:8A:EF:97:BA:AF:56:87:14:0E:D5:9A:D1:82:1B:B4:AF:AC:F0:AA:9A:58:B5:D5:7A:33:8A:3A:FB:CB"); - put("certplusclass3pprimaryca [jdk]", - "CC:C8:94:89:37:1B:AD:11:1C:90:61:9B:EA:24:0A:2E:6D:AD:D9:9F:9F:6E:1D:4D:41:E5:8E:D6:DE:3D:02:85"); put("keynectisrootca [jdk]", "42:10:F1:99:49:9A:9A:C3:3C:8D:E0:2B:A6:DB:AA:14:40:8B:DD:8A:6E:32:46:89:C1:92:2D:06:97:15:A3:32"); put("dtrustclass3ca2 [jdk]", @@ -243,10 +240,6 @@ public class VerifyCACerts { @SuppressWarnings("serial") private static final HashSet EXPIRY_EXC_ENTRIES = new HashSet<>() { { - // Valid until: Sat Jul 06 19:59:59 EDT 2019 - add("certplusclass2primaryca [jdk]"); - // Valid until: Sat Jul 06 19:59:59 EDT 2019 - add("certplusclass3pprimaryca [jdk]"); // Valid until: Tue Jul 09 14:40:36 EDT 2019 add("utnuserfirstobjectca [jdk]"); } From bddd94f0a6570551ecd3499a544cf61c6faf6cac Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 16 May 2019 21:32:24 +0200 Subject: [PATCH 031/263] 8224033: os::snprintf should be used in virtualizationSupport.cpp Reviewed-by: mbaesken, stuefe --- src/hotspot/share/utilities/virtualizationSupport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/virtualizationSupport.cpp b/src/hotspot/share/utilities/virtualizationSupport.cpp index ef5013e4cef..cbd93dd9e9a 100644 --- a/src/hotspot/share/utilities/virtualizationSupport.cpp +++ b/src/hotspot/share/utilities/virtualizationSupport.cpp @@ -65,13 +65,13 @@ void VirtualizationSupport::initialize() { VMGuestLibError sg_error = GuestLib_StatGet("text", "resources", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_resource_information = true; - snprintf(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); + os::snprintf(extended_resource_info_at_startup, sizeof(extended_resource_info_at_startup), "%s", result_info); GuestLib_StatFree(result_info, result_size); } sg_error = GuestLib_StatGet("text", "host", &result_info, &result_size); if (sg_error == VMGUESTLIB_ERROR_SUCCESS) { has_host_information = true; - snprintf(host_information, sizeof(host_information), "%s", result_info); + os::snprintf(host_information, sizeof(host_information), "%s", result_info); GuestLib_StatFree(result_info, result_size); } } From c8319ed0cc5d5663c9dc8d28563bb60efff08c1e Mon Sep 17 00:00:00 2001 From: Jean Christophe Beyler Date: Thu, 16 May 2019 12:48:21 -0700 Subject: [PATCH 032/263] 8224020: AsyncGetCallTrace test should not run on PPC64 or IA64 Restrict the test to the right architectures Reviewed-by: cjplummer, sspitsyn, simonis --- .../AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java | 3 ++- .../AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java index f700fdf694a..06e0882e9a9 100644 --- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java +++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java @@ -28,7 +28,8 @@ package MyPackage; * @test * @summary Verifies that AsyncGetCallTrace is call-able and provides sane information. * @compile ASGCTBaseTest.java - * @requires (os.family == "linux") + * @requires os.family == "linux" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="arm" | os.arch=="sparc" | os.arch=="aarch64" * @run main/othervm/native -agentlib:AsyncGetCallTraceTest MyPackage.ASGCTBaseTest */ diff --git a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp index 62e0d7d3397..ec52277cbbe 100644 --- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp +++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp @@ -185,7 +185,7 @@ typedef void (*ASGCTType)(ASGCT_CallTrace *, jint, void *); JNIEXPORT jboolean JNICALL Java_MyPackage_ASGCTBaseTest_checkAsyncGetCallTraceCall(JNIEnv* env, jclass cls) { - ASGCTType agct = reinterpret_cast(dlsym(NULL, "AsyncGetCallTrace")); + ASGCTType agct = reinterpret_cast(dlsym(RTLD_DEFAULT, "AsyncGetCallTrace")); const int MAX_DEPTH = 16; ASGCT_CallTrace trace; From ca569937dafb92dd0b992229be1be2be18f0f8eb Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Thu, 16 May 2019 12:33:44 -0700 Subject: [PATCH 033/263] 8224017: [Graal] gc/z/TestUncommit.java fails with Graal Reviewed-by: kvn --- test/hotspot/jtreg/ProblemList-graal.txt | 16 ++++++---------- test/hotspot/jtreg/gc/z/TestUncommit.java | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList-graal.txt b/test/hotspot/jtreg/ProblemList-graal.txt index 959aedc7947..f2673500376 100644 --- a/test/hotspot/jtreg/ProblemList-graal.txt +++ b/test/hotspot/jtreg/ProblemList-graal.txt @@ -54,7 +54,9 @@ gc/arguments/TestVerifyBeforeAndAfterGCFlags.java 8196611 generi gc/g1/mixedgc/TestOldGenCollectionUsage.java 8196611 generic-all gc/g1/TestConcurrentSystemGC.java 8196611 generic-all gc/g1/TestPeriodicCollection.java 8196611 generic-all +gc/g1/TestFromCardCacheIndex.java 8196611 generic-all gc/parallel/TestPrintGCDetailsVerbose.java 8196611 generic-all +vm/gc/InfiniteList.java 8196611 generic-all vmTestbase/gc/lock/malloc/malloclock03/TestDescription.java 8196611 macosx-all vmTestbase/gc/gctests/LargeObjects/large001/large001.java 8196611 generic-all vmTestbase/gc/gctests/ReferencesGC/ReferencesGC.java 8196611 generic-all @@ -62,9 +64,12 @@ vmTestbase/nsk/stress/except/except004.java 8196611 generi vmTestbase/nsk/stress/except/except007.java 8196611 generic-all vmTestbase/nsk/stress/except/except008.java 8196611 generic-all vmTestbase/nsk/stress/except/except011.java 8196611 generic-all -serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorMultiArrayTest.java 8196611 generic-all vmTestbase/nsk/jdi/VirtualMachine/instanceCounts/instancecounts003/instancecounts003.java 8196611 generic-all vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects002/referringObjects002.java 8196611 generic-all +serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorMultiArrayTest.java 8196611 generic-all +serviceability/tmtools/jstat/GcTest02.java 8196611 generic-all +serviceability/tmtools/jstat/GcCapacityTest.java 8196611 generic-all + gc/g1/ihop/TestIHOPErgo.java 8191048 generic-all gc/g1/plab/TestPLABEvacuationFailure.java 8191048 generic-all @@ -204,15 +209,6 @@ compiler/stable/TestStableShort.java 8204347 gener compiler/stable/TestStableUByte.java 8204347 generic-all compiler/stable/TestStableUShort.java 8204347 generic-all -gc/g1/mixedgc/TestOldGenCollectionUsage.java 8196611 generic-all -gc/g1/TestPeriodicCollection.java 8196611 generic-all -gc/parallel/TestPrintGCDetailsVerbose.java 8196611 generic-all -vm/gc/InfiniteList.java 8196611 generic-all -vmTestbase/nsk/stress/except/except007.java 8196611 generic-all -vmTestbase/nsk/stress/except/except008.java 8196611 generic-all -serviceability/tmtools/jstat/GcTest02.java 8196611 generic-all -serviceability/tmtools/jstat/GcCapacityTest.java 8196611 generic-all -serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorMultiArrayTest.java 8196611 generic-all vmTestbase/nsk/jdb/unmonitor/unmonitor001/unmonitor001.java 8218701 generic-all diff --git a/test/hotspot/jtreg/gc/z/TestUncommit.java b/test/hotspot/jtreg/gc/z/TestUncommit.java index 335606d08a5..5929063f191 100644 --- a/test/hotspot/jtreg/gc/z/TestUncommit.java +++ b/test/hotspot/jtreg/gc/z/TestUncommit.java @@ -25,7 +25,7 @@ package gc.z; /* * @test TestUncommit - * @requires vm.gc.Z + * @requires vm.gc.Z & !vm.graal.enabled * @summary Test ZGC uncommit unused memory * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms128M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit true 3 * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms512M -Xmx512M -XX:ZUncommitDelay=10 gc.z.TestUncommit false 1 From 1e4085b359a183529c0e3bf2044bc376b6280f7a Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Thu, 16 May 2019 12:16:47 -0700 Subject: [PATCH 034/263] 8222154: upgrade gtest to 1.8.1 Reviewed-by: jwilhelm, rwestberg --- make/hotspot/lib/CompileGtest.gmk | 2 - test/fmw/gtest/CONTRIBUTORS | 37 + test/fmw/gtest/README | 435 ---- test/fmw/gtest/README.md | 345 ++++ .../gtest/include/gtest/gtest-death-test.h | 66 +- test/fmw/gtest/include/gtest/gtest-message.h | 13 +- .../gtest/include/gtest/gtest-param-test.h | 67 +- .../include/gtest/gtest-param-test.h.pump | 67 +- test/fmw/gtest/include/gtest/gtest-printers.h | 468 ++++- test/fmw/gtest/include/gtest/gtest-spi.h | 15 +- .../fmw/gtest/include/gtest/gtest-test-part.h | 10 +- .../gtest/include/gtest/gtest-typed-test.h | 111 +- test/fmw/gtest/include/gtest/gtest.h | 571 +++--- .../fmw/gtest/include/gtest/gtest_pred_impl.h | 15 +- test/fmw/gtest/include/gtest/gtest_prod.h | 17 +- .../include/gtest/internal/custom/README.md | 56 + .../gtest/internal/custom/gtest-port.h | 37 + .../gtest/internal/custom/gtest-printers.h | 42 + .../include/gtest/internal/custom/gtest.h | 37 + .../internal/gtest-death-test-internal.h | 77 +- .../include/gtest/internal/gtest-filepath.h | 11 +- .../include/gtest/internal/gtest-internal.h | 398 ++-- .../include/gtest/internal/gtest-linked_ptr.h | 20 +- .../internal/gtest-param-util-generated.h | 575 +++++- .../gtest-param-util-generated.h.pump | 49 +- .../include/gtest/internal/gtest-param-util.h | 177 +- .../include/gtest/internal/gtest-port-arch.h | 100 + .../gtest/include/gtest/internal/gtest-port.h | 1301 +++++++++--- .../include/gtest/internal/gtest-string.h | 8 +- .../include/gtest/internal/gtest-tuple.h | 15 +- .../include/gtest/internal/gtest-tuple.h.pump | 15 +- .../include/gtest/internal/gtest-type-util.h | 23 +- .../gtest/internal/gtest-type-util.h.pump | 23 +- test/fmw/gtest/src/gtest-all.cc | 5 +- test/fmw/gtest/src/gtest-death-test.cc | 343 +++- test/fmw/gtest/src/gtest-filepath.cc | 29 +- test/fmw/gtest/src/gtest-internal-inl.h | 109 +- test/fmw/gtest/src/gtest-port.cc | 665 ++++++- test/fmw/gtest/src/gtest-printers.cc | 118 +- test/fmw/gtest/src/gtest-test-part.cc | 13 +- test/fmw/gtest/src/gtest-typed-test.cc | 44 +- test/fmw/gtest/src/gtest.cc | 1767 +++++++++++++---- test/fmw/gtest/src/gtest_main.cc | 3 +- 43 files changed, 6113 insertions(+), 2186 deletions(-) create mode 100644 test/fmw/gtest/CONTRIBUTORS delete mode 100644 test/fmw/gtest/README create mode 100644 test/fmw/gtest/README.md create mode 100644 test/fmw/gtest/include/gtest/internal/custom/README.md create mode 100644 test/fmw/gtest/include/gtest/internal/custom/gtest-port.h create mode 100644 test/fmw/gtest/include/gtest/internal/custom/gtest-printers.h create mode 100644 test/fmw/gtest/include/gtest/internal/custom/gtest.h create mode 100644 test/fmw/gtest/include/gtest/internal/gtest-port-arch.h diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index b4e61fad659..9814aba0395 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -80,8 +80,6 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \ self-assign-overloaded, \ DISABLED_WARNINGS_solstudio := $(DISABLED_WARNINGS_solstudio) \ identexpected, \ - DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) \ - 4996, \ LDFLAGS := $(JVM_LDFLAGS), \ LDFLAGS_solaris := -library=stlport4 $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JVM_LIBS), \ diff --git a/test/fmw/gtest/CONTRIBUTORS b/test/fmw/gtest/CONTRIBUTORS new file mode 100644 index 00000000000..feae2fc0441 --- /dev/null +++ b/test/fmw/gtest/CONTRIBUTORS @@ -0,0 +1,37 @@ +# This file contains a list of people who've made non-trivial +# contribution to the Google C++ Testing Framework project. People +# who commit code to the project are encouraged to add their names +# here. Please keep the list sorted by first names. + +Ajay Joshi +Balázs Dán +Bharat Mediratta +Chandler Carruth +Chris Prince +Chris Taylor +Dan Egnor +Eric Roman +Hady Zalek +Jeffrey Yasskin +Jói Sigurðsson +Keir Mierle +Keith Ray +Kenton Varda +Manuel Klimek +Markus Heule +Mika Raento +Miklós Fazekas +Pasi Valminen +Patrick Hanna +Patrick Riley +Peter Kaminski +Preston Jackson +Rainer Klaffenboeck +Russ Cox +Russ Rufer +Sean Mcafee +Sigurður Ásgeirsson +Tracy Bialik +Vadim Berman +Vlad Losev +Zhanyong Wan diff --git a/test/fmw/gtest/README b/test/fmw/gtest/README deleted file mode 100644 index 26f35a84794..00000000000 --- a/test/fmw/gtest/README +++ /dev/null @@ -1,435 +0,0 @@ -Google C++ Testing Framework -============================ - -http://code.google.com/p/googletest/ - -Overview --------- - -Google's framework for writing C++ tests on a variety of platforms -(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the -xUnit architecture. Supports automatic test discovery, a rich set of -assertions, user-defined assertions, death tests, fatal and non-fatal -failures, various options for running the tests, and XML test report -generation. - -Please see the project page above for more information as well as the -mailing list for questions, discussions, and development. There is -also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please -join us! - -Requirements for End Users --------------------------- - -Google Test is designed to have fairly minimal requirements to build -and use with your projects, but there are some. Currently, we support -Linux, Windows, Mac OS X, and Cygwin. We will also make our best -effort to support other platforms (e.g. Solaris, AIX, and z/OS). -However, since core members of the Google Test project have no access -to these platforms, Google Test may have outstanding issues there. If -you notice any problems on your platform, please notify -googletestframework@googlegroups.com. Patches for fixing them are -even more welcome! - -### Linux Requirements ### - -These are the base requirements to build and use Google Test from a source -package (as described below): - * GNU-compatible Make or gmake - * POSIX-standard shell - * POSIX(-2) Regular Expressions (regex.h) - * A C++98-standard-compliant compiler - -### Windows Requirements ### - - * Microsoft Visual C++ 7.1 or newer - -### Cygwin Requirements ### - - * Cygwin 1.5.25-14 or newer - -### Mac OS X Requirements ### - - * Mac OS X 10.4 Tiger or newer - * Developer Tools Installed - -Also, you'll need CMake 2.6.4 or higher if you want to build the -samples using the provided CMake script, regardless of the platform. - -Requirements for Contributors ------------------------------ - -We welcome patches. If you plan to contribute a patch, you need to -build Google Test and its own tests from an SVN checkout (described -below), which has further requirements: - - * Python version 2.3 or newer (for running some of the tests and - re-generating certain source files from templates) - * CMake 2.6.4 or newer - -Getting the Source ------------------- - -There are two primary ways of getting Google Test's source code: you -can download a stable source release in your preferred archive format, -or directly check out the source from our Subversion (SVN) repositary. -The SVN checkout requires a few extra steps and some extra software -packages on your system, but lets you track the latest development and -make patches much more easily, so we highly encourage it. - -### Source Package ### - -Google Test is released in versioned source packages which can be -downloaded from the download page [1]. Several different archive -formats are provided, but the only difference is the tools used to -manipulate them, and the size of the resulting file. Download -whichever you are most comfortable with. - - [1] http://code.google.com/p/googletest/downloads/list - -Once the package is downloaded, expand it using whichever tools you -prefer for that type. This will result in a new directory with the -name "gtest-X.Y.Z" which contains all of the source code. Here are -some examples on Linux: - - tar -xvzf gtest-X.Y.Z.tar.gz - tar -xvjf gtest-X.Y.Z.tar.bz2 - unzip gtest-X.Y.Z.zip - -### SVN Checkout ### - -To check out the main branch (also known as the "trunk") of Google -Test, run the following Subversion command: - - svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn - -Setting up the Build --------------------- - -To build Google Test and your tests that use it, you need to tell your -build system where to find its headers and source files. The exact -way to do it depends on which build system you use, and is usually -straightforward. - -### Generic Build Instructions ### - -Suppose you put Google Test in directory ${GTEST_DIR}. To build it, -create a library build target (or a project as called by Visual Studio -and Xcode) to compile - - ${GTEST_DIR}/src/gtest-all.cc - -with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR} -in the normal header search path. Assuming a Linux-like system and gcc, -something like the following will do: - - g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ - -pthread -c ${GTEST_DIR}/src/gtest-all.cc - ar -rv libgtest.a gtest-all.o - -(We need -pthread as Google Test uses threads.) - -Next, you should compile your test source file with -${GTEST_DIR}/include in the system header search path, and link it -with gtest and any other necessary libraries: - - g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \ - -o your_test - -As an example, the make/ directory contains a Makefile that you can -use to build Google Test on systems where GNU make is available -(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google -Test's own tests. Instead, it just builds the Google Test library and -a sample test. You can use it as a starting point for your own build -script. - -If the default settings are correct for your environment, the -following commands should succeed: - - cd ${GTEST_DIR}/make - make - ./sample1_unittest - -If you see errors, try to tweak the contents of make/Makefile to make -them go away. There are instructions in make/Makefile on how to do -it. - -### Using CMake ### - -Google Test comes with a CMake build script (CMakeLists.txt) that can -be used on a wide range of platforms ("C" stands for cross-platofrm.). -If you don't have CMake installed already, you can download it for -free from http://www.cmake.org/. - -CMake works by generating native makefiles or build projects that can -be used in the compiler environment of your choice. The typical -workflow starts with: - - mkdir mybuild # Create a directory to hold the build output. - cd mybuild - cmake ${GTEST_DIR} # Generate native build scripts. - -If you want to build Google Test's samples, you should replace the -last command with - - cmake -Dgtest_build_samples=ON ${GTEST_DIR} - -If you are on a *nix system, you should now see a Makefile in the -current directory. Just type 'make' to build gtest. - -If you use Windows and have Vistual Studio installed, a gtest.sln file -and several .vcproj files will be created. You can then build them -using Visual Studio. - -On Mac OS X with Xcode installed, a .xcodeproj file will be generated. - -### Legacy Build Scripts ### - -Before settling on CMake, we have been providing hand-maintained build -projects/scripts for Visual Studio, Xcode, and Autotools. While we -continue to provide them for convenience, they are not actively -maintained any more. We highly recommend that you follow the -instructions in the previous two sections to integrate Google Test -with your existing build system. - -If you still need to use the legacy build scripts, here's how: - -The msvc\ folder contains two solutions with Visual C++ projects. -Open the gtest.sln or gtest-md.sln file using Visual Studio, and you -are ready to build Google Test the same way you build any Visual -Studio project. Files that have names ending with -md use DLL -versions of Microsoft runtime libraries (the /MD or the /MDd compiler -option). Files without that suffix use static versions of the runtime -libraries (the /MT or the /MTd option). Please note that one must use -the same option to compile both gtest and the test code. If you use -Visual Studio 2005 or above, we recommend the -md version as /MD is -the default for new projects in these versions of Visual Studio. - -On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using -Xcode. Build the "gtest" target. The universal binary framework will -end up in your selected build directory (selected in the Xcode -"Preferences..." -> "Building" pane and defaults to xcode/build). -Alternatively, at the command line, enter: - - xcodebuild - -This will build the "Release" configuration of gtest.framework in your -default build location. See the "xcodebuild" man page for more -information about building different configurations and building in -different locations. - -If you wish to use the Google Test Xcode project with Xcode 4.x and -above, you need to either: - * update the SDK configuration options in xcode/Config/General.xconfig. - Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If - you choose this route you lose the ability to target earlier versions - of MacOS X. - * Install an SDK for an earlier version. This doesn't appear to be - supported by Apple, but has been reported to work - (http://stackoverflow.com/questions/5378518). - -Tweaking Google Test --------------------- - -Google Test can be used in diverse environments. The default -configuration may not work (or may not work well) out of the box in -some environments. However, you can easily tweak Google Test by -defining control macros on the compiler command line. Generally, -these macros are named like GTEST_XYZ and you define them to either 1 -or 0 to enable or disable a certain feature. - -We list the most frequently used macros below. For a complete list, -see file include/gtest/internal/gtest-port.h. - -### Choosing a TR1 Tuple Library ### - -Some Google Test features require the C++ Technical Report 1 (TR1) -tuple library, which is not yet available with all compilers. The -good news is that Google Test implements a subset of TR1 tuple that's -enough for its own need, and will automatically use this when the -compiler doesn't provide TR1 tuple. - -Usually you don't need to care about which tuple library Google Test -uses. However, if your project already uses TR1 tuple, you need to -tell Google Test to use the same TR1 tuple library the rest of your -project uses, or the two tuple implementations will clash. To do -that, add - - -DGTEST_USE_OWN_TR1_TUPLE=0 - -to the compiler flags while compiling Google Test and your tests. If -you want to force Google Test to use its own tuple library, just add - - -DGTEST_USE_OWN_TR1_TUPLE=1 - -to the compiler flags instead. - -If you don't want Google Test to use tuple at all, add - - -DGTEST_HAS_TR1_TUPLE=0 - -and all features using tuple will be disabled. - -### Multi-threaded Tests ### - -Google Test is thread-safe where the pthread library is available. -After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE -macro to see whether this is the case (yes if the macro is #defined to -1, no if it's undefined.). - -If Google Test doesn't correctly detect whether pthread is available -in your environment, you can force it with - - -DGTEST_HAS_PTHREAD=1 - -or - - -DGTEST_HAS_PTHREAD=0 - -When Google Test uses pthread, you may need to add flags to your -compiler and/or linker to select the pthread library, or you'll get -link errors. If you use the CMake script or the deprecated Autotools -script, this is taken care of for you. If you use your own build -script, you'll need to read your compiler and linker's manual to -figure out what flags to add. - -### As a Shared Library (DLL) ### - -Google Test is compact, so most users can build and link it as a -static library for the simplicity. You can choose to use Google Test -as a shared library (known as a DLL on Windows) if you prefer. - -To compile *gtest* as a shared library, add - - -DGTEST_CREATE_SHARED_LIBRARY=1 - -to the compiler flags. You'll also need to tell the linker to produce -a shared library instead - consult your linker's manual for how to do -it. - -To compile your *tests* that use the gtest shared library, add - - -DGTEST_LINKED_AS_SHARED_LIBRARY=1 - -to the compiler flags. - -Note: while the above steps aren't technically necessary today when -using some compilers (e.g. GCC), they may become necessary in the -future, if we decide to improve the speed of loading the library (see -http://gcc.gnu.org/wiki/Visibility for details). Therefore you are -recommended to always add the above flags when using Google Test as a -shared library. Otherwise a future release of Google Test may break -your build script. - -### Avoiding Macro Name Clashes ### - -In C++, macros don't obey namespaces. Therefore two libraries that -both define a macro of the same name will clash if you #include both -definitions. In case a Google Test macro clashes with another -library, you can force Google Test to rename its macro to avoid the -conflict. - -Specifically, if both Google Test and some other code define macro -FOO, you can add - - -DGTEST_DONT_DEFINE_FOO=1 - -to the compiler flags to tell Google Test to change the macro's name -from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST. -For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write - - GTEST_TEST(SomeTest, DoesThis) { ... } - -instead of - - TEST(SomeTest, DoesThis) { ... } - -in order to define a test. - -Upgrating from an Earlier Version ---------------------------------- - -We strive to keep Google Test releases backward compatible. -Sometimes, though, we have to make some breaking changes for the -users' long-term benefits. This section describes what you'll need to -do if you are upgrading from an earlier version of Google Test. - -### Upgrading from 1.3.0 or Earlier ### - -You may need to explicitly enable or disable Google Test's own TR1 -tuple library. See the instructions in section "Choosing a TR1 Tuple -Library". - -### Upgrading from 1.4.0 or Earlier ### - -The Autotools build script (configure + make) is no longer officially -supportted. You are encouraged to migrate to your own build system or -use CMake. If you still need to use Autotools, you can find -instructions in the README file from Google Test 1.4.0. - -On platforms where the pthread library is available, Google Test uses -it in order to be thread-safe. See the "Multi-threaded Tests" section -for what this means to your build script. - -If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google -Test will no longer compile. This should affect very few people, as a -large portion of STL (including ) doesn't compile in this mode -anyway. We decided to stop supporting it in order to greatly simplify -Google Test's implementation. - -Developing Google Test ----------------------- - -This section discusses how to make your own changes to Google Test. - -### Testing Google Test Itself ### - -To make sure your changes work as intended and don't break existing -functionality, you'll want to compile and run Google Test's own tests. -For that you can use CMake: - - mkdir mybuild - cd mybuild - cmake -Dgtest_build_tests=ON ${GTEST_DIR} - -Make sure you have Python installed, as some of Google Test's tests -are written in Python. If the cmake command complains about not being -able to find Python ("Could NOT find PythonInterp (missing: -PYTHON_EXECUTABLE)"), try telling it explicitly where your Python -executable can be found: - - cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR} - -Next, you can build Google Test and all of its own tests. On *nix, -this is usually done by 'make'. To run the tests, do - - make test - -All tests should pass. - -### Regenerating Source Files ### - -Some of Google Test's source files are generated from templates (not -in the C++ sense) using a script. A template file is named FOO.pump, -where FOO is the name of the file it will generate. For example, the -file include/gtest/internal/gtest-type-util.h.pump is used to generate -gtest-type-util.h in the same directory. - -Normally you don't need to worry about regenerating the source files, -unless you need to modify them. In that case, you should modify the -corresponding .pump files instead and run the pump.py Python script to -regenerate them. You can find pump.py in the scripts/ directory. -Read the Pump manual [2] for how to use it. - - [2] http://code.google.com/p/googletest/wiki/PumpManual - -### Contributing a Patch ### - -We welcome patches. Please read the Google Test developer's guide [3] -for how you can contribute. In particular, make sure you have signed -the Contributor License Agreement, or we won't be able to accept the -patch. - - [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide - -Happy testing! diff --git a/test/fmw/gtest/README.md b/test/fmw/gtest/README.md new file mode 100644 index 00000000000..46de3dd47fa --- /dev/null +++ b/test/fmw/gtest/README.md @@ -0,0 +1,345 @@ +### Generic Build Instructions + +#### Setup + +To build Google Test and your tests that use it, you need to tell your build +system where to find its headers and source files. The exact way to do it +depends on which build system you use, and is usually straightforward. + +#### Build + +Suppose you put Google Test in directory `${GTEST_DIR}`. To build it, create a +library build target (or a project as called by Visual Studio and Xcode) to +compile + + ${GTEST_DIR}/src/gtest-all.cc + +with `${GTEST_DIR}/include` in the system header search path and `${GTEST_DIR}` +in the normal header search path. Assuming a Linux-like system and gcc, +something like the following will do: + + g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ + -pthread -c ${GTEST_DIR}/src/gtest-all.cc + ar -rv libgtest.a gtest-all.o + +(We need `-pthread` as Google Test uses threads.) + +Next, you should compile your test source file with `${GTEST_DIR}/include` in +the system header search path, and link it with gtest and any other necessary +libraries: + + g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \ + -o your_test + +As an example, the make/ directory contains a Makefile that you can use to build +Google Test on systems where GNU make is available (e.g. Linux, Mac OS X, and +Cygwin). It doesn't try to build Google Test's own tests. Instead, it just +builds the Google Test library and a sample test. You can use it as a starting +point for your own build script. + +If the default settings are correct for your environment, the following commands +should succeed: + + cd ${GTEST_DIR}/make + make + ./sample1_unittest + +If you see errors, try to tweak the contents of `make/Makefile` to make them go +away. There are instructions in `make/Makefile` on how to do it. + +### Using CMake + +Google Test comes with a CMake build script ( +[CMakeLists.txt](https://github.com/google/googletest/blob/master/CMakeLists.txt)) +that can be used on a wide range of platforms ("C" stands for cross-platform.). +If you don't have CMake installed already, you can download it for free from +. + +CMake works by generating native makefiles or build projects that can be used in +the compiler environment of your choice. You can either build Google Test as a +standalone project or it can be incorporated into an existing CMake build for +another project. + +#### Standalone CMake Project + +When building Google Test as a standalone project, the typical workflow starts +with: + + mkdir mybuild # Create a directory to hold the build output. + cd mybuild + cmake ${GTEST_DIR} # Generate native build scripts. + +If you want to build Google Test's samples, you should replace the last command +with + + cmake -Dgtest_build_samples=ON ${GTEST_DIR} + +If you are on a \*nix system, you should now see a Makefile in the current +directory. Just type 'make' to build gtest. + +If you use Windows and have Visual Studio installed, a `gtest.sln` file and +several `.vcproj` files will be created. You can then build them using Visual +Studio. + +On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated. + +#### Incorporating Into An Existing CMake Project + +If you want to use gtest in a project which already uses CMake, then a more +robust and flexible approach is to build gtest as part of that project directly. +This is done by making the GoogleTest source code available to the main build +and adding it using CMake's `add_subdirectory()` command. This has the +significant advantage that the same compiler and linker settings are used +between gtest and the rest of your project, so issues associated with using +incompatible libraries (eg debug/release), etc. are avoided. This is +particularly useful on Windows. Making GoogleTest's source code available to the +main build can be done a few different ways: + +* Download the GoogleTest source code manually and place it at a known + location. This is the least flexible approach and can make it more difficult + to use with continuous integration systems, etc. +* Embed the GoogleTest source code as a direct copy in the main project's + source tree. This is often the simplest approach, but is also the hardest to + keep up to date. Some organizations may not permit this method. +* Add GoogleTest as a git submodule or equivalent. This may not always be + possible or appropriate. Git submodules, for example, have their own set of + advantages and drawbacks. +* Use CMake to download GoogleTest as part of the build's configure step. This + is just a little more complex, but doesn't have the limitations of the other + methods. + +The last of the above methods is implemented with a small piece of CMake code in +a separate file (e.g. `CMakeLists.txt.in`) which is copied to the build area and +then invoked as a sub-build _during the CMake stage_. That directory is then +pulled into the main build with `add_subdirectory()`. For example: + +New file `CMakeLists.txt.in`: + +``` cmake +cmake_minimum_required(VERSION 2.8.2) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" +) +``` + +Existing build's `CMakeLists.txt`: + +``` cmake +# Download and unpack googletest at configure time +configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src + ${CMAKE_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) + +# The gtest/gtest_main targets carry header search path +# dependencies automatically when using CMake 2.8.11 or +# later. Otherwise we have to add them here ourselves. +if (CMAKE_VERSION VERSION_LESS 2.8.11) + include_directories("${gtest_SOURCE_DIR}/include") +endif() + +# Now simply link against gtest or gtest_main as needed. Eg +add_executable(example example.cpp) +target_link_libraries(example gtest_main) +add_test(NAME example_test COMMAND example) +``` + +Note that this approach requires CMake 2.8.2 or later due to its use of the +`ExternalProject_Add()` command. The above technique is discussed in more detail +in [this separate article](http://crascit.com/2015/07/25/cmake-gtest/) which +also contains a link to a fully generalized implementation of the technique. + +##### Visual Studio Dynamic vs Static Runtimes + +By default, new Visual Studio projects link the C runtimes dynamically but +Google Test links them statically. This will generate an error that looks +something like the following: gtest.lib(gtest-all.obj) : error LNK2038: mismatch +detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value +'MDd_DynamicDebug' in main.obj + +Google Test already has a CMake option for this: `gtest_force_shared_crt` + +Enabling this option will make gtest link the runtimes dynamically too, and +match the project in which it is included. + +### Legacy Build Scripts + +Before settling on CMake, we have been providing hand-maintained build +projects/scripts for Visual Studio, Xcode, and Autotools. While we continue to +provide them for convenience, they are not actively maintained any more. We +highly recommend that you follow the instructions in the above sections to +integrate Google Test with your existing build system. + +If you still need to use the legacy build scripts, here's how: + +The msvc\ folder contains two solutions with Visual C++ projects. Open the +`gtest.sln` or `gtest-md.sln` file using Visual Studio, and you are ready to +build Google Test the same way you build any Visual Studio project. Files that +have names ending with -md use DLL versions of Microsoft runtime libraries (the +/MD or the /MDd compiler option). Files without that suffix use static versions +of the runtime libraries (the /MT or the /MTd option). Please note that one must +use the same option to compile both gtest and the test code. If you use Visual +Studio 2005 or above, we recommend the -md version as /MD is the default for new +projects in these versions of Visual Studio. + +On Mac OS X, open the `gtest.xcodeproj` in the `xcode/` folder using Xcode. +Build the "gtest" target. The universal binary framework will end up in your +selected build directory (selected in the Xcode "Preferences..." -> "Building" +pane and defaults to xcode/build). Alternatively, at the command line, enter: + + xcodebuild + +This will build the "Release" configuration of gtest.framework in your default +build location. See the "xcodebuild" man page for more information about +building different configurations and building in different locations. + +If you wish to use the Google Test Xcode project with Xcode 4.x and above, you +need to either: + +* update the SDK configuration options in xcode/Config/General.xconfig. + Comment options `SDKROOT`, `MACOS_DEPLOYMENT_TARGET`, and `GCC_VERSION`. If + you choose this route you lose the ability to target earlier versions of + MacOS X. +* Install an SDK for an earlier version. This doesn't appear to be supported + by Apple, but has been reported to work + (http://stackoverflow.com/questions/5378518). + +### Tweaking Google Test + +Google Test can be used in diverse environments. The default configuration may +not work (or may not work well) out of the box in some environments. However, +you can easily tweak Google Test by defining control macros on the compiler +command line. Generally, these macros are named like `GTEST_XYZ` and you define +them to either 1 or 0 to enable or disable a certain feature. + +We list the most frequently used macros below. For a complete list, see file +[include/gtest/internal/gtest-port.h](https://github.com/google/googletest/blob/master/include/gtest/internal/gtest-port.h). + +### Choosing a TR1 Tuple Library + +Some Google Test features require the C++ Technical Report 1 (TR1) tuple +library, which is not yet available with all compilers. The good news is that +Google Test implements a subset of TR1 tuple that's enough for its own need, and +will automatically use this when the compiler doesn't provide TR1 tuple. + +Usually you don't need to care about which tuple library Google Test uses. +However, if your project already uses TR1 tuple, you need to tell Google Test to +use the same TR1 tuple library the rest of your project uses, or the two tuple +implementations will clash. To do that, add + + -DGTEST_USE_OWN_TR1_TUPLE=0 + +to the compiler flags while compiling Google Test and your tests. If you want to +force Google Test to use its own tuple library, just add + + -DGTEST_USE_OWN_TR1_TUPLE=1 + +to the compiler flags instead. + +If you don't want Google Test to use tuple at all, add + + -DGTEST_HAS_TR1_TUPLE=0 + +and all features using tuple will be disabled. + +### Multi-threaded Tests + +Google Test is thread-safe where the pthread library is available. After +`#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE` macro to see +whether this is the case (yes if the macro is `#defined` to 1, no if it's +undefined.). + +If Google Test doesn't correctly detect whether pthread is available in your +environment, you can force it with + + -DGTEST_HAS_PTHREAD=1 + +or + + -DGTEST_HAS_PTHREAD=0 + +When Google Test uses pthread, you may need to add flags to your compiler and/or +linker to select the pthread library, or you'll get link errors. If you use the +CMake script or the deprecated Autotools script, this is taken care of for you. +If you use your own build script, you'll need to read your compiler and linker's +manual to figure out what flags to add. + +### As a Shared Library (DLL) + +Google Test is compact, so most users can build and link it as a static library +for the simplicity. You can choose to use Google Test as a shared library (known +as a DLL on Windows) if you prefer. + +To compile *gtest* as a shared library, add + + -DGTEST_CREATE_SHARED_LIBRARY=1 + +to the compiler flags. You'll also need to tell the linker to produce a shared +library instead - consult your linker's manual for how to do it. + +To compile your *tests* that use the gtest shared library, add + + -DGTEST_LINKED_AS_SHARED_LIBRARY=1 + +to the compiler flags. + +Note: while the above steps aren't technically necessary today when using some +compilers (e.g. GCC), they may become necessary in the future, if we decide to +improve the speed of loading the library (see + for details). Therefore you are recommended +to always add the above flags when using Google Test as a shared library. +Otherwise a future release of Google Test may break your build script. + +### Avoiding Macro Name Clashes + +In C++, macros don't obey namespaces. Therefore two libraries that both define a +macro of the same name will clash if you `#include` both definitions. In case a +Google Test macro clashes with another library, you can force Google Test to +rename its macro to avoid the conflict. + +Specifically, if both Google Test and some other code define macro FOO, you can +add + + -DGTEST_DONT_DEFINE_FOO=1 + +to the compiler flags to tell Google Test to change the macro's name from `FOO` +to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`, or `TEST`. For +example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write + + GTEST_TEST(SomeTest, DoesThis) { ... } + +instead of + + TEST(SomeTest, DoesThis) { ... } + +in order to define a test. diff --git a/test/fmw/gtest/include/gtest/gtest-death-test.h b/test/fmw/gtest/include/gtest/gtest-death-test.h index 957a69c6a9e..20c54d86951 100644 --- a/test/fmw/gtest/include/gtest/gtest-death-test.h +++ b/test/fmw/gtest/include/gtest/gtest-death-test.h @@ -26,14 +26,14 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ @@ -99,10 +99,11 @@ GTEST_API_ bool InDeathTestChild(); // // On the regular expressions used in death tests: // +// GOOGLETEST_CM0005 DO NOT DELETE // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // -// On other platforms (e.g. Windows), we only support a simple regex +// On other platforms (e.g. Windows or Mac), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE @@ -160,7 +161,7 @@ GTEST_API_ bool InDeathTestChild(); // is rarely a problem as people usually don't put the test binary // directory in PATH. // -// TODO(wan@google.com): make thread-safe death tests search the PATH. +// FIXME: make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output @@ -198,9 +199,10 @@ class GTEST_API_ ExitedWithCode { const int exit_code_; }; -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Tests that an exit code describes an exit due to termination by a // given signal. +// GOOGLETEST_CM0006 DO NOT DELETE class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); @@ -272,6 +274,54 @@ class GTEST_API_ KilledBySignal { # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. It is exposed publicly so that +// systems that have death-tests with stricter requirements than +// GTEST_HAS_DEATH_TEST can write their own equivalent of +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is @@ -284,9 +334,9 @@ class GTEST_API_ KilledBySignal { ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) + GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return) #endif } // namespace testing diff --git a/test/fmw/gtest/include/gtest/gtest-message.h b/test/fmw/gtest/include/gtest/gtest-message.h index fe879bca792..5ca041614cb 100644 --- a/test/fmw/gtest/include/gtest/gtest-message.h +++ b/test/fmw/gtest/include/gtest/gtest-message.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the Message class. // @@ -43,6 +42,8 @@ // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ @@ -50,6 +51,9 @@ #include "gtest/internal/gtest-port.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); @@ -196,7 +200,6 @@ class GTEST_API_ Message { std::string GetString() const; private: - #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ @@ -247,4 +250,6 @@ std::string StreamableToString(const T& streamable) { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ diff --git a/test/fmw/gtest/include/gtest/gtest-param-test.h b/test/fmw/gtest/include/gtest/gtest-param-test.h index d6702c8f162..3e95e4390e0 100644 --- a/test/fmw/gtest/include/gtest/gtest-param-test.h +++ b/test/fmw/gtest/include/gtest/gtest-param-test.h @@ -31,13 +31,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -79,7 +78,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -185,15 +184,10 @@ TEST_P(DerivedTest, DoesBlah) { # include #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -273,7 +267,7 @@ internal::ParamGenerator Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -1375,8 +1369,6 @@ internal::CartesianProductHolder10parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestPattern(\ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(\ + test_case_name, test_name)>()); \ return 0; \ } \ - static int gtest_registering_dummy_; \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ @@ -1403,19 +1398,37 @@ internal::CartesianProductHolder10 \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ + static ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + return ::testing::internal::GetParamNameGen \ + (__VA_ARGS__)(info); \ + } \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ + __FILE__, __LINE__) } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/fmw/gtest/include/gtest/gtest-param-test.h.pump b/test/fmw/gtest/include/gtest/gtest-param-test.h.pump index 2dc9303b5e3..274f2b3b569 100644 --- a/test/fmw/gtest/include/gtest/gtest-param-test.h.pump +++ b/test/fmw/gtest/include/gtest/gtest-param-test.h.pump @@ -30,13 +30,12 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: vladl@google.com (Vlad Losev) -// // Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) +// in Google C++ Testing and Mocking Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ @@ -78,7 +77,7 @@ TEST_P(FooTest, HasBlahBlah) { // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which +// (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // @@ -184,15 +183,10 @@ TEST_P(DerivedTest, DoesBlah) { # include #endif -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-param-util-generated.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Functions producing parameter generators. @@ -272,7 +266,7 @@ internal::ParamGenerator Range(T start, T end) { // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// INSTANTIATE_TEST_CASE_P(StringSequence, StringTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": @@ -441,8 +435,6 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( ]] # endif // GTEST_HAS_COMBINE - - # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ @@ -453,14 +445,17 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestPattern(\ + GTEST_STRINGIFY_(test_case_name), \ + GTEST_STRINGIFY_(test_name), \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(\ + test_case_name, test_name)>()); \ return 0; \ } \ - static int gtest_registering_dummy_; \ + static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ @@ -469,19 +464,37 @@ internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine( GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ +// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user +// to specify a function or functor that generates custom test name suffixes +// based on the test parameters. The function should accept one argument of +// type testing::TestParamInfo, and return std::string. +// +// testing::PrintToStringParamName is a builtin test suffix generator that +// returns the value of testing::PrintToString(GetParam()). +// +// Note: test names must be non-empty, unique, and may only contain ASCII +// alphanumeric characters or underscore. Because PrintToString adds quotes +// to std::string and C strings, it won't work for these types. + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ + static ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ + static ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo& info) { \ + return ::testing::internal::GetParamNameGen \ + (__VA_ARGS__)(info); \ + } \ + static int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) + #test_case_name, \ + ::testing::internal::CodeLocation(\ + __FILE__, __LINE__))->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + >est_##prefix##test_case_name##_EvalGenerateName_, \ + __FILE__, __LINE__) } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ diff --git a/test/fmw/gtest/include/gtest/gtest-printers.h b/test/fmw/gtest/include/gtest/gtest-printers.h index 0639d9f5869..71f2aaec949 100644 --- a/test/fmw/gtest/include/gtest/gtest-printers.h +++ b/test/fmw/gtest/include/gtest/gtest-printers.h @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -46,6 +45,10 @@ // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // +// However if T is an STL-style container then it is printed element-wise +// unless foo::PrintTo(const T&, ostream*) is defined. Note that +// operator<<() is ignored for container types. +// // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. @@ -92,6 +95,8 @@ // being defined as many user-defined container types don't have // value_type. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ @@ -103,6 +108,16 @@ #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" +#if GTEST_HAS_STD_TUPLE_ +# include +#endif + +#if GTEST_HAS_ABSL +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/variant.h" +#endif // GTEST_HAS_ABSL + namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are @@ -121,7 +136,11 @@ enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) - kOtherType // anything else +#if GTEST_HAS_ABSL + kConvertibleToStringView, // a type implicitly convertible to + // absl::string_view +#endif + kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called @@ -133,7 +152,8 @@ class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), + PrintBytesInObjectTo(static_cast( + reinterpret_cast(&value)), sizeof(value), os); } }; @@ -147,10 +167,10 @@ template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); + std::string pretty_str = value.ShortDebugString(); + if (pretty_str.length() > kProtobufOneLinerMaxLength) { + pretty_str = "\n" + value.DebugString(); + } *os << ("<" + pretty_str + ">"); } }; @@ -171,6 +191,19 @@ class TypeWithoutFormatter { } }; +#if GTEST_HAS_ABSL +template +class TypeWithoutFormatter { + public: + // Since T has neither operator<< nor PrintTo() but can be implicitly + // converted to absl::string_view, we print it as a absl::string_view. + // + // Note: the implementation is further below, as it depends on + // internal::PrintTo symbol which is defined later in the file. + static void PrintValue(const T& value, ::std::ostream* os); +}; +#endif + // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an @@ -198,10 +231,19 @@ class TypeWithoutFormatter { template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + TypeWithoutFormatter::value + ? kProtobuf + : internal::ImplicitlyConvertible< + const T&, internal::BiggestInt>::value + ? kConvertibleToInteger + : +#if GTEST_HAS_ABSL + internal::ImplicitlyConvertible< + const T&, absl::string_view>::value + ? kConvertibleToStringView + : +#endif + kOtherType)>::PrintValue(x, &os); return os; } @@ -250,6 +292,103 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { namespace testing { namespace internal { +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_GLOBAL_STRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); +#endif + +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); +#endif + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. @@ -263,11 +402,18 @@ class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); +enum DefaultPrinterType { + kPrintContainer, + kPrintPointer, + kPrintFunctionPointer, + kPrintOther, +}; +template struct WrapPrinterType {}; + // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; @@ -300,40 +446,34 @@ void DefaultPrintTo(IsContainer /* dummy */, // implementation-defined. Therefore they will be printed as raw // bytes.) template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } +} +template +void DefaultPrintTo(WrapPrinterType /* dummy */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. + *os << reinterpret_cast(p); } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, +void DefaultPrintTo(WrapPrinterType /* dummy */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } @@ -351,11 +491,8 @@ void DefaultPrintTo(IsNotContainer /* dummy */, // wants). template void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. + // DefaultPrintTo() is overloaded. The type of its first argument + // determines which version will be picked. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: @@ -367,13 +504,27 @@ void PrintTo(const T& value, ::std::ostream* os) { // elements; therefore we check for container types here to ensure // that our format is used. // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); + // Note that MSVC and clang-cl do allow an implicit conversion from + // pointer-to-function to pointer-to-object, but clang-cl warns on it. + // So don't use ImplicitlyConvertible if it can be helped since it will + // cause this warning, and use a separate overload of DefaultPrintTo for + // function pointers so that the `*os << p` in the object pointer overload + // doesn't cause that warning either. + DefaultPrintTo( + WrapPrinterType < + (sizeof(IsContainerTest(0)) == sizeof(IsContainer)) && + !IsRecursiveContainer::value + ? kPrintContainer + : !is_pointer::value + ? kPrintOther +#if GTEST_LANG_CXX11 + : std::is_function::type>::value +#else + : !internal::ImplicitlyConvertible::value +#endif + ? kPrintFunctionPointer + : kPrintPointer > (), + value, os); } // The following list of PrintTo() overloads tells @@ -480,14 +631,27 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { } #endif // GTEST_HAS_STD_WSTRING -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. +#if GTEST_HAS_ABSL +// Overload for absl::string_view. +inline void PrintTo(absl::string_view sp, ::std::ostream* os) { + PrintTo(::std::string(sp), os); +} +#endif // GTEST_HAS_ABSL +#if GTEST_LANG_CXX11 +inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; } +#endif // GTEST_LANG_CXX11 + +#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os); +#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. // Overloaded PrintTo() for tuples of various arities. We support // tuples of up-to 10 fields. The following implementation works @@ -561,6 +725,13 @@ void PrintTo( } #endif // GTEST_HAS_TR1_TUPLE +#if GTEST_HAS_STD_TUPLE_ +template +void PrintTo(const ::std::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_STD_TUPLE_ + // Overload for std::pair. template void PrintTo(const ::std::pair& value, ::std::ostream* os) { @@ -580,10 +751,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the @@ -600,11 +768,51 @@ class UniversalPrinter { PrintTo(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; +#if GTEST_HAS_ABSL + +// Printer for absl::optional + +template +class UniversalPrinter<::absl::optional> { + public: + static void Print(const ::absl::optional& value, ::std::ostream* os) { + *os << '('; + if (!value) { + *os << "nullopt"; + } else { + UniversalPrint(*value, os); + } + *os << ')'; + } +}; + +// Printer for absl::variant + +template +class UniversalPrinter<::absl::variant> { + public: + static void Print(const ::absl::variant& value, ::std::ostream* os) { + *os << '('; + absl::visit(Visitor{os}, value); + *os << ')'; + } + + private: + struct Visitor { + template + void operator()(const U& u) const { + *os << "'" << GetTypeName() << "' with value "; + UniversalPrint(u, os); + } + ::std::ostream* os; + }; +}; + +#endif // GTEST_HAS_ABSL + // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template @@ -618,7 +826,7 @@ void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { @@ -654,10 +862,7 @@ class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here @@ -668,9 +873,7 @@ class UniversalPrinter { UniversalPrint(value, os); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value @@ -705,7 +908,7 @@ class UniversalTersePrinter { if (str == NULL) { *os << "NULL"; } else { - UniversalPrint(string(str), os); + UniversalPrint(std::string(str), os); } } }; @@ -756,16 +959,70 @@ void UniversalPrint(const T& value, ::std::ostream* os) { UniversalPrinter::Print(value, os); } -#if GTEST_HAS_TR1_TUPLE -typedef ::std::vector Strings; +typedef ::std::vector< ::std::string> Strings; +// TuplePolicy must provide: +// - tuple_size +// size of tuple TupleT. +// - get(const TupleT& t) +// static function extracting element I of tuple TupleT. +// - tuple_element::type +// type of element I of tuple TupleT. +template +struct TuplePolicy; + +#if GTEST_HAS_TR1_TUPLE +template +struct TuplePolicy { + typedef TupleT Tuple; + static const size_t tuple_size = ::std::tr1::tuple_size::value; + + template + struct tuple_element : ::std::tr1::tuple_element(I), Tuple> { + }; + + template + static typename AddReference::type>::type +#else + static_cast(I), Tuple>::type>::type +#endif + get(const Tuple& tuple) { + return ::std::tr1::get(tuple); + } +}; +template +const size_t TuplePolicy::tuple_size; +#endif // GTEST_HAS_TR1_TUPLE + +#if GTEST_HAS_STD_TUPLE_ +template +struct TuplePolicy< ::std::tuple > { + typedef ::std::tuple Tuple; + static const size_t tuple_size = ::std::tuple_size::value; + + template + struct tuple_element : ::std::tuple_element {}; + + template + static const typename ::std::tuple_element::type& get( + const Tuple& tuple) { + return ::std::get(tuple); + } +}; +template +const size_t TuplePolicy< ::std::tuple >::tuple_size; +#endif // GTEST_HAS_STD_TUPLE_ + +#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // This helper template allows PrintTo() for tuples and // UniversalTersePrintTupleFieldsToStrings() to be defined by // induction on the number of tuple fields. The idea is that // TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. - +// // The inductive case. template struct TuplePrefixPrinter { @@ -773,9 +1030,14 @@ struct TuplePrefixPrinter { template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); + GTEST_INTENTIONAL_CONST_COND_PUSH_() + if (N > 1) { + GTEST_INTENTIONAL_CONST_COND_POP_() + *os << ", "; + } + UniversalPrinter< + typename TuplePolicy::template tuple_element::type> + ::Print(TuplePolicy::template get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, @@ -784,12 +1046,12 @@ struct TuplePrefixPrinter { static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); + UniversalTersePrint(TuplePolicy::template get(t), &ss); strings->push_back(ss.str()); } }; -// Base cases. +// Base case. template <> struct TuplePrefixPrinter<0> { template @@ -798,34 +1060,13 @@ struct TuplePrefixPrinter<0> { template static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} }; -// We have to specialize the entire TuplePrefixPrinter<> class -// template here, even though the definition of -// TersePrintPrefixToStrings() is the same as the generic version, as -// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't -// support specializing a method template of a class template. -template <> -struct TuplePrefixPrinter<1> { - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); - } - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get<0>(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os) { +// Helper function for printing a tuple. +// Tuple must be either std::tr1::tuple or std::tuple type. +template +void PrintTupleTo(const Tuple& t, ::std::ostream* os) { *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); + TuplePrefixPrinter::tuple_size>::PrintPrefixTo(t, os); *os << ")"; } @@ -835,14 +1076,24 @@ void PrintTupleTo(const T& t, ::std::ostream* os) { template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TuplePrefixPrinter::tuple_size>:: TersePrintPrefixToStrings(value, &result); return result; } -#endif // GTEST_HAS_TR1_TUPLE +#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ } // namespace internal +#if GTEST_HAS_ABSL +namespace internal2 { +template +void TypeWithoutFormatter::PrintValue( + const T& value, ::std::ostream* os) { + internal::PrintTo(absl::string_view(value), os); +} +} // namespace internal2 +#endif + template ::std::string PrintToString(const T& value) { ::std::stringstream ss; @@ -852,4 +1103,9 @@ template } // namespace testing +// Include any custom printer added by the local installation. +// We must include this header at the end to make sure it can use the +// declarations from this file. +#include "gtest/internal/custom/gtest-printers.h" + #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ diff --git a/test/fmw/gtest/include/gtest/gtest-spi.h b/test/fmw/gtest/include/gtest/gtest-spi.h index f63fa9a1b2a..1e8983938ea 100644 --- a/test/fmw/gtest/include/gtest/gtest-spi.h +++ b/test/fmw/gtest/include/gtest/gtest-spi.h @@ -26,17 +26,21 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). +// GOOGLETEST_CM0004 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include "gtest/gtest.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // This helper class can be used to mock out Google Test failure reporting @@ -97,13 +101,12 @@ class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); + TestPartResult::Type type, const std::string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; - const string substr_; + const std::string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; @@ -112,6 +115,8 @@ class GTEST_API_ SingleFailureChecker { } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' diff --git a/test/fmw/gtest/include/gtest/gtest-test-part.h b/test/fmw/gtest/include/gtest/gtest-test-part.h index 77eb844839d..1c7b89e0879 100644 --- a/test/fmw/gtest/include/gtest/gtest-test-part.h +++ b/test/fmw/gtest/include/gtest/gtest-test-part.h @@ -27,8 +27,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: mheule@google.com (Markus Heule) -// +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ @@ -38,6 +37,9 @@ #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // A copyable object representing the result of a test part (i.e. an @@ -143,7 +145,7 @@ class GTEST_API_ TestPartResultArray { }; // This interface knows how to report a test part result. -class TestPartResultReporterInterface { +class GTEST_API_ TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} @@ -176,4 +178,6 @@ class GTEST_API_ HasNewFatalFailureHelper } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ diff --git a/test/fmw/gtest/include/gtest/gtest-typed-test.h b/test/fmw/gtest/include/gtest/gtest-typed-test.h index fe1e83b274b..74bce46bdc5 100644 --- a/test/fmw/gtest/include/gtest/gtest-typed-test.h +++ b/test/fmw/gtest/include/gtest/gtest-typed-test.h @@ -26,8 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + + +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ @@ -82,6 +83,24 @@ TYPED_TEST(FooTest, DoesBlah) { TYPED_TEST(FooTest, HasPropertyA) { ... } +// TYPED_TEST_CASE takes an optional third argument which allows to specify a +// class that generates custom test name suffixes based on the type. This should +// be a class which has a static template function GetName(int index) returning +// a string for each type. The provided integer index equals the index of the +// type in the provided type list. In many cases the index can be ignored. +// +// For example: +// class MyTypeNames { +// public: +// template +// static std::string GetName(int) { +// if (std::is_same()) return "char"; +// if (std::is_same()) return "int"; +// if (std::is_same()) return "unsignedInt"; +// } +// }; +// TYPED_TEST_CASE(FooTest, MyTypes, MyTypeNames); + #endif // 0 // Type-parameterized tests are abstract test patterns parameterized @@ -143,6 +162,11 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); +// +// Similar to the optional argument of TYPED_TEST_CASE above, +// INSTANTIATE_TEST_CASE_P takes an optional fourth argument which allows to +// generate custom names. +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes, MyTypeNames); #endif // 0 @@ -159,31 +183,46 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ +// Expands to the name of the typedef for the NameGenerator, responsible for +// creating the suffixes of the name. +#define GTEST_NAME_GENERATOR_(TestCaseName) \ + gtest_type_params_##TestCaseName##_NameGenerator + // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) +# define TYPED_TEST_CASE(CaseName, Types, ...) \ + typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \ + CaseName); \ + typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ + GTEST_NAME_GENERATOR_(CaseName) -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##CaseName##_##TestName##_registered_ \ + GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + #CaseName, #TestName, 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST @@ -240,19 +279,27 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) \ + GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames( \ + __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types, ...) \ + static bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase< \ + CaseName, GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \ + ::testing::internal::TypeList< Types >::type>:: \ + Register(#Prefix, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_CASE_P_STATE_(CaseName), #CaseName, \ + GTEST_REGISTERED_TEST_NAMES_(CaseName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::TypeList< Types >::type>()) #endif // GTEST_HAS_TYPED_TEST_P diff --git a/test/fmw/gtest/include/gtest/gtest.h b/test/fmw/gtest/include/gtest/gtest.h index 6fa0a3925e7..5df4b0a3a71 100644 --- a/test/fmw/gtest/include/gtest/gtest.h +++ b/test/fmw/gtest/include/gtest/gtest.h @@ -26,10 +26,9 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. @@ -48,6 +47,8 @@ // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ @@ -65,23 +66,35 @@ #include "gtest/gtest-test-part.h" #include "gtest/gtest-typed-test.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// If ::std::string and ::string are the same class on your platform +// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. // -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { +// Silence C4100 (unreferenced formal parameter) and 4805 +// unsafe mix of type 'const int' and type 'const bool' +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4805) +# pragma warning(disable:4100) +#endif + + // Declares the flags. // This flag temporary enables the disabled tests. @@ -103,6 +116,10 @@ GTEST_DECLARE_string_(color); // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); +// This flag controls whether Google Test installs a signal handler that dumps +// debugging information when fatal signals are raised. +GTEST_DECLARE_bool_(install_failure_signal_handler); + // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); @@ -115,6 +132,9 @@ GTEST_DECLARE_string_(output); // test. GTEST_DECLARE_bool_(print_time); +// This flags control whether Google Test prints UTF8 characters as text. +GTEST_DECLARE_bool_(print_utf8); + // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); @@ -135,7 +155,7 @@ GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. +// non-zero code otherwise. For use with an external test framework. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported @@ -143,6 +163,10 @@ GTEST_DECLARE_bool_(throw_on_failure); // the specified host machine. GTEST_DECLARE_string_(stream_result_to); +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DECLARE_string_(flagfile); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; @@ -160,6 +184,7 @@ class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; +class FuchsiaDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); @@ -258,8 +283,35 @@ class GTEST_API_ AssertionResult { // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) +#endif + // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} + // + // T must be contextually convertible to bool. + // + // The second parameter prevents this overload from being considered if + // the argument is implicitly convertible to AssertionResult. In that case + // we want AssertionResult's copy constructor to be used. + template + explicit AssertionResult( + const T& success, + typename internal::EnableIf< + !internal::ImplicitlyConvertible::value>::type* + /*enabler*/ = NULL) + : success_(success) {} + +#if defined(_MSC_VER) && _MSC_VER < 1910 + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + + // Assignment operator. + AssertionResult& operator=(AssertionResult other) { + swap(other); + return *this; + } // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT @@ -274,7 +326,7 @@ class GTEST_API_ AssertionResult { const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } - // TODO(vladl@google.com): Remove this after making sure no clients use it. + // FIXME: Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } @@ -300,6 +352,9 @@ class GTEST_API_ AssertionResult { message_->append(a_message.GetString().c_str()); } + // Swap the contents of this AssertionResult with other. + void swap(AssertionResult& other); + // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation @@ -307,8 +362,6 @@ class GTEST_API_ AssertionResult { // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; - - GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. @@ -321,6 +374,15 @@ GTEST_API_ AssertionResult AssertionFailure(); // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); +} // namespace testing + +// Includes the auto-generated header that implements a family of generic +// predicate assertion macros. This include comes late because it relies on +// APIs declared above. +#include "gtest/gtest_pred_impl.h" + +namespace testing { + // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and @@ -331,12 +393,12 @@ GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // this for you. // // The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: +// to be used in a TEST_F. For example: // // class FooTest : public testing::Test { // protected: -// virtual void SetUp() { ... } -// virtual void TearDown() { ... } +// void SetUp() override { ... } +// void TearDown() override { ... } // ... // }; // @@ -428,20 +490,19 @@ class GTEST_API_ Test { // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; + const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; - // Often a user mis-spells SetUp() as Setup() and spends a long time + // Often a user misspells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. + // will be a conflict if void Setup() is declared in the user's + // test fixture. // // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. + // if the method is called from the user's test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // @@ -527,9 +588,8 @@ class GTEST_API_ TestResult { // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. + // Returns the i-th test part result among all the results. i can range from 0 + // to total_part_count() - 1. If i is not in that range, aborts the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to @@ -546,6 +606,7 @@ class GTEST_API_ TestResult { friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; + friend class internal::FuchsiaDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { @@ -571,7 +632,7 @@ class GTEST_API_ TestResult { // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. + // FIXME: Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); @@ -646,6 +707,15 @@ class GTEST_API_ TestInfo { return NULL; } + // Returns the file name where this test is defined. + const char* file() const { return location_.file.c_str(); } + + // Returns the line where this test is defined. + int line() const { return location_.line; } + + // Return true if this test should not be run because it's in another shard. + bool is_in_another_shard() const { return is_in_another_shard_; } + // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. @@ -666,10 +736,9 @@ class GTEST_API_ TestInfo { // Returns true iff this test will appear in the XML report. bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; + // The XML report includes tests matching the filter, excluding those + // run in other shards. + return matches_filter_ && !is_in_another_shard_; } // Returns the result of the test. @@ -688,6 +757,7 @@ class GTEST_API_ TestInfo { const char* name, const char* type_param, const char* value_param, + internal::CodeLocation code_location, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, @@ -699,6 +769,7 @@ class GTEST_API_ TestInfo { const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); @@ -725,11 +796,13 @@ class GTEST_API_ TestInfo { // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; + internal::CodeLocation location_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. + bool is_in_another_shard_; // Will be run in another shard. internal::TestFactoryBase* const factory_; // The factory that creates // the test object @@ -924,7 +997,7 @@ class GTEST_API_ TestCase { }; // An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own +// environment. You should subclass this to define your own // environment(s). // // An Environment object does the set-up and tear-down in virtual @@ -954,6 +1027,18 @@ class Environment { virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; +#if GTEST_HAS_EXCEPTIONS + +// Exception which can be thrown from TestEventListener::OnTestPartResult. +class GTEST_API_ AssertionException + : public internal::GoogleTestFailureException { + public: + explicit AssertionException(const TestPartResult& result) + : GoogleTestFailureException(result) {} +}; + +#endif // GTEST_HAS_EXCEPTIONS + // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { @@ -982,6 +1067,8 @@ class TestEventListener { virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. + // If you want to throw an exception from this function to skip to the next + // TEST, it must be AssertionException defined above, or inherited from it. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. @@ -1148,14 +1235,12 @@ class GTEST_API_ UnitTest { // Returns the random seed used at the start of the current test run. int random_seed() const; -#if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; @@ -1255,11 +1340,11 @@ class GTEST_API_ UnitTest { internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } - // These classes and funcions are friends as they need to access private + // These classes and functions are friends as they need to access private // members of UnitTest. + friend class ScopedTrace; friend class Test; friend class internal::AssertHelper; - friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); @@ -1336,137 +1421,40 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { -// FormatForComparison::Format(value) formats a -// value of type ToPrint that is an operand of a comparison assertion -// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in -// the comparison, and is used to help determine the best way to -// format the value. In particular, when the value is a C string -// (char pointer) and the other operand is an STL string object, we -// want to format the C string as a string, since we know it is -// compared by value with the string object. If the value is a char -// pointer but the other operand is not an STL string object, we don't -// know whether the pointer is supposed to point to a NUL-terminated -// string, and thus want to print it as a pointer to be safe. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// The default case. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint& value) { - return ::testing::PrintToString(value); - } -}; - -// Array. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); - } -}; - -// By default, print C string as pointers to be safe, as we don't know -// whether they actually point to a NUL-terminated string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ - -// If a C string is compared with an STL string object, we know it's meant -// to point to a NUL-terminated string, and thus can print it as a string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); - -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif - -#if GTEST_HAS_STD_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); -#endif - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ - -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char* or void*, and print it as a C string when it is compared -// against an std::string object, for example. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers +// when calling EXPECT_* in a tight loop. template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { - return FormatForComparison::Format(value); +AssertionResult CmpHelperEQFailure(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, const T2& rhs) { + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), + false); } // The helper function for {ASSERT|EXPECT}_EQ. template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + if (lhs == rhs) { return AssertionSuccess(); } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); + return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); +GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() @@ -1477,12 +1465,11 @@ class EqHelper { public: // This templatized version is for the general case. template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // With this overloaded version, we allow anonymous enums to be used @@ -1491,12 +1478,11 @@ class EqHelper { // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + static AssertionResult Compare(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } }; @@ -1511,40 +1497,52 @@ class EqHelper { // EXPECT_EQ(false, a_bool). template static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual, + const char* lhs_expression, + const char* rhs_expression, + const T1& lhs, + const T2& rhs, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); + return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, + const char* lhs_expression, + const char* rhs_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. - Secret* /* expected (NULL) */, - T* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); + Secret* /* lhs (NULL) */, + T* rhs) { + // We already know that 'lhs' is a null pointer. + return CmpHelperEQ(lhs_expression, rhs_expression, + static_cast(NULL), rhs); } }; +// Separate the error generating code from the code path to reduce the stack +// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers +// when calling EXPECT_OP in a tight loop. +template +AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, + const T1& val1, const T2& val2, + const char* op) { + return AssertionFailure() + << "Expected: (" << expr1 << ") " << op << " (" << expr2 + << "), actual: " << FormatForComparisonFailureMessage(val1, val2) + << " vs " << FormatForComparisonFailureMessage(val2, val1); +} + // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. @@ -1555,6 +1553,7 @@ class EqHelper { // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ @@ -1562,10 +1561,7 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ @@ -1589,18 +1585,18 @@ GTEST_IMPL_CMP_HELPER_(GT, >); // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); // The helper function for {ASSERT|EXPECT}_STRNE. // @@ -1622,10 +1618,10 @@ GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); // Helper function for *_STRNE on wide strings. // @@ -1683,28 +1679,28 @@ namespace internal { // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); +AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, + const char* rhs_expression, + RawType lhs_value, + RawType rhs_value) { + const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } - ::std::stringstream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; + ::std::stringstream lhs_ss; + lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << lhs_value; - ::std::stringstream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; + ::std::stringstream rhs_ss; + rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << rhs_value; - return EqFailure(expected_expression, - actual_expression, - StringStreamToString(&expected_ss), - StringStreamToString(&actual_ss), + return EqFailure(lhs_expression, + rhs_expression, + StringStreamToString(&lhs_ss), + StringStreamToString(&rhs_ss), false); } @@ -1761,7 +1757,6 @@ class GTEST_API_ AssertHelper { } // namespace internal -#if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting @@ -1838,8 +1833,6 @@ template class TestWithParam : public Test, public WithParamInterface { }; -#endif // GTEST_HAS_PARAM_TEST - // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. @@ -1924,18 +1917,14 @@ class TestWithParam : public Test, public WithParamInterface { GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -#include "gtest/gtest_pred_impl.h" - // Macros for testing equalities and inequalities. // -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2 +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, @@ -1957,8 +1946,8 @@ class TestWithParam : public Test, public WithParamInterface { // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to +// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // @@ -1969,17 +1958,17 @@ class TestWithParam : public Test, public WithParamInterface { // // Examples: // -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); +// EXPECT_NE(Foo(), 5); +// EXPECT_EQ(a_pointer, NULL); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; -#define EXPECT_EQ(expected, actual) \ +#define EXPECT_EQ(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) + EqHelper::Compare, \ + val1, val2) +#define EXPECT_NE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ @@ -1989,10 +1978,10 @@ class TestWithParam : public Test, public WithParamInterface { #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) -#define GTEST_ASSERT_EQ(expected, actual) \ +#define GTEST_ASSERT_EQ(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) + EqHelper::Compare, \ + val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ @@ -2047,29 +2036,29 @@ class TestWithParam : public Test, public WithParamInterface { // // These macros evaluate their arguments exactly once. -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STREQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASEEQ(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STREQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASEEQ(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): // Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. @@ -2079,21 +2068,21 @@ class TestWithParam : public Test, public WithParamInterface { // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. -#define EXPECT_FLOAT_EQ(expected, actual)\ +#define EXPECT_FLOAT_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define EXPECT_DOUBLE_EQ(expected, actual)\ +#define EXPECT_DOUBLE_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_FLOAT_EQ(expected, actual)\ +#define ASSERT_FLOAT_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) -#define ASSERT_DOUBLE_EQ(expected, actual)\ +#define ASSERT_DOUBLE_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) + val1, val2) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ @@ -2156,6 +2145,57 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) +// Causes a trace (including the given source file path and line number, +// and the given message) to be included in every test failure message generated +// by code in the scope of the lifetime of an instance of this class. The effect +// is undone with the destruction of the instance. +// +// The message argument can be anything streamable to std::ostream. +// +// Example: +// testing::ScopedTrace trace("file.cc", 123, "message"); +// +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + + // Template version. Uses Message() to convert the values into strings. + // Slow, but flexible. + template + ScopedTrace(const char* file, int line, const T& message) { + PushTrace(file, line, (Message() << message).GetString()); + } + + // Optimize for some known types. + ScopedTrace(const char* file, int line, const char* message) { + PushTrace(file, line, message ? message : "(null)"); + } + +#if GTEST_HAS_GLOBAL_STRING + ScopedTrace(const char* file, int line, const ::string& message) { + PushTrace(file, line, message); + } +#endif + + ScopedTrace(const char* file, int line, const std::string& message) { + PushTrace(file, line, message); + } + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + void PushTrace(const char* file, int line, std::string message); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is @@ -2167,9 +2207,14 @@ GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. +// +// Assuming that each thread maintains its own stack of traces. +// Therefore, a SCOPED_TRACE() would (correctly) only affect the +// assertions in its own thread. #define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) + ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, (message)) + // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are @@ -2215,8 +2260,8 @@ bool StaticAssertTypeEq() { // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // -// The user should put his test code between braces after using this -// macro. Example: +// Test code should appear between braces after an invocation of +// this macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; @@ -2249,7 +2294,7 @@ bool StaticAssertTypeEq() { // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: +// the test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: @@ -2264,14 +2309,22 @@ bool StaticAssertTypeEq() { // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); +// EXPECT_EQ(a_.size(), 0); +// EXPECT_EQ(b_.size(), 1); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) +// Returns a path to temporary directory. +// Tries to determine an appropriate directory for the platform. +GTEST_API_ std::string TempDir(); + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } // namespace testing // Use this function in main() to run all tests. It returns 0 if all @@ -2288,4 +2341,6 @@ inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/test/fmw/gtest/include/gtest/gtest_pred_impl.h b/test/fmw/gtest/include/gtest/gtest_pred_impl.h index 30ae712f50e..0c1105cb8eb 100644 --- a/test/fmw/gtest/include/gtest/gtest_pred_impl.h +++ b/test/fmw/gtest/include/gtest/gtest_pred_impl.h @@ -27,18 +27,19 @@ // (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 file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// This file is AUTOMATICALLY GENERATED on 01/02/2018 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ +#include "gtest/gtest.h" + +namespace testing { // This header implements a family of generic predicate assertion // macros: @@ -66,8 +67,6 @@ // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. @@ -355,4 +354,6 @@ AssertionResult AssertPred5Helper(const char* pred_text, +} // namespace testing + #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ diff --git a/test/fmw/gtest/include/gtest/gtest_prod.h b/test/fmw/gtest/include/gtest/gtest_prod.h index da80ddc6c70..e651671ebde 100644 --- a/test/fmw/gtest/include/gtest/gtest_prod.h +++ b/test/fmw/gtest/include/gtest/gtest_prod.h @@ -26,10 +26,10 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. +// Google C++ Testing and Mocking Framework definitions useful in production code. +// GOOGLETEST_CM0003 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ @@ -40,17 +40,20 @@ // // class MyClass { // private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); +// void PrivateMethod(); +// FRIEND_TEST(MyClassTest, PrivateMethodWorks); // }; // // class MyClassTest : public testing::Test { // // ... // }; // -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. +// TEST_F(MyClassTest, PrivateMethodWorks) { +// // Can call MyClass::PrivateMethod() here. // } +// +// Note: The test class must be in the same namespace as the class being tested. +// For example, putting MyClassTest in an anonymous namespace will not work. #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test diff --git a/test/fmw/gtest/include/gtest/internal/custom/README.md b/test/fmw/gtest/include/gtest/internal/custom/README.md new file mode 100644 index 00000000000..ff391fb4e2b --- /dev/null +++ b/test/fmw/gtest/include/gtest/internal/custom/README.md @@ -0,0 +1,56 @@ +# Customization Points + +The custom directory is an injection point for custom user configurations. + +## Header `gtest.h` + +### The following macros can be defined: + +* `GTEST_OS_STACK_TRACE_GETTER_` - The name of an implementation of + `OsStackTraceGetterInterface`. +* `GTEST_CUSTOM_TEMPDIR_FUNCTION_` - An override for `testing::TempDir()`. See + `testing::TempDir` for semantics and signature. + +## Header `gtest-port.h` + +The following macros can be defined: + +### Flag related macros: + +* `GTEST_FLAG(flag_name)` +* `GTEST_USE_OWN_FLAGFILE_FLAG_` - Define to 0 when the system provides its + own flagfile flag parsing. +* `GTEST_DECLARE_bool_(name)` +* `GTEST_DECLARE_int32_(name)` +* `GTEST_DECLARE_string_(name)` +* `GTEST_DEFINE_bool_(name, default_val, doc)` +* `GTEST_DEFINE_int32_(name, default_val, doc)` +* `GTEST_DEFINE_string_(name, default_val, doc)` + +### Logging: + +* `GTEST_LOG_(severity)` +* `GTEST_CHECK_(condition)` +* Functions `LogToStderr()` and `FlushInfoLog()` have to be provided too. + +### Threading: + +* `GTEST_HAS_NOTIFICATION_` - Enabled if Notification is already provided. +* `GTEST_HAS_MUTEX_AND_THREAD_LOCAL_` - Enabled if `Mutex` and `ThreadLocal` + are already provided. Must also provide `GTEST_DECLARE_STATIC_MUTEX_(mutex)` + and `GTEST_DEFINE_STATIC_MUTEX_(mutex)` +* `GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)` +* `GTEST_LOCK_EXCLUDED_(locks)` + +### Underlying library support features + +* `GTEST_HAS_CXXABI_H_` + +### Exporting API symbols: + +* `GTEST_API_` - Specifier for exported symbols. + +## Header `gtest-printers.h` + +* See documentation at `gtest/gtest-printers.h` for details on how to define a + custom printer. diff --git a/test/fmw/gtest/include/gtest/internal/custom/gtest-port.h b/test/fmw/gtest/include/gtest/internal/custom/gtest-port.h new file mode 100644 index 00000000000..cd85d956d2d --- /dev/null +++ b/test/fmw/gtest/include/gtest/internal/custom/gtest-port.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ diff --git a/test/fmw/gtest/include/gtest/internal/custom/gtest-printers.h b/test/fmw/gtest/include/gtest/internal/custom/gtest-printers.h new file mode 100644 index 00000000000..eb4467abcab --- /dev/null +++ b/test/fmw/gtest/include/gtest/internal/custom/gtest-printers.h @@ -0,0 +1,42 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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 file provides an injection point for custom printers in a local +// installation of gTest. +// It will be included from gtest-printers.h and the overrides in this file +// will be visible to everyone. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ diff --git a/test/fmw/gtest/include/gtest/internal/custom/gtest.h b/test/fmw/gtest/include/gtest/internal/custom/gtest.h new file mode 100644 index 00000000000..4c8e07be23f --- /dev/null +++ b/test/fmw/gtest/include/gtest/internal/custom/gtest.h @@ -0,0 +1,37 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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. +// +// Injection point for custom user configurations. See README for details +// +// ** Custom implementation starts here ** + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-death-test-internal.h b/test/fmw/gtest/include/gtest/internal/gtest-death-test-internal.h index 2b3a78f5bf8..0a9b42c8a57 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-death-test-internal.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-death-test-internal.h @@ -27,12 +27,11 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ @@ -53,6 +52,9 @@ const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test @@ -136,6 +138,8 @@ class GTEST_API_ DeathTest { GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: @@ -218,14 +222,18 @@ GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ +// NDEBUG mode. In this case we need the statements to be executed and the macro +// must accept a streamed message even though the message is never printed. +// The regex object is not evaluated, but it is used to prevent "unused" +// warnings and to avoid an expression that doesn't compile in debug mode. +#define GTEST_EXECUTE_STATEMENT_(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else if (!::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + static_cast(gtest_regex); \ + } else \ ::testing::Message() // A class representing the parsed contents of the @@ -264,53 +272,6 @@ class InternalRunDeathTestFlag { // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - #endif // GTEST_HAS_DEATH_TEST } // namespace internal diff --git a/test/fmw/gtest/include/gtest/internal/gtest-filepath.h b/test/fmw/gtest/include/gtest/internal/gtest-filepath.h index 7a13b4b0de6..ae38d95bf84 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-filepath.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-filepath.h @@ -27,21 +27,24 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Author: keith.ray@gmail.com (Keith Ray) -// // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // -// This file is #included in . +// This file is #included in gtest/internal/gtest-internal.h. // Do not include this header file separately! +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #include "gtest/internal/gtest-string.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { namespace internal { @@ -203,4 +206,6 @@ class GTEST_API_ FilePath { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-internal.h b/test/fmw/gtest/include/gtest/internal/gtest-internal.h index 0dcc3a3194f..b762f61fc53 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-internal.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-internal.h @@ -27,13 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ @@ -55,11 +55,14 @@ #include #include #include +#include #include +#include +#include #include "gtest/gtest-message.h" -#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" +#include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-type-util.h" // Due to C++ preprocessor weirdness, we need double indirection to @@ -73,6 +76,9 @@ #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar +// Stringifies its argument. +#define GTEST_STRINGIFY_(name) #name + class ProtocolMessage; namespace proto2 { class Message; } @@ -93,13 +99,9 @@ template namespace internal { struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest -// How many times InitGoogleTest() has been called. -GTEST_API_ extern int g_init_gtest_count; - // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; @@ -139,6 +141,9 @@ GTEST_API_ std::string AppendUserMessage( #if GTEST_HAS_EXCEPTIONS +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \ +/* an exported class was derived from a class that was not exported */) + // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for @@ -150,26 +155,39 @@ class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { explicit GoogleTestFailureException(const TestPartResult& failure); }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275 + #endif // GTEST_HAS_EXCEPTIONS -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); +namespace edit_distance { +// Returns the optimal edits to go from 'left' to 'right'. +// All edits cost the same, with replace having lower priority than +// add/remove. +// Simple implementation of the Wagner-Fischer algorithm. +// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm +enum EditType { kMatch, kAdd, kRemove, kReplace }; +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, const std::vector& right); - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); +// Same as above, but the input is represented as strings. +GTEST_API_ std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right); - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. +// Create a diff of the input strings in Unified diff format. +GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context = 2); + +} // namespace edit_distance + +// Calculate the diff between 'left' and 'right' and return it in unified diff +// format. +// If not null, stores in 'total_line_count' the total number of lines found +// in left + right. +GTEST_API_ std::string DiffStrings(const std::string& left, + const std::string& right, + size_t* total_line_count); // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. @@ -471,6 +489,14 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); +struct CodeLocation { + CodeLocation(const std::string& a_file, int a_line) + : file(a_file), line(a_line) {} + + std::string file; + int line; +}; + // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // @@ -482,6 +508,7 @@ typedef void (*TearDownTestCaseFunc)(); // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case @@ -493,6 +520,7 @@ GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* name, const char* type_param, const char* value_param, + CodeLocation code_location, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, @@ -505,6 +533,9 @@ GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: @@ -522,10 +553,21 @@ class GTEST_API_ TypedTestCasePState { fflush(stderr); posix::Abort(); } - defined_test_names_.insert(test_name); + registered_tests_.insert( + ::std::make_pair(test_name, CodeLocation(file, line))); return true; } + bool TestExists(const std::string& test_name) const { + return registered_tests_.count(test_name) > 0; + } + + const CodeLocation& GetCodeLocation(const std::string& test_name) const { + RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); + GTEST_CHECK_(it != registered_tests_.end()); + return it->second; + } + // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. @@ -533,10 +575,14 @@ class GTEST_API_ TypedTestCasePState { const char* file, int line, const char* registered_tests); private: + typedef ::std::map RegisteredTestsMap; + bool registered_; - ::std::set defined_test_names_; + RegisteredTestsMap registered_tests_; }; +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { @@ -555,6 +601,42 @@ inline std::string GetPrefixUntilComma(const char* str) { return comma == NULL ? str : std::string(str, comma); } +// Splits a given string on a given delimiter, populating a given +// vector with the fields. +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest); + +// The default argument to the template below for the case when the user does +// not provide a name generator. +struct DefaultNameGenerator { + template + static std::string GetName(int i) { + return StreamableToString(i); + } +}; + +template +struct NameGeneratorSelector { + typedef Provided type; +}; + +template +void GenerateNamesRecursively(Types0, std::vector*, int) {} + +template +void GenerateNamesRecursively(Types, std::vector* result, int i) { + result->push_back(NameGenerator::template GetName(i)); + GenerateNamesRecursively(typename Types::Tail(), result, + i + 1); +} + +template +std::vector GenerateNames() { + std::vector result; + GenerateNamesRecursively(Types(), &result, 0); + return result; +} + // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something @@ -569,8 +651,10 @@ class TypeParameterizedTest { // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { + static bool Register(const char* prefix, const CodeLocation& code_location, + const char* case_name, const char* test_names, int index, + const std::vector& type_names = + GenerateNames()) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; @@ -578,19 +662,23 @@ class TypeParameterizedTest { // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), - GetPrefixUntilComma(test_names).c_str(), + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + + "/" + type_names[index]) + .c_str(), + StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), NULL, // No value parameter. - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl); + code_location, GetTypeId(), TestClass::SetUpTestCase, + TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); + return TypeParameterizedTest::Register(prefix, + code_location, + case_name, + test_names, + index + 1, + type_names); } }; @@ -598,8 +686,11 @@ class TypeParameterizedTest { template class TypeParameterizedTest { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const char* /*case_name*/, const char* /*test_names*/, + int /*index*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -611,17 +702,35 @@ class TypeParameterizedTest { template class TypeParameterizedTestCase { public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { + static bool Register(const char* prefix, CodeLocation code_location, + const TypedTestCasePState* state, const char* case_name, + const char* test_names, + const std::vector& type_names = + GenerateNames()) { + std::string test_name = StripTrailingSpaces( + GetPrefixUntilComma(test_names)); + if (!state->TestExists(test_name)) { + fprintf(stderr, "Failed to get code location for test %s.%s at %s.", + case_name, test_name.c_str(), + FormatFileLocation(code_location.file.c_str(), + code_location.line).c_str()); + fflush(stderr); + posix::Abort(); + } + const CodeLocation& test_location = state->GetCodeLocation(test_name); + typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); + prefix, test_location, case_name, test_names, 0, type_names); // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); + return TypeParameterizedTestCase::Register(prefix, code_location, + state, case_name, + SkipComma(test_names), + type_names); } }; @@ -629,8 +738,11 @@ class TypeParameterizedTestCase { template class TypeParameterizedTestCase { public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { + static bool Register(const char* /*prefix*/, const CodeLocation&, + const TypedTestCasePState* /*state*/, + const char* /*case_name*/, const char* /*test_names*/, + const std::vector& = + std::vector() /*type_names*/) { return true; } }; @@ -747,31 +859,6 @@ struct RemoveConst { #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. @@ -784,7 +871,7 @@ class ImplicitlyConvertible { // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. - static From MakeFrom(); + static typename AddReference::type MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be @@ -802,25 +889,20 @@ class ImplicitlyConvertible { // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4244) // Temporarily disables warning 4244. - - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -# pragma warning(pop) // Restores the warning state. -#elif defined(__BORLANDC__) +#if defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif // __BORLANDC__ }; template const bool ImplicitlyConvertible::value; @@ -846,8 +928,11 @@ struct IsAProtocolMessage // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the +// In C++11 mode we check the existence of a const_iterator and that an +// iterator is properly implemented for the container. +// +// For pre-C++11 that we look for both C::iterator and C::const_iterator. +// The reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named @@ -857,17 +942,96 @@ struct IsAProtocolMessage // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; +#if GTEST_LANG_CXX11 +template ().begin()), + class = decltype(::std::declval().end()), + class = decltype(++::std::declval()), + class = decltype(*::std::declval()), + class = typename C::const_iterator> +IsContainer IsContainerTest(int /* dummy */) { + return 0; +} +#else template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } +#endif // GTEST_LANG_CXX11 typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } +// Trait to detect whether a type T is a hash table. +// The heuristic used is that the type contains an inner type `hasher` and does +// not contain an inner type `reverse_iterator`. +// If the container is iterable in reverse, then order might actually matter. +template +struct IsHashTable { + private: + template + static char test(typename U::hasher*, typename U::reverse_iterator*); + template + static int test(typename U::hasher*, ...); + template + static char test(...); + + public: + static const bool value = sizeof(test(0, 0)) == sizeof(int); +}; + +template +const bool IsHashTable::value; + +template +struct VoidT { + typedef void value_type; +}; + +template +struct HasValueType : false_type {}; +template +struct HasValueType > : true_type { +}; + +template (0)) == sizeof(IsContainer), + bool = HasValueType::value> +struct IsRecursiveContainerImpl; + +template +struct IsRecursiveContainerImpl : public false_type {}; + +// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to +// obey the same inconsistencies as the IsContainerTest, namely check if +// something is a container is relying on only const_iterator in C++11 and +// is relying on both const_iterator and iterator otherwise +template +struct IsRecursiveContainerImpl : public false_type {}; + +template +struct IsRecursiveContainerImpl { + #if GTEST_LANG_CXX11 + typedef typename IteratorTraits::value_type + value_type; +#else + typedef typename IteratorTraits::value_type value_type; +#endif + typedef is_same type; +}; + +// IsRecursiveContainer is a unary compile-time predicate that +// evaluates whether C is a recursive container type. A recursive container +// type is a container type whose value_type is equal to the container type +// itself. An example for a recursive container type is +// boost::filesystem::path, whose iterator has a value_type that is equal to +// boost::filesystem::path. +template +struct IsRecursiveContainer : public IsRecursiveContainerImpl::type {}; + // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add @@ -946,11 +1110,10 @@ void CopyArray(const T* from, size_t size, U* to) { // The relation between an NativeArray object (see below) and the // native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; +// We use 2 different structs to allow non-copyable types to be used, as long +// as RelationToSourceReference() is passed. +struct RelationToSourceReference {}; +struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements @@ -968,22 +1131,23 @@ class NativeArray { typedef Element* iterator; typedef const Element* const_iterator; - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); + // Constructs from a native array. References the source. + NativeArray(const Element* array, size_t count, RelationToSourceReference) { + InitRef(array, count); + } + + // Constructs from a native array. Copies the source. + NativeArray(const Element* array, size_t count, RelationToSourceCopy) { + InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - static_cast(StaticAssertTypeEqHelper()); - if (relation_to_source_ == kCopy) + if (clone_ != &NativeArray::InitRef) delete[] array_; } @@ -997,23 +1161,30 @@ class NativeArray { } private: - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } + enum { + kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< + Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value + }; + + // Initializes this object with a copy of the input. + void InitCopy(const Element* array, size_t a_size) { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; size_ = a_size; - relation_to_source_ = relation; + clone_ = &NativeArray::InitCopy; + } + + // Initializes this object with a reference of the input. + void InitRef(const Element* array, size_t a_size) { + array_ = array; + size_ = a_size; + clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; - RelationToSource relation_to_source_; + void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; @@ -1037,7 +1208,7 @@ class NativeArray { #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) -// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// Suppress MSVC warning 4702 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ @@ -1148,6 +1319,7 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, NULL, NULL, \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-linked_ptr.h b/test/fmw/gtest/include/gtest/internal/gtest-linked_ptr.h index b1362cd002c..082b87289ae 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-linked_ptr.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-linked_ptr.h @@ -27,8 +27,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: Dan Egnor (egnor@google.com) -// // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. @@ -62,9 +60,11 @@ // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// FIXME: rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ @@ -110,7 +110,12 @@ class linked_ptr_internal { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; + while (p->next_ != ptr) { + assert(p->next_ != this && + "Trying to join() a linked ring we are already in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = this; next_ = ptr; } @@ -123,7 +128,12 @@ class linked_ptr_internal { if (next_ == this) return true; linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; + while (p->next_ != this) { + assert(p->next_ != next_ && + "Trying to depart() a linked ring we are not in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } p->next_ = next_; return false; } diff --git a/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h b/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h index e80548592c7..4fac8c02703 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h @@ -30,8 +30,7 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -40,20 +39,17 @@ // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at 10. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -79,7 +75,12 @@ class ValueArray1 { explicit ValueArray1(T1 v1) : v1_(v1) {} template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + operator ParamGenerator() const { + const T array[] = {static_cast(v1_)}; + return ValuesIn(array); + } + + ValueArray1(const ValueArray1& other) : v1_(other.v1_) {} private: // No implementation - assignment is unsupported. @@ -99,6 +100,8 @@ class ValueArray2 { return ValuesIn(array); } + ValueArray2(const ValueArray2& other) : v1_(other.v1_), v2_(other.v2_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); @@ -119,6 +122,9 @@ class ValueArray3 { return ValuesIn(array); } + ValueArray3(const ValueArray3& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); @@ -141,6 +147,9 @@ class ValueArray4 { return ValuesIn(array); } + ValueArray4(const ValueArray4& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); @@ -164,6 +173,9 @@ class ValueArray5 { return ValuesIn(array); } + ValueArray5(const ValueArray5& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); @@ -190,6 +202,9 @@ class ValueArray6 { return ValuesIn(array); } + ValueArray6(const ValueArray6& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); @@ -217,6 +232,10 @@ class ValueArray7 { return ValuesIn(array); } + ValueArray7(const ValueArray7& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); @@ -246,6 +265,10 @@ class ValueArray8 { return ValuesIn(array); } + ValueArray8(const ValueArray8& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); @@ -277,6 +300,10 @@ class ValueArray9 { return ValuesIn(array); } + ValueArray9(const ValueArray9& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); @@ -309,6 +336,10 @@ class ValueArray10 { return ValuesIn(array); } + ValueArray10(const ValueArray10& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); @@ -343,6 +374,11 @@ class ValueArray11 { return ValuesIn(array); } + ValueArray11(const ValueArray11& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); @@ -379,6 +415,11 @@ class ValueArray12 { return ValuesIn(array); } + ValueArray12(const ValueArray12& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); @@ -417,6 +458,11 @@ class ValueArray13 { return ValuesIn(array); } + ValueArray13(const ValueArray13& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); @@ -456,6 +502,11 @@ class ValueArray14 { return ValuesIn(array); } + ValueArray14(const ValueArray14& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); @@ -497,6 +548,12 @@ class ValueArray15 { return ValuesIn(array); } + ValueArray15(const ValueArray15& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); @@ -541,6 +598,12 @@ class ValueArray16 { return ValuesIn(array); } + ValueArray16(const ValueArray16& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); @@ -586,6 +649,12 @@ class ValueArray17 { return ValuesIn(array); } + ValueArray17(const ValueArray17& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); @@ -633,6 +702,12 @@ class ValueArray18 { return ValuesIn(array); } + ValueArray18(const ValueArray18& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); @@ -681,6 +756,13 @@ class ValueArray19 { return ValuesIn(array); } + ValueArray19(const ValueArray19& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); @@ -731,6 +813,13 @@ class ValueArray20 { return ValuesIn(array); } + ValueArray20(const ValueArray20& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); @@ -784,6 +873,13 @@ class ValueArray21 { return ValuesIn(array); } + ValueArray21(const ValueArray21& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); @@ -838,6 +934,13 @@ class ValueArray22 { return ValuesIn(array); } + ValueArray22(const ValueArray22& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); @@ -894,6 +997,14 @@ class ValueArray23 { return ValuesIn(array); } + ValueArray23(const ValueArray23& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); @@ -952,6 +1063,14 @@ class ValueArray24 { return ValuesIn(array); } + ValueArray24(const ValueArray24& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); @@ -1011,6 +1130,14 @@ class ValueArray25 { return ValuesIn(array); } + ValueArray25(const ValueArray25& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); @@ -1072,6 +1199,14 @@ class ValueArray26 { return ValuesIn(array); } + ValueArray26(const ValueArray26& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); @@ -1136,6 +1271,15 @@ class ValueArray27 { return ValuesIn(array); } + ValueArray27(const ValueArray27& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); @@ -1201,6 +1345,15 @@ class ValueArray28 { return ValuesIn(array); } + ValueArray28(const ValueArray28& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); @@ -1267,6 +1420,15 @@ class ValueArray29 { return ValuesIn(array); } + ValueArray29(const ValueArray29& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); @@ -1336,6 +1498,15 @@ class ValueArray30 { return ValuesIn(array); } + ValueArray30(const ValueArray30& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); @@ -1407,6 +1578,16 @@ class ValueArray31 { return ValuesIn(array); } + ValueArray31(const ValueArray31& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); @@ -1479,6 +1660,16 @@ class ValueArray32 { return ValuesIn(array); } + ValueArray32(const ValueArray32& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); @@ -1554,6 +1745,16 @@ class ValueArray33 { return ValuesIn(array); } + ValueArray33(const ValueArray33& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); @@ -1630,6 +1831,16 @@ class ValueArray34 { return ValuesIn(array); } + ValueArray34(const ValueArray34& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); @@ -1707,6 +1918,17 @@ class ValueArray35 { return ValuesIn(array); } + ValueArray35(const ValueArray35& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); @@ -1787,6 +2009,17 @@ class ValueArray36 { return ValuesIn(array); } + ValueArray36(const ValueArray36& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); @@ -1869,6 +2102,17 @@ class ValueArray37 { return ValuesIn(array); } + ValueArray37(const ValueArray37& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); @@ -1952,6 +2196,17 @@ class ValueArray38 { return ValuesIn(array); } + ValueArray38(const ValueArray38& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); @@ -2037,6 +2292,18 @@ class ValueArray39 { return ValuesIn(array); } + ValueArray39(const ValueArray39& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); @@ -2124,6 +2391,18 @@ class ValueArray40 { return ValuesIn(array); } + ValueArray40(const ValueArray40& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); @@ -2213,6 +2492,18 @@ class ValueArray41 { return ValuesIn(array); } + ValueArray41(const ValueArray41& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); @@ -2304,6 +2595,18 @@ class ValueArray42 { return ValuesIn(array); } + ValueArray42(const ValueArray42& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); @@ -2396,6 +2699,19 @@ class ValueArray43 { return ValuesIn(array); } + ValueArray43(const ValueArray43& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); @@ -2490,6 +2806,19 @@ class ValueArray44 { return ValuesIn(array); } + ValueArray44(const ValueArray44& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); @@ -2586,6 +2915,19 @@ class ValueArray45 { return ValuesIn(array); } + ValueArray45(const ValueArray45& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); @@ -2684,6 +3026,19 @@ class ValueArray46 { return ValuesIn(array); } + ValueArray46(const ValueArray46& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); @@ -2784,6 +3139,20 @@ class ValueArray47 { return ValuesIn(array); } + ValueArray47(const ValueArray47& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); @@ -2886,6 +3255,20 @@ class ValueArray48 { return ValuesIn(array); } + ValueArray48(const ValueArray48& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); @@ -2989,6 +3372,20 @@ class ValueArray49 { return ValuesIn(array); } + ValueArray49(const ValueArray49& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); @@ -3093,6 +3490,20 @@ class ValueArray50 { return ValuesIn(array); } + ValueArray50(const ValueArray50& other) : v1_(other.v1_), v2_(other.v2_), + v3_(other.v3_), v4_(other.v4_), v5_(other.v5_), v6_(other.v6_), + v7_(other.v7_), v8_(other.v8_), v9_(other.v9_), v10_(other.v10_), + v11_(other.v11_), v12_(other.v12_), v13_(other.v13_), v14_(other.v14_), + v15_(other.v15_), v16_(other.v16_), v17_(other.v17_), v18_(other.v18_), + v19_(other.v19_), v20_(other.v20_), v21_(other.v21_), v22_(other.v22_), + v23_(other.v23_), v24_(other.v24_), v25_(other.v25_), v26_(other.v26_), + v27_(other.v27_), v28_(other.v28_), v29_(other.v29_), v30_(other.v30_), + v31_(other.v31_), v32_(other.v32_), v33_(other.v33_), v34_(other.v34_), + v35_(other.v35_), v36_(other.v36_), v37_(other.v37_), v38_(other.v38_), + v39_(other.v39_), v40_(other.v40_), v41_(other.v41_), v42_(other.v42_), + v43_(other.v43_), v44_(other.v44_), v45_(other.v45_), v46_(other.v46_), + v47_(other.v47_), v48_(other.v48_), v49_(other.v49_), v50_(other.v50_) {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); @@ -3157,9 +3568,9 @@ class ValueArray50 { // template class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) @@ -3205,7 +3616,7 @@ class CartesianProductGenerator2 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3237,7 +3648,7 @@ class CartesianProductGenerator2 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); + current_value_.reset(new ParamType(*current1_, *current2_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3259,7 +3670,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -3272,9 +3683,9 @@ class CartesianProductGenerator2 template class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) @@ -3328,7 +3739,7 @@ class CartesianProductGenerator3 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3364,7 +3775,7 @@ class CartesianProductGenerator3 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3390,7 +3801,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -3404,9 +3815,9 @@ class CartesianProductGenerator3 template class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3469,7 +3880,7 @@ class CartesianProductGenerator4 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3509,8 +3920,8 @@ class CartesianProductGenerator4 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3540,7 +3951,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -3555,9 +3966,9 @@ class CartesianProductGenerator4 template class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { + : public ParamGeneratorInterface< ::testing::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3627,7 +4038,7 @@ class CartesianProductGenerator5 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3671,8 +4082,8 @@ class CartesianProductGenerator5 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3706,7 +4117,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -3723,10 +4134,10 @@ class CartesianProductGenerator5 template class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3804,7 +4215,7 @@ class CartesianProductGenerator6 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -3852,8 +4263,8 @@ class CartesianProductGenerator6 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -3891,7 +4302,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -3909,10 +4320,10 @@ class CartesianProductGenerator6 template class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -3998,7 +4409,7 @@ class CartesianProductGenerator7 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4050,8 +4461,8 @@ class CartesianProductGenerator7 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4093,7 +4504,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -4112,10 +4523,10 @@ class CartesianProductGenerator7 template class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4211,7 +4622,7 @@ class CartesianProductGenerator8 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4267,8 +4678,8 @@ class CartesianProductGenerator8 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4314,7 +4725,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -4334,10 +4745,10 @@ class CartesianProductGenerator8 template class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4440,7 +4851,7 @@ class CartesianProductGenerator9 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4500,9 +4911,9 @@ class CartesianProductGenerator9 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); + *current9_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4552,7 +4963,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -4573,10 +4984,10 @@ class CartesianProductGenerator9 template class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { public: - typedef ::std::tr1::tuple ParamType; + typedef ::testing::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, @@ -4687,7 +5098,7 @@ class CartesianProductGenerator10 virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -4751,9 +5162,9 @@ class CartesianProductGenerator10 void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, + current_value_.reset(new ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); + *current9_, *current10_)); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -4807,7 +5218,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. @@ -4838,8 +5249,8 @@ class CartesianProductHolder2 { CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); @@ -4860,8 +5271,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), @@ -4885,8 +5296,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), @@ -4912,8 +5323,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), @@ -4943,8 +5354,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), @@ -4976,9 +5387,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2, : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), @@ -5014,9 +5425,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2, g8_(g8) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), @@ -5055,9 +5466,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2, g9_(g9) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), @@ -5099,10 +5510,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, g9_(g9), g10_(g10) {} template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( + operator ParamGenerator< ::testing::tuple >() const { + return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator10( static_cast >(g1_), @@ -5138,6 +5549,4 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2, } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h.pump b/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h.pump index 009206fd319..30dffe43c3c 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/test/fmw/gtest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -29,8 +29,7 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -39,20 +38,17 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // and at most $maxtuple arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is +// by the maximum arity of the implementation of tuple which is // currently set at $maxtuple. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { // Forward declarations of ValuesIn(), which is implemented in @@ -72,29 +68,14 @@ internal::ParamGenerator ValuesIn( namespace internal { // Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -$range i 2..n +$range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: - ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} + $if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { @@ -102,6 +83,8 @@ class ValueArray$i { return ValuesIn(array); } + ValueArray$i(const ValueArray$i& other) : $for j, [[v$(j)_(other.v$(j)_)]] {} + private: // No implementation - assignment is unsupported. void operator=(const ValueArray$i& other); @@ -128,9 +111,9 @@ $range k 2..i template <$for j, [[typename T$j]]> class CartesianProductGenerator$i - : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > { + : public ParamGeneratorInterface< ::testing::tuple<$for j, [[T$j]]> > { public: - typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType; + typedef ::testing::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} @@ -180,7 +163,7 @@ $for k [[ virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } - virtual const ParamType* Current() const { return ¤t_value_; } + virtual const ParamType* Current() const { return current_value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. @@ -212,7 +195,7 @@ $for k [[ void ComputeCurrentValue() { if (!AtEnd()) - current_value_ = ParamType($for j, [[*current$(j)_]]); + current_value_.reset(new ParamType($for j, [[*current$(j)_]])); } bool AtEnd() const { // We must report iterator past the end of the range when either of the @@ -237,7 +220,7 @@ $for j [[ typename ParamGenerator::iterator current$(j)_; ]] - ParamType current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. @@ -269,8 +252,8 @@ class CartesianProductHolder$i { CartesianProductHolder$i($for j, [[const Generator$j& g$j]]) : $for j, [[g$(j)_(g$j)]] {} template <$for j, [[typename T$j]]> - operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const { - return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >( + operator ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >() const { + return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ @@ -296,6 +279,4 @@ $for j [[ } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-param-util.h b/test/fmw/gtest/include/gtest/internal/gtest-param-util.h index d5e1028b0c1..d64f620c4c6 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-param-util.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-param-util.h @@ -26,29 +26,49 @@ // 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. -// -// Author: vladl@google.com (Vlad Losev) + // Type and function utilities for implementing parameterized tests. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#include + #include +#include #include #include -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" -#if GTEST_HAS_PARAM_TEST - namespace testing { + +// Input to a parameterized test name generator, describing a test parameter. +// Consists of the parameter value and the integer parameter index. +template +struct TestParamInfo { + TestParamInfo(const ParamType& a_param, size_t an_index) : + param(a_param), + index(an_index) {} + ParamType param; + size_t index; +}; + +// A builtin parameterized test name generator which returns the result of +// testing::PrintToString. +struct PrintToStringParamName { + template + std::string operator()(const TestParamInfo& info) const { + return PrintToString(info.param); + } +}; + namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. @@ -58,7 +78,7 @@ namespace internal { // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); + CodeLocation code_location); template class ParamGeneratorInterface; template class ParamGenerator; @@ -206,7 +226,7 @@ class RangeGenerator : public ParamGeneratorInterface { return base_; } virtual void Advance() { - value_ = value_ + step_; + value_ = static_cast(value_ + step_); index_++; } virtual ParamIteratorInterface* Clone() const { @@ -243,7 +263,7 @@ class RangeGenerator : public ParamGeneratorInterface { const T& end, const IncrementT& step) { int end_index = 0; - for (T i = begin; i < end; i = i + step) + for (T i = begin; i < end; i = static_cast(i + step)) end_index++; return end_index; } @@ -345,6 +365,37 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { const ContainerType container_; }; // class ValuesInIteratorRangeGenerator +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Default parameterized test name generator, returns a string containing the +// integer test parameter index. +template +std::string DefaultParamName(const TestParamInfo& info) { + Message name_stream; + name_stream << info.index; + return name_stream.GetString(); +} + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Parameterized test name overload helpers, which help the +// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized +// test name generator and user param name generator. +template +ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) { + return func; +} + +template +struct ParamNameGenFunc { + typedef std::string Type(const TestParamInfo&); +}; + +template +typename ParamNameGenFunc::Type *GetParamNameGen() { + return DefaultParamName; +} + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that @@ -417,7 +468,7 @@ class ParameterizedTestCaseInfoBase { virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; + virtual const std::string& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this @@ -449,12 +500,14 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); + typedef typename ParamNameGenFunc::Type ParamNameGeneratorFunc; - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} + explicit ParameterizedTestCaseInfo( + const char* name, CodeLocation code_location) + : test_case_name_(name), code_location_(code_location) {} // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } + virtual const std::string& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information @@ -472,11 +525,12 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, + int AddTestCaseInstantiation(const std::string& instantiation_name, GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); + ParamNameGeneratorFunc* name_func, + const char* file, int line) { + instantiations_.push_back( + InstantiationInfo(instantiation_name, func, name_func, file, line)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case @@ -491,25 +545,45 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); + const std::string& instantiation_name = gen_it->name; + ParamGenerator generator((*gen_it->generator)()); + ParamNameGeneratorFunc* name_func = gen_it->name_func; + const char* file = gen_it->file; + int line = gen_it->line; - string test_case_name; + std::string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; - int i = 0; + size_t i = 0; + std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; + + std::string param_name = name_func( + TestParamInfo(*param_it, i)); + + GTEST_CHECK_(IsValidParamName(param_name)) + << "Parameterized test name '" << param_name + << "' is invalid, in " << file + << " line " << line << std::endl; + + GTEST_CHECK_(test_param_names.count(param_name) == 0) + << "Duplicate parameterized test name '" << param_name + << "', in " << file << " line " << line << std::endl; + + test_param_names.insert(param_name); + + test_name_stream << test_info->test_base_name << "/" << param_name; MakeAndRegisterTestInfo( test_case_name.c_str(), test_name_stream.GetString().c_str(), NULL, // No type parameter. PrintToString(*param_it).c_str(), + code_location_, GetTestCaseTypeId(), TestCase::SetUpTestCase, TestCase::TearDownTestCase, @@ -530,17 +604,50 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} - const string test_case_base_name; - const string test_base_name; + const std::string test_case_base_name; + const std::string test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; + // Records data received from INSTANTIATE_TEST_CASE_P macros: + // + struct InstantiationInfo { + InstantiationInfo(const std::string &name_in, + GeneratorCreationFunc* generator_in, + ParamNameGeneratorFunc* name_func_in, + const char* file_in, + int line_in) + : name(name_in), + generator(generator_in), + name_func(name_func_in), + file(file_in), + line(line_in) {} - const string test_case_name_; + std::string name; + GeneratorCreationFunc* generator; + ParamNameGeneratorFunc* name_func; + const char* file; + int line; + }; + typedef ::std::vector InstantiationContainer; + + static bool IsValidParamName(const std::string& name) { + // Check for empty string + if (name.empty()) + return false; + + // Check for invalid characters + for (std::string::size_type index = 0; index < name.size(); ++index) { + if (!isalnum(name[index]) && name[index] != '_') + return false; + } + + return true; + } + + const std::string test_case_name_; + CodeLocation code_location_; TestInfoContainer tests_; InstantiationContainer instantiations_; @@ -568,8 +675,7 @@ class ParameterizedTestCaseRegistry { template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, - const char* file, - int line) { + CodeLocation code_location) { ParameterizedTestCaseInfo* typed_test_info = NULL; for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { @@ -578,7 +684,7 @@ class ParameterizedTestCaseRegistry { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); + ReportInvalidTestCaseType(test_case_name, code_location); posix::Abort(); } else { // At this point we are sure that the object we found is of the same @@ -591,7 +697,8 @@ class ParameterizedTestCaseRegistry { } } if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + typed_test_info = new ParameterizedTestCaseInfo( + test_case_name, code_location); test_case_infos_.push_back(typed_test_info); } return typed_test_info; @@ -614,6 +721,4 @@ class ParameterizedTestCaseRegistry { } // namespace internal } // namespace testing -#endif // GTEST_HAS_PARAM_TEST - #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-port-arch.h b/test/fmw/gtest/include/gtest/internal/gtest-port-arch.h new file mode 100644 index 00000000000..f83700e06d9 --- /dev/null +++ b/test/fmw/gtest/include/gtest/internal/gtest-port-arch.h @@ -0,0 +1,100 @@ +// Copyright 2015, Google Inc. +// 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 Google Inc. 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. +// +// The Google C++ Testing and Mocking Framework (Google Test) +// +// This header file defines the GTEST_OS_* macro. +// It is separate from gtest-port.h so that custom/gtest-port.h can include it. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# elif defined(WINAPI_FAMILY) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define GTEST_OS_WINDOWS_DESKTOP 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +# define GTEST_OS_WINDOWS_PHONE 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +# define GTEST_OS_WINDOWS_RT 1 +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE) +# define GTEST_OS_WINDOWS_PHONE 1 +# define GTEST_OS_WINDOWS_TV_TITLE 1 +# else + // WINAPI_FAMILY defined but no known partition matched. + // Default to desktop. +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# endif +#elif defined __FreeBSD__ +# define GTEST_OS_FREEBSD 1 +#elif defined __Fuchsia__ +# define GTEST_OS_FUCHSIA 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __NetBSD__ +# define GTEST_OS_NETBSD 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#endif // __CYGWIN__ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-port.h b/test/fmw/gtest/include/gtest/internal/gtest-port.h index b772f4bed77..49d3f7580d7 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-port.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-port.h @@ -27,33 +27,55 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan) -// // Low-level types and utilities for porting Google Test to various -// platforms. They are subject to change without notice. DO NOT USE -// THEM IN USER CODE. +// platforms. All macros ending with _ and symbols defined in an +// internal namespace are subject to change without notice. Code +// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't +// end with _ are part of Google Test's public API and can be used by +// code outside Google Test. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -// The user can define the following macros in the build script to -// control Google Test's behavior. If the user doesn't define a macro -// in this list, Google Test will define it. +// Environment-describing macros +// ----------------------------- +// +// Google Test can be used in many different environments. Macros in +// this section tell Google Test what kind of environment it is being +// used in, such that Google Test can provide environment-specific +// features and implementations. +// +// Google Test tries to automatically detect the properties of its +// environment, so users usually don't need to worry about these +// macros. However, the automatic detection is not perfect. +// Sometimes it's necessary for a user to define some of the following +// macros in the build script to override Google Test's decisions. +// +// If the user doesn't define a macro in the list, Google Test will +// provide a default definition. After this header is #included, all +// macros in this list will be defined to either 1 or 0. +// +// Notes to maintainers: +// - Each macro here is a user-tweakable knob; do not grow the list +// lightly. +// - Use #if to key off these macros. Don't use #ifdef or "#if +// defined(...)", which will not work as these macros are ALWAYS +// defined. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). +// is/isn't available +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring +// is/isn't available // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that @@ -85,20 +107,33 @@ // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. +// GTEST_DEFAULT_DEATH_TEST_STYLE +// - The default value of --gtest_death_test_style. +// The legacy default has been "fast" in the open +// source version since 2008. The recommended value +// is "threadsafe", and can be set in +// custom/gtest-port.h. -// This header defines the following utilities: +// Platform-indicating macros +// -------------------------- +// +// Macros indicating the platform on which Google Test is being used +// (a macro is defined to 1 if compiled on the given platform; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. // -// Macros indicating the current platform (defined to 1 if compiled on -// the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_FREEBSD - FreeBSD +// GTEST_OS_FUCHSIA - Fuchsia // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS -// GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_NETBSD - NetBSD // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris @@ -107,6 +142,8 @@ // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_WINDOWS_PHONE - Windows Phone +// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the @@ -116,22 +153,50 @@ // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // -// Note that it is possible that none of the GTEST_OS_* macros are defined. +// It is possible that none of the GTEST_OS_* macros are defined. + +// Feature-indicating macros +// ------------------------- +// +// Macros indicating which Google Test features are available (a macro +// is defined to 1 if the corresponding feature is supported; +// otherwise UNDEFINED -- it's never defined to 0.). Google Test +// defines these macros automatically. Code outside Google Test MUST +// NOT define them. +// +// These macros are public so that portable tests can be written. +// Such tests typically surround code using a feature with an #if +// which controls that code. For example: +// +// #if GTEST_HAS_DEATH_TEST +// EXPECT_DEATH(DoSomethingDeadly()); +// #endif // -// Macros indicating available Google Test features (defined to 1 if -// the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_IS_THREADSAFE - Google Test is thread-safe. +// GOOGLETEST_CM0007 DO NOT DELETE // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. +// the above RE\b(s) are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). + +// Misc public macros +// ------------------ +// +// GTEST_FLAG(flag_name) - references the variable corresponding to +// the given Google Test flag. + +// Internal utilities +// ------------------ +// +// The following macros and utilities are for Google Test's INTERNAL +// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. @@ -140,13 +205,19 @@ // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is +// suppressed (constant conditional). +// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 +// is suppressed. +// +// C++11 feature wrappers: +// +// testing::internal::forward - portability wrapper for std::forward. +// testing::internal::move - portability wrapper for std::move. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above -// synchronization primitives have real implementations -// and Google Test is thread-safe; or 0 otherwise. +// - synchronization primitives. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. @@ -158,10 +229,10 @@ // // Regular expressions: // RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// +// Extended Regular Expression syntax on UNIX-like platforms +// GOOGLETEST_CM0008 DO NOT DELETE +// or a reduced regular exception syntax on other +// platforms, including Windows. // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. @@ -182,7 +253,6 @@ // BiggestInt - the biggest signed integer type. // // Command-line utilities: -// GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. @@ -201,23 +271,44 @@ #ifndef _WIN32_WCE # include # include -#endif // !_WIN32_WCE +#elif _WIN32_WCE >= 0x800 // Windows Embedded Compact 2013 +// Forward declare instead of including / / +typedef wchar_t WCHAR; +typedef WCHAR *PWCHAR, *LPWCH, *PWCH; +typedef const WCHAR *LPCWCH, *PCWCH; +typedef __readableTo(sentinel(0)) const WCHAR *LPCWSTR, *PCWSTR; +typedef const WCHAR *LPCWCHAR, *PCWCHAR; +#endif #if defined __APPLE__ # include # include #endif +// Brings in the definition of HAS_GLOBAL_STRING. This must be done +// BEFORE we test HAS_GLOBAL_STRING. +#include // NOLINT +#include // NOLINT #include // NOLINT #include // NOLINT -#include // NOLINT +#include +#include // NOLINT -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" +#include "gtest/internal/gtest-port-arch.h" +#include "gtest/internal/custom/gtest-port.h" + +#if !defined(GTEST_DEV_EMAIL_) +# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +# define GTEST_FLAG_PREFIX_ "gtest_" +# define GTEST_FLAG_PREFIX_DASH_ "gtest-" +# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +# define GTEST_NAME_ "Google Test" +# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/" +#endif // !defined(GTEST_DEV_EMAIL_) + +#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) +# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" +#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ @@ -226,55 +317,45 @@ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE -#elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# if TARGET_IPHONE_SIMULATOR -# define GTEST_OS_IOS_SIMULATOR 1 -# endif -# endif -#elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif -#elif defined __MVS__ -# define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -# define GTEST_OS_AIX 1 -#elif defined(__hpux) -# define GTEST_OS_HPUX 1 -#elif defined __native_client__ -# define GTEST_OS_NACL 1 -#elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 -#elif defined __QNX__ -# define GTEST_OS_QNX 1 -#endif // __CYGWIN__ +// Macros for disabling Microsoft Visual C++ warnings. +// +// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) +// /* code that triggers warnings C4800 and C4385 */ +// GTEST_DISABLE_MSC_WARNINGS_POP_() +#if _MSC_VER >= 1400 +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ + __pragma(warning(push)) \ + __pragma(warning(disable: warnings)) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() \ + __pragma(warning(pop)) +#else +// Older versions of MSVC don't have __pragma. +# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) +# define GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif + +// Clang on Windows does not understand MSVC's pragma warning. +// We need clang-specific way to disable function deprecation warning. +#ifdef __clang__ +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \ + _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"") +#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + _Pragma("clang diagnostic pop") +#else +# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) +# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() +#endif #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L +# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L || _MSC_VER >= 1900 // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else @@ -282,19 +363,95 @@ # endif #endif +// Distinct from C++11 language support, some environments don't provide +// proper C++11 library support. Notably, it's possible to build in +// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++ +// with no C++11 support. +// +// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__ +// 20110325, but maintenance releases in the 4.4 and 4.5 series followed +// this date, so check for those versions by their date stamps. +// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning +#if GTEST_LANG_CXX11 && \ + (!defined(__GLIBCXX__) || ( \ + __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \ + /* Blacklist of patch releases of older branches: */ \ + __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \ + __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \ + __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \ + __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */ +# define GTEST_STDLIB_CXX11 1 +#endif + +// Only use C++11 library features if the library provides them. +#if GTEST_STDLIB_CXX11 +# define GTEST_HAS_STD_BEGIN_AND_END_ 1 +# define GTEST_HAS_STD_FORWARD_LIST_ 1 +# if !defined(_MSC_VER) || (_MSC_FULL_VER >= 190023824) +// works only with VS2015U2 and better +# define GTEST_HAS_STD_FUNCTION_ 1 +# endif +# define GTEST_HAS_STD_INITIALIZER_LIST_ 1 +# define GTEST_HAS_STD_MOVE_ 1 +# define GTEST_HAS_STD_UNIQUE_PTR_ 1 +# define GTEST_HAS_STD_SHARED_PTR_ 1 +# define GTEST_HAS_UNORDERED_MAP_ 1 +# define GTEST_HAS_UNORDERED_SET_ 1 +#endif + +// C++11 specifies that provides std::tuple. +// Some platforms still might not have it, however. +#if GTEST_LANG_CXX11 +# define GTEST_HAS_STD_TUPLE_ 1 +# if defined(__clang__) +// Inspired by +// https://clang.llvm.org/docs/LanguageExtensions.html#include-file-checking-macros +# if defined(__has_include) && !__has_include() +# undef GTEST_HAS_STD_TUPLE_ +# endif +# elif defined(_MSC_VER) +// Inspired by boost/config/stdlib/dinkumware.hpp +# if defined(_CPPLIB_VER) && _CPPLIB_VER < 520 +# undef GTEST_HAS_STD_TUPLE_ +# endif +# elif defined(__GLIBCXX__) +// Inspired by boost/config/stdlib/libstdcpp3.hpp, +// http://gcc.gnu.org/gcc-4.2/changes.html and +// https://web.archive.org/web/20140227044429/gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) +# undef GTEST_HAS_STD_TUPLE_ +# endif +# endif +#endif + // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. -#if !GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS_MOBILE +# include +# include +# endif +// In order to avoid having to include , use forward declaration +#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR) +// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two +// separate (equivalent) structs, instead of using typedef +typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#elif _WIN32_WCE >= 0x800 +typedef struct CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#else +// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. +// This assumption is verified by +// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. +typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; +#endif +#else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include -#elif !GTEST_OS_WINDOWS_MOBILE -# include -# include -#endif +#endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. @@ -311,7 +468,10 @@ # endif #endif -#if GTEST_HAS_POSIX_RE +#if GTEST_USES_PCRE +// The appropriate headers have already been included. + +#elif GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already @@ -333,19 +493,31 @@ // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 -#endif // GTEST_HAS_POSIX_RE +#endif // GTEST_USES_PCRE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +# if defined(_MSC_VER) && defined(_CPPUNWIND) +// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__BORLANDC__) +// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__clang__) +// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714, +// but iff cleanups are enabled after that. In Obj-C++ files, there can be +// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions +// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++ +// exceptions starting at clang r206352, but which checked for cleanups prior to +// that. To reliably check for C++ exception availability with clang, check for +// __EXCEPTIONS && __has_feature(cxx_exceptions). +# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions)) # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 @@ -374,21 +546,17 @@ # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." +# error "::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - # define GTEST_HAS_GLOBAL_STRING 0 - #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// FIXME: uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. @@ -471,13 +639,14 @@ // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we assume pthreads support is -// available on Linux and Mac. +// The user didn't tell us explicitly, so we make reasonable assumptions about +// which platforms have pthreads support. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX) +#define GTEST_HAS_PTHREAD \ + (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \ + GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD @@ -489,6 +658,15 @@ # include // NOLINT #endif +// Determines if hash_map/hash_set are available. +// Only used for testing against those containers. +#if !defined(GTEST_HAS_HASH_MAP_) +# if defined(_MSC_VER) && (_MSC_VER < 1900) +# define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. +# define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. +# endif // _MSC_VER +#endif // !defined(GTEST_HAS_HASH_MAP_) + // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). @@ -496,6 +674,14 @@ # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 +# elif defined(_MSC_VER) && (_MSC_VER >= 1910) +// Prevent `warning C4996: 'std::tr1': warning STL4002: +// The non-Standard std::tr1 namespace and TR1-only machinery +// are deprecated and will be REMOVED.` +# define GTEST_HAS_TR1_TUPLE 0 +# elif GTEST_LANG_CXX11 && defined(_LIBCPP_VERSION) +// libc++ doesn't support TR1. +# define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 @@ -505,6 +691,10 @@ // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE +// We use our own tuple implementation on Symbian. +# if GTEST_OS_SYMBIAN +# define GTEST_USE_OWN_TR1_TUPLE 1 +# else // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an @@ -518,7 +708,8 @@ // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 + && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) \ + || (_MSC_VER >= 1600 && _MSC_VER < 1900) # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif @@ -534,32 +725,25 @@ # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif - +# endif // GTEST_OS_SYMBIAN #endif // GTEST_USE_OWN_TR1_TUPLE -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. +// To avoid conditional compilation we make it gtest-port.h's responsibility +// to #include the header implementing tuple. +#if GTEST_HAS_STD_TUPLE_ +# include // IWYU pragma: export +# define GTEST_TUPLE_NAMESPACE_ ::std +#endif // GTEST_HAS_STD_TUPLE_ + +// We include tr1::tuple even if std::tuple is available to define printers for +// them. #if GTEST_HAS_TR1_TUPLE +# ifndef GTEST_TUPLE_NAMESPACE_ +# define GTEST_TUPLE_NAMESPACE_ ::std::tr1 +# endif // GTEST_TUPLE_NAMESPACE_ # if GTEST_USE_OWN_TR1_TUPLE -# include "gtest/internal/gtest-tuple.h" -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - +# include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to @@ -574,7 +758,7 @@ using ::std::tuple_size; // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include +# include // IWYU pragma: export // NOLINT # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does @@ -584,20 +768,22 @@ using ::std::tuple_size; // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent +// . Hence the following #define is used to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. + // if they choose to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -# include // NOLINT +// VS 2010 now has tr1 support. +# elif _MSC_VER >= 1600 +# include // IWYU pragma: export // NOLINT + +# else // GTEST_USE_OWN_TR1_TUPLE +# include // IWYU pragma: export // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE @@ -611,8 +797,12 @@ using ::std::tuple_size; # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 +// On Android, clone() became available at different API levels for each 32-bit +// architecture. +# if defined(__LP64__) || \ + (defined(__arm__) && __ANDROID_API__ >= 9) || \ + (defined(__mips__) && __ANDROID_API__ >= 12) || \ + (defined(__i386__) && __ANDROID_API__ >= 17) # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 @@ -631,7 +821,8 @@ using ::std::tuple_size; #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ + GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 @@ -642,20 +833,15 @@ using ::std::tuple_size; // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX) + GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \ + GTEST_OS_NETBSD || GTEST_OS_FUCHSIA) # define GTEST_HAS_DEATH_TEST 1 -# include // NOLINT #endif -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, @@ -670,7 +856,7 @@ using ::std::tuple_size; // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +#if (GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_) && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif @@ -712,19 +898,48 @@ using ::std::tuple_size; // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else +#elif defined(__clang__) +# if __has_attribute(unused) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +# endif +#endif +#ifndef GTEST_ATTRIBUTE_UNUSED_ # define GTEST_ATTRIBUTE_UNUSED_ #endif +#if GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ = delete +#else // GTEST_LANG_CXX11 +# define GTEST_CXX11_EQUALS_DELETE_ +#endif // GTEST_LANG_CXX11 + +// Use this annotation before a function that takes a printf format string. +#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC) +# if defined(__MINGW_PRINTF_FORMAT) +// MinGW has two different printf implementations. Ensure the format macro +// matches the selected implementation. See +// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/. +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \ + first_to_check))) +# else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \ + __attribute__((__format__(__printf__, string_index, first_to_check))) +# endif +#else +# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) +#endif + + // A macro to disallow operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) +#define GTEST_DISALLOW_ASSIGN_(type) \ + void operator=(type const &) GTEST_CXX11_EQUALS_DELETE_ // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \ + type(type const &) GTEST_CXX11_EQUALS_DELETE_; \ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared @@ -738,6 +953,19 @@ using ::std::tuple_size; # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC +// MS C++ compiler emits warning when a conditional expression is compile time +// constant. In some contexts this warning is false positive and needs to be +// suppressed. Use the following two macros in such cases: +// +// GTEST_INTENTIONAL_CONST_COND_PUSH_() +// while (true) { +// GTEST_INTENTIONAL_CONST_COND_POP_() +// } +# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) +# define GTEST_INTENTIONAL_CONST_COND_POP_() \ + GTEST_DISABLE_MSC_WARNINGS_POP_() + // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. @@ -752,21 +980,37 @@ using ::std::tuple_size; # define GTEST_HAS_SEH 0 # endif +#define GTEST_IS_THREADSAFE \ + (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \ + || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ + || GTEST_HAS_PTHREAD) + #endif // GTEST_HAS_SEH -#ifdef _MSC_VER +// GTEST_API_ qualifies all symbols that must be exported. The definitions below +// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in +// gtest/internal/custom/gtest-port.h +#ifndef GTEST_API_ +#ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif - +#elif __GNUC__ >= 4 || defined(__clang__) +# define GTEST_API_ __attribute__((visibility ("default"))) #endif // _MSC_VER +#endif // GTEST_API_ + #ifndef GTEST_API_ # define GTEST_API_ -#endif +#endif // GTEST_API_ + +#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE +# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast" +#endif // GTEST_DEFAULT_DEATH_TEST_STYLE #ifdef __GNUC__ // Ask the compiler to never inline a given function. @@ -776,16 +1020,66 @@ using ::std::tuple_size; #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 +#if !defined(GTEST_HAS_CXXABI_H_) +# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER)) +# define GTEST_HAS_CXXABI_H_ 1 +# else +# define GTEST_HAS_CXXABI_H_ 0 +# endif #endif +// A function level attribute to disable checking for use of uninitialized +// memory when built with MemorySanitizer. +#if defined(__clang__) +# if __has_feature(memory_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ + __attribute__((no_sanitize_memory)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +# endif // __has_feature(memory_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +#endif // __clang__ + +// A function level attribute to disable AddressSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(address_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ + __attribute__((no_sanitize_address)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +# endif // __has_feature(address_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +#endif // __clang__ + +// A function level attribute to disable ThreadSanitizer instrumentation. +#if defined(__clang__) +# if __has_feature(thread_sanitizer) +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ + __attribute__((no_sanitize_thread)) +# else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +# endif // __has_feature(thread_sanitizer) +#else +# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +#endif // __clang__ + namespace testing { class Message; +#if defined(GTEST_TUPLE_NAMESPACE_) +// Import tuple and friends into the ::testing namespace. +// It is part of our interface, having them in ::testing allows us to change +// their types as needed. +using GTEST_TUPLE_NAMESPACE_::get; +using GTEST_TUPLE_NAMESPACE_::make_tuple; +using GTEST_TUPLE_NAMESPACE_::tuple; +using GTEST_TUPLE_NAMESPACE_::tuple_size; +using GTEST_TUPLE_NAMESPACE_::tuple_element; +#endif // defined(GTEST_TUPLE_NAMESPACE_) + namespace internal { // A secret type that Google Test users don't know about. It has no @@ -797,8 +1091,8 @@ class Secret; // expression is true. For example, you could use it to verify the // size of a static array: // -// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); +// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, +// names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // @@ -808,16 +1102,22 @@ class Secret; // the expression is false, most compilers will issue a warning/error // containing the name of the variable. +#if GTEST_LANG_CXX11 +# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) +#else // !GTEST_LANG_CXX11 template -struct CompileAssert { + struct CompileAssert { }; -#define GTEST_COMPILE_ASSERT_(expr, msg) \ +# define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ +#endif // !GTEST_LANG_CXX11 // Implementation details of GTEST_COMPILE_ASSERT_: // +// (In C++11, we simply use static_assert instead of the following) +// // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // @@ -864,7 +1164,22 @@ template struct StaticAssertTypeEqHelper; template -struct StaticAssertTypeEqHelper {}; +struct StaticAssertTypeEqHelper { + enum { value = true }; +}; + +// Same as std::is_same<>. +template +struct IsSame { + enum { value = false }; +}; +template +struct IsSame { + enum { value = true }; +}; + +// Evaluates to the number of elements in 'array'. +#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) #if GTEST_HAS_GLOBAL_STRING typedef ::string string; @@ -913,6 +1228,11 @@ class scoped_ptr { } } + friend void swap(scoped_ptr& a, scoped_ptr& b) { + using std::swap; + swap(a.ptr_, b.ptr_); + } + private: T* ptr_; @@ -921,6 +1241,10 @@ class scoped_ptr { // Defines RE. +#if GTEST_USES_PCRE +// if used, PCRE is injected by custom/gtest-port.h +#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE + // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { @@ -932,11 +1256,11 @@ class GTEST_API_ RE { // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); @@ -949,7 +1273,7 @@ class GTEST_API_ RE { // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // FIXME: make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -958,7 +1282,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#if GTEST_HAS_GLOBAL_STRING +# if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); @@ -967,7 +1291,7 @@ class GTEST_API_ RE { return PartialMatch(str.c_str(), re); } -#endif // GTEST_HAS_GLOBAL_STRING +# endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); @@ -976,25 +1300,27 @@ class GTEST_API_ RE { void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to + // used where std::string is not available. FIXME: change to // std::string. const char* pattern_; bool is_valid_; -#if GTEST_USES_POSIX_RE +# if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). -#else // GTEST_USES_SIMPLE_RE +# else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); -#endif +# endif GTEST_DISALLOW_ASSIGN_(RE); }; +#endif // GTEST_USES_PCRE + // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); @@ -1036,13 +1362,18 @@ class GTEST_API_ GTestLog { GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; -#define GTEST_LOG_(severity) \ +#if !defined(GTEST_LOG_) + +# define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } +#endif // !defined(GTEST_LOG_) + +#if !defined(GTEST_CHECK_) // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition @@ -1057,12 +1388,13 @@ inline void FlushInfoLog() { fflush(NULL); } // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ +# define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " +#endif // !defined(GTEST_CHECK_) // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this @@ -1074,6 +1406,61 @@ inline void FlushInfoLog() { fflush(NULL); } GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Transforms "T" into "const T&" according to standard reference collapsing +// rules (this is only needed as a backport for C++98 compilers that do not +// support reference collapsing). Specifically, it transforms: +// +// char ==> const char& +// const char ==> const char& +// char& ==> char& +// const char& ==> const char& +// +// Note that the non-const reference will not have "const" added. This is +// standard, and necessary so that "T" can always bind to "const T&". +template +struct ConstRef { typedef const T& type; }; +template +struct ConstRef { typedef T& type; }; + +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + typename ::testing::internal::ConstRef::type + +#if GTEST_HAS_STD_MOVE_ +using std::forward; +using std::move; + +template +struct RvalueRef { + typedef T&& type; +}; +#else // GTEST_HAS_STD_MOVE_ +template +const T& move(const T& t) { + return t; +} +template +GTEST_ADD_REFERENCE_(T) forward(GTEST_ADD_REFERENCE_(T) t) { return t; } + +template +struct RvalueRef { + typedef const T& type; +}; +#endif // GTEST_HAS_STD_MOVE_ + // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in @@ -1124,7 +1511,9 @@ inline To DownCast_(From* f) { // so we only accept pointers // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. + GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { + GTEST_INTENTIONAL_CONST_COND_POP_() const To to = NULL; ::testing::internal::ImplicitCast_(to); } @@ -1145,6 +1534,11 @@ template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); +#endif + +#if GTEST_HAS_DOWNCAST_ + return ::down_cast(base); +#elif GTEST_HAS_RTTI return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. @@ -1165,26 +1559,34 @@ GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION +// Returns the size (in bytes) of a file. +GTEST_API_ size_t GetFileSize(FILE* file); +// Reads the entire content of a file as a string. +GTEST_API_ std::string ReadEntireFile(FILE* file); + +// All command line arguments. +GTEST_API_ std::vector GetArgvs(); #if GTEST_HAS_DEATH_TEST -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); - -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; +std::vector GetInjectableArgvs(); +// Deprecated: pass the args vector by value instead. +void SetInjectableArgvs(const std::vector* new_argvs); +void SetInjectableArgvs(const std::vector& new_argvs); +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs); +#endif // GTEST_HAS_GLOBAL_STRING +void ClearInjectableArgvs(); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. - -#if GTEST_HAS_PTHREAD - -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. +#if GTEST_IS_THREADSAFE +# if GTEST_HAS_PTHREAD +// Sleeps for (roughly) n milliseconds. This function is only for testing +// Google Test's own constructs. Don't use it in user tests, either +// directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. @@ -1192,7 +1594,13 @@ inline void SleepMilliseconds(int n) { }; nanosleep(&time, NULL); } +# endif // GTEST_HAS_PTHREAD +# if GTEST_HAS_NOTIFICATION_ +// Notification has already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_HAS_PTHREAD // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. @@ -1236,6 +1644,62 @@ class Notification { GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +GTEST_API_ void SleepMilliseconds(int n); + +// Provides leak-safe Windows kernel handle ownership. +// Used in death tests and in threading support. +class GTEST_API_ AutoHandle { + public: + // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to + // avoid including in this header file. Including is + // undesirable because it defines a lot of symbols and macros that tend to + // conflict with client code. This assumption is verified by + // WindowsTypesTest.HANDLEIsVoidStar. + typedef void* Handle; + AutoHandle(); + explicit AutoHandle(Handle handle); + + ~AutoHandle(); + + Handle Get() const; + void Reset(); + void Reset(Handle handle); + + private: + // Returns true iff the handle is a valid handle object that can be closed. + bool IsCloseable() const; + + Handle handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class GTEST_API_ Notification { + public: + Notification(); + void Notify(); + void WaitForNotification(); + + private: + AutoHandle event_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; +# endif // GTEST_HAS_NOTIFICATION_ + +// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD +// defined, but we don't want to use MinGW's pthreads implementation, which +// has conformance problems with some versions of the POSIX standard. +# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW + // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a @@ -1273,10 +1737,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { template class ThreadWithParam : public ThreadWithParamBase { public: - typedef void (*UserThreadFunc)(T); + typedef void UserThreadFunc(T); - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), @@ -1303,7 +1766,7 @@ class ThreadWithParam : public ThreadWithParamBase { } private: - const UserThreadFunc func_; // User-supplied thread function. + UserThreadFunc* const func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. @@ -1313,26 +1776,293 @@ class ThreadWithParam : public ThreadWithParamBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; +# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || + // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: +# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ +// Mutex and ThreadLocal have already been imported into the namespace. +// Nothing to do here. + +# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT + +// Mutex implements mutex on Windows platforms. It is used in conjunction +// with class MutexLock: // // Mutex mutex; // ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the +// // end of the current scope. // +// A static Mutex *must* be defined or declared using one of the following +// macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); -// -// You can forward declare a static mutex like this: -// // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // -// To create a dynamic mutex, just define an object of type Mutex. +// (A non-static Mutex is defined/declared in the usual way). +class GTEST_API_ Mutex { + public: + enum MutexType { kStatic = 0, kDynamic = 1 }; + // We rely on kStaticMutex being 0 as it is to what the linker initializes + // type_ in static mutexes. critical_section_ will be initialized lazily + // in ThreadSafeLazyInit(). + enum StaticConstructorSelector { kStaticMutex = 0 }; + + // This constructor intentionally does nothing. It relies on type_ being + // statically initialized to 0 (effectively setting it to kStatic) and on + // ThreadSafeLazyInit() to lazily initialize the rest of the members. + explicit Mutex(StaticConstructorSelector /*dummy*/) {} + + Mutex(); + ~Mutex(); + + void Lock(); + + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld(); + + private: + // Initializes owner_thread_id_ and critical_section_ in static mutexes. + void ThreadSafeLazyInit(); + + // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503, + // we assume that 0 is an invalid value for thread IDs. + unsigned int owner_thread_id_; + + // For static mutexes, we rely on these members being initialized to zeros + // by the linker. + MutexType type_; + long critical_section_init_phase_; // NOLINT + GTEST_CRITICAL_SECTION* critical_section_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) + +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + Mutex* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Base class for ValueHolder. Allows a caller to hold and delete a value +// without knowing its type. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Provides a way for a thread to send notifications to a ThreadLocal +// regardless of its parameter type. +class ThreadLocalBase { + public: + // Creates a new ValueHolder object holding a default value passed to + // this ThreadLocal's constructor and returns it. It is the caller's + // responsibility not to call this when the ThreadLocal instance already + // has a value on the current thread. + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; + + protected: + ThreadLocalBase() {} + virtual ~ThreadLocalBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); +}; + +// Maps a thread to a set of ThreadLocals that have values instantiated on that +// thread and notifies them when the thread exits. A ThreadLocal instance is +// expected to persist until all threads it has values on have terminated. +class GTEST_API_ ThreadLocalRegistry { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance); + + // Invoked when a ThreadLocal instance is destroyed. + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance); +}; + +class GTEST_API_ ThreadWithParamBase { + public: + void Join(); + + protected: + class Runnable { + public: + virtual ~Runnable() {} + virtual void Run() = 0; + }; + + ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); + virtual ~ThreadWithParamBase(); + + private: + AutoHandle thread_; +}; + +// Helper class for testing Google Test's multi-threading constructs. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void UserThreadFunc(T); + + ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) + : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { + } + virtual ~ThreadWithParam() {} + + private: + class RunnableImpl : public Runnable { + public: + RunnableImpl(UserThreadFunc* func, T param) + : func_(func), + param_(param) { + } + virtual ~RunnableImpl() {} + virtual void Run() { + func_(param_); + } + + private: + UserThreadFunc* const func_; + const T param_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); + }; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// Implements thread-local storage on Windows systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// The users of a TheadLocal instance have to make sure that all but one +// threads (including the main one) using that instance have exited before +// destroying it. Otherwise, the per-thread objects managed for them by the +// ThreadLocal instance are not guaranteed to be destroyed on all platforms. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal : public ThreadLocalBase { + public: + ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : default_factory_(new InstanceValueHolderFactory(value)) {} + + ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of T. Can be deleted via its base class without the caller + // knowing the type of T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + ValueHolder() : value_() {} + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + + T* GetOrCreateValue() const { + return static_cast( + ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); + } + + virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { + return default_factory_->MakeNewHolder(); + } + + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + + scoped_ptr default_factory_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# elif GTEST_HAS_PTHREAD + +// MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. @@ -1377,8 +2107,8 @@ class MutexBase { }; // Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, @@ -1386,8 +2116,8 @@ class MutexBase { // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0} // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. @@ -1405,9 +2135,11 @@ class Mutex : public MutexBase { GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; -// We cannot name this class MutexLock as the ctor declaration would +// We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) @@ -1441,41 +2173,14 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) { } // Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} + ThreadLocal() + : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. @@ -1495,6 +2200,7 @@ class ThreadLocal { // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: + ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } @@ -1520,22 +2226,54 @@ class ThreadLocal { return CheckedDowncastToActualType(holder)->pointer(); } - ValueHolder* const new_holder = new ValueHolder(default_); + ValueHolder* const new_holder = default_factory_->MakeNewHolder(); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } + class ValueHolderFactory { + public: + ValueHolderFactory() {} + virtual ~ValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); + }; + + class DefaultValueHolderFactory : public ValueHolderFactory { + public: + DefaultValueHolderFactory() {} + virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); + }; + + class InstanceValueHolderFactory : public ValueHolderFactory { + public: + explicit InstanceValueHolderFactory(const T& value) : value_(value) {} + virtual ValueHolder* MakeNewHolder() const { + return new ValueHolder(value_); + } + + private: + const T value_; // The value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); + }; + // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; - const T default_; // The default value for each thread. + scoped_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; -# define GTEST_IS_THREADSAFE 1 +# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ -#else // GTEST_HAS_PTHREAD +#else // GTEST_IS_THREADSAFE // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where @@ -1555,6 +2293,11 @@ class Mutex { # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex +// We cannot name this class MutexLock because the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. That macro is used as a defensive measure to prevent against +// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than +// "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -1563,7 +2306,7 @@ class GTestMutexLock { typedef GTestMutexLock MutexLock; template -class ThreadLocal { +class GTEST_API_ ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} @@ -1575,11 +2318,7 @@ class ThreadLocal { T value_; }; -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -# define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD +#endif // GTEST_IS_THREADSAFE // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. @@ -1618,6 +2357,13 @@ template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; +template +struct is_same : public false_type {}; + +template +struct is_same : public true_type {}; + + template struct is_pointer : public false_type {}; @@ -1629,6 +2375,7 @@ struct IteratorTraits { typedef typename Iterator::value_type value_type; }; + template struct IteratorTraits { typedef T value_type; @@ -1690,6 +2437,13 @@ inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } +inline std::string StripTrailingSpaces(std::string str) { + std::string::iterator it = str.end(); + while (it != str.begin() && IsSpace(*--it)) + it = str.erase(it); + return str; +} + // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these @@ -1723,7 +2477,7 @@ inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE -inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +inline int FileNo(FILE* file) { return static_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else @@ -1753,11 +2507,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } // Functions deprecated by MSVC 8.0. -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -# pragma warning(push) -# pragma warning(disable:4996) -#endif +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); @@ -1767,7 +2517,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) { // StrError() aren't needed on Windows CE at this time and thus not // defined there. -#if !GTEST_OS_WINDOWS_MOBILE +#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { @@ -1791,8 +2541,9 @@ inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. + static_cast(name); // To prevent 'unused argument' warning. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the @@ -1804,9 +2555,7 @@ inline const char* GetEnv(const char* name) { #endif } -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif +GTEST_DISABLE_MSC_DEPRECATED_POP_() #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in @@ -1907,31 +2656,44 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name +#if !defined(GTEST_FLAG) +# define GTEST_FLAG(name) FLAGS_gtest_##name +#endif // !defined(GTEST_FLAG) + +#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) +# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 +#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) + +#if !defined(GTEST_DECLARE_bool_) +# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ +# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +# define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ +# define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ +# define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ +# define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ +# define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) +#endif // !defined(GTEST_DECLARE_bool_) + // Thread annotations -#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -#define GTEST_LOCK_EXCLUDED_(locks) +#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) +# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +# define GTEST_LOCK_EXCLUDED_(locks) +#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// FIXME: Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); @@ -1940,6 +2702,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value); // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +std::string OutputFlagAlsoCheckEnvVar(); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal diff --git a/test/fmw/gtest/include/gtest/internal/gtest-string.h b/test/fmw/gtest/include/gtest/internal/gtest-string.h index 97f1a7fdd2c..4c9b6262c3c 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-string.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-string.h @@ -27,17 +27,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // -// This header file is #included by . +// This header file is #included by gtest-internal.h. // It should not be #included by other files. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ diff --git a/test/fmw/gtest/include/gtest/internal/gtest-tuple.h b/test/fmw/gtest/include/gtest/internal/gtest-tuple.h index 7b3dfc312dc..78a3a6a01fa 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-tuple.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-tuple.h @@ -30,11 +30,12 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Implements a subset of TR1 tuple needed by Google Test and Google Mock. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ @@ -42,7 +43,7 @@ // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be +// bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) @@ -53,6 +54,14 @@ private: #endif +// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict +// with our own definitions. Therefore using our own tuple does not work on +// those compilers. +#if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple= 1600 /* 1600 is Visual Studio 2010 */ +# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ +GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." +#endif + $range i 0..n-1 $range j 0..n diff --git a/test/fmw/gtest/include/gtest/internal/gtest-type-util.h b/test/fmw/gtest/include/gtest/internal/gtest-type-util.h index e46f7cfcb48..28e41124536 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-type-util.h +++ b/test/fmw/gtest/include/gtest/internal/gtest-type-util.h @@ -30,8 +30,7 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -41,6 +40,8 @@ // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -57,6 +58,22 @@ namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -75,7 +92,7 @@ std::string GetTypeName() { char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC diff --git a/test/fmw/gtest/include/gtest/internal/gtest-type-util.h.pump b/test/fmw/gtest/include/gtest/internal/gtest-type-util.h.pump index 251fdf025b2..0001a5d39df 100644 --- a/test/fmw/gtest/include/gtest/internal/gtest-type-util.h.pump +++ b/test/fmw/gtest/include/gtest/internal/gtest-type-util.h.pump @@ -28,8 +28,7 @@ $var n = 50 $$ Maximum length of type lists we want to support. // 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. -// -// Author: wan@google.com (Zhanyong Wan) + // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! @@ -39,6 +38,8 @@ $var n = 50 $$ Maximum length of type lists we want to support. // Please contact googletestframework@googlegroups.com if you need // more. +// GOOGLETEST_CM0001 DO NOT DELETE + #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ @@ -55,6 +56,22 @@ $var n = 50 $$ Maximum length of type lists we want to support. namespace testing { namespace internal { +// Canonicalizes a given name with respect to the Standard C++ Library. +// This handles removing the inline namespace within `std` that is +// used by various standard libraries (e.g., `std::__1`). Names outside +// of namespace std are returned unmodified. +inline std::string CanonicalizeForStdLibVersioning(std::string s) { + static const char prefix[] = "std::__"; + if (s.compare(0, strlen(prefix), prefix) == 0) { + std::string::size_type end = s.find("::", strlen(prefix)); + if (end != s.npos) { + // Erase everything between the initial `std` and the second `::`. + s.erase(strlen("std"), end - strlen("std")); + } + } + return s; +} + // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. @@ -73,7 +90,7 @@ std::string GetTypeName() { char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); - return name_str; + return CanonicalizeForStdLibVersioning(name_str); # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC diff --git a/test/fmw/gtest/src/gtest-all.cc b/test/fmw/gtest/src/gtest-all.cc index 0a9cee52233..b217a18006b 100644 --- a/test/fmw/gtest/src/gtest-all.cc +++ b/test/fmw/gtest/src/gtest-all.cc @@ -26,10 +26,9 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) +// Google C++ Testing and Mocking Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. diff --git a/test/fmw/gtest/src/gtest-death-test.cc b/test/fmw/gtest/src/gtest-death-test.cc index a6023fce4fa..09083551612 100644 --- a/test/fmw/gtest/src/gtest-death-test.cc +++ b/test/fmw/gtest/src/gtest-death-test.cc @@ -26,13 +26,13 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) + // // This file implements death tests. #include "gtest/gtest-death-test.h" #include "gtest/internal/gtest-port.h" +#include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST @@ -61,26 +61,30 @@ # include # endif // GTEST_OS_QNX +# if GTEST_OS_FUCHSIA +# include +# include +# include +# include +# include +# endif // GTEST_OS_FUCHSIA + #endif // GTEST_HAS_DEATH_TEST #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; +// +// This is defined in internal/gtest-port.h as "fast", but can be overridden by +// a definition in internal/custom/gtest-port.h. The recommended value, which is +// used internally at Google, is "threadsafe". +static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE; GTEST_DEFINE_string_( death_test_style, @@ -120,7 +124,9 @@ namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA static bool g_in_fast_death_test_child = false; +# endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as @@ -128,10 +134,10 @@ static bool g_in_fast_death_test_child = false; // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. + // On Windows and Fuchsia, death tests are thread-safe regardless of the value + // of the death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else @@ -151,7 +157,7 @@ ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return exit_status == exit_code_; @@ -159,19 +165,27 @@ bool ExitedWithCode::operator()(int exit_status) const { return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { +# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) + { + bool result; + if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { + return result; + } + } +# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA namespace internal { @@ -182,7 +196,7 @@ namespace internal { static std::string ExitSummary(int exit_code) { Message m; -# if GTEST_OS_WINDOWS +# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA m << "Exited with exit status " << exit_code; @@ -198,7 +212,7 @@ static std::string ExitSummary(int exit_code) { m << " (core dumped)"; } # endif -# endif // GTEST_OS_WINDOWS +# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA return m.GetString(); } @@ -209,7 +223,7 @@ bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } -# if !GTEST_OS_WINDOWS +# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the @@ -218,13 +232,19 @@ static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) + if (thread_count == 0) { msg << "couldn't detect the number of threads."; - else + } else { msg << "detected " << thread_count << " threads."; + } + msg << " See " + "https://github.com/google/googletest/blob/master/googletest/docs/" + "advanced.md#death-tests-and-threads" + << " for more explanation and suggested solutions, especially if" + << " this is the last message you see before your test times out."; return msg.GetString(); } -# endif // !GTEST_OS_WINDOWS +# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; @@ -232,6 +252,13 @@ static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; +#if GTEST_OS_FUCHSIA + +// File descriptor used for the pipe in the child process. +static const int kFuchsiaReadPipeFd = 3; + +#endif + // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; @@ -239,7 +266,7 @@ static const char kDeathTestInternalError = 'I'; // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for +// FIXME: Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; @@ -248,7 +275,7 @@ enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. -void DeathTestAbort(const std::string& message) { +static void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. @@ -552,7 +579,12 @@ bool DeathTestImpl::Passed(bool status_ok) { break; case DIED: if (status_ok) { +# if GTEST_USES_PCRE + // PCRE regexes support embedded NULs. + const bool matched = RE::PartialMatch(error_message, *regex()); +# else const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); +# endif // GTEST_USES_PCRE if (matched) { success = true; } else { @@ -768,7 +800,200 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() { set_spawned(true); return OVERSEE_TEST; } -# else // We are not on Windows. + +# elif GTEST_OS_FUCHSIA + +class FuchsiaDeathTest : public DeathTestImpl { + public: + FuchsiaDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + virtual ~FuchsiaDeathTest() { + zx_status_t status = zx_handle_close(child_process_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_handle_close(port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + } + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + + zx_handle_t child_process_ = ZX_HANDLE_INVALID; + zx_handle_t port_ = ZX_HANDLE_INVALID; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + int size() { + return args_.size() - 1; + } + + private: + std::vector args_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int FuchsiaDeathTest::Wait() { + if (!spawned()) + return 0; + + // Register to wait for the child process to terminate. + zx_status_t status_zx; + status_zx = zx_object_wait_async(child_process_, + port_, + 0 /* key */, + ZX_PROCESS_TERMINATED, + ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Wait for it to terminate, or an exception to be received. + zx_port_packet_t packet; + status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + if (ZX_PKT_IS_EXCEPTION(packet.type)) { + // Process encountered an exception. Kill it directly rather than letting + // other handlers process the event. + status_zx = zx_task_kill(child_process_); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + // Now wait for |child_process_| to terminate. + zx_signals_t signals = 0; + status_zx = zx_object_wait_one( + child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); + } else { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + } + + ReadAndInterpretStatusByte(); + + zx_info_process_t buffer; + status_zx = zx_object_get_info( + child_process_, + ZX_INFO_PROCESS, + &buffer, + sizeof(buffer), + nullptr, + nullptr); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + + GTEST_DEATH_TEST_CHECK_(buffer.exited); + set_status(buffer.return_code); + return status(); +} + +// The AssumeRole process for a Fuchsia death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(kFuchsiaReadPipeFd); + return EXECUTE_TEST; + } + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // Build the child process command line. + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + + StreamableToString(line_) + "|" + + StreamableToString(death_test_index); + Arguments args; + args.AddArguments(GetInjectableArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + // Build the pipe for communication with the child. + zx_status_t status; + zx_handle_t child_pipe_handle; + uint32_t type; + status = fdio_pipe_half(&child_pipe_handle, &type); + GTEST_DEATH_TEST_CHECK_(status >= 0); + set_read_fd(status); + + // Set the pipe handle for the child. + fdio_spawn_action_t add_handle_action = {}; + add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); + add_handle_action.h.handle = child_pipe_handle; + + // Spawn the child process. + status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, + args.Argv()[0], args.Argv(), nullptr, 1, + &add_handle_action, &child_process_, nullptr); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + // Create an exception port and attach it to the |child_process_|, to allow + // us to suppress the system default exception handler from firing. + status = zx_port_create(0, &port_); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + status = zx_task_bind_exception_port( + child_process_, port_, 0 /* key */, 0 /*options */); + GTEST_DEATH_TEST_CHECK_(status == ZX_OK); + + set_spawned(true); + return OVERSEE_TEST; +} + +#else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is @@ -872,9 +1097,13 @@ class ExecDeathTest : public ForkingDeathTest { ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); + static ::std::vector GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); +# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) + ::std::vector extra_args = + GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); + args.insert(args.end(), extra_args.begin(), extra_args.end()); +# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // The name of the file in which the death test is located. @@ -970,6 +1199,7 @@ static int ExecDeathTestChildMain(void* child_arg) { } # endif // !GTEST_OS_QNX +# if GTEST_HAS_CLONE // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive @@ -979,18 +1209,22 @@ static int ExecDeathTestChildMain(void* child_arg) { // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { +static void StackLowerThanAddress(const void* ptr, + bool* result) GTEST_NO_INLINE_; +static void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } -bool StackGrowsDown() { +// Make sure AddressSanitizer does not tamper with the stack here. +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +static bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } +# endif // GTEST_HAS_CLONE // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The @@ -1182,6 +1416,13 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, *test = new WindowsDeathTest(statement, regex, file, line); } +# elif GTEST_OS_FUCHSIA + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new FuchsiaDeathTest(statement, regex, file, line); + } + # else if (GTEST_FLAG(death_test_style) == "threadsafe") { @@ -1202,31 +1443,11 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, return true; } -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, +static int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, @@ -1237,7 +1458,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, StreamableToString(parent_process_id)); } - // TODO(vladl@google.com): Replace the following check with a + // FIXME: Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); @@ -1245,7 +1466,7 @@ int GetStatusFileDescriptor(unsigned int parent_process_id, reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; - // The newly initialized handle is accessible only in in the parent + // The newly initialized handle is accessible only in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, @@ -1322,6 +1543,16 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); + +# elif GTEST_OS_FUCHSIA + + if (fields.size() != 3 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + # else if (fields.size() != 4 diff --git a/test/fmw/gtest/src/gtest-filepath.cc b/test/fmw/gtest/src/gtest-filepath.cc index 6be58b6fca2..a7e65c082a7 100644 --- a/test/fmw/gtest/src/gtest-filepath.cc +++ b/test/fmw/gtest/src/gtest-filepath.cc @@ -26,14 +26,12 @@ // 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) -#include "gtest/gtest-message.h" #include "gtest/internal/gtest-filepath.h" -#include "gtest/internal/gtest-port.h" #include +#include "gtest/internal/gtest-port.h" +#include "gtest/gtest-message.h" #if GTEST_OS_WINDOWS_MOBILE # include @@ -48,6 +46,8 @@ # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE +#include "gtest/internal/gtest-string.h" + #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) @@ -58,8 +58,6 @@ # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS -#include "gtest/internal/gtest-string.h" - namespace testing { namespace internal { @@ -70,7 +68,6 @@ namespace internal { // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; -const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use @@ -84,7 +81,6 @@ const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; -const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS @@ -99,7 +95,7 @@ static bool IsPathSeparator(char c) { // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); @@ -108,7 +104,14 @@ FilePath FilePath::GetCurrentDir() { return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); + char* result = getcwd(cwd, sizeof(cwd)); +# if GTEST_OS_NACL + // getcwd will likely fail in NaCl due to the sandbox, so return something + // reasonable. The user may have provided a shim implementation for getcwd, + // however, so fallback only when failure is detected. + return FilePath(result == NULL ? kCurrentDirectoryString : cwd); +# endif // GTEST_OS_NACL + return FilePath(result == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } @@ -125,7 +128,7 @@ FilePath FilePath::RemoveExtension(const char* extension) const { return *this; } -// Returns a pointer to the last occurence of a valid path separator in +// Returns a pointer to the last occurrence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { @@ -247,7 +250,7 @@ bool FilePath::DirectoryExists() const { // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like + // FIXME: on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); @@ -347,7 +350,7 @@ FilePath FilePath::RemoveTrailingPathSeparator() const { // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +// FIXME: handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; diff --git a/test/fmw/gtest/src/gtest-internal-inl.h b/test/fmw/gtest/src/gtest-internal-inl.h index 35df303cca6..479004149b4 100644 --- a/test/fmw/gtest/src/gtest-internal-inl.h +++ b/test/fmw/gtest/src/gtest-internal-inl.h @@ -27,24 +27,13 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// +// Utility functions and classes used by the Google C++ testing framework.// // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE @@ -67,9 +56,12 @@ # include // NOLINT #endif // GTEST_OS_WINDOWS -#include "gtest/gtest.h" // NOLINT +#include "gtest/gtest.h" #include "gtest/gtest-spi.h" +GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ +/* class A needs to have dll-interface to be used by clients of class B */) + namespace testing { // Declares the flags. @@ -94,12 +86,14 @@ const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; +const char kPrintUTF8Flag[] = "print_utf8"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; +const char kFlagfileFlag[] = "flagfile"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; @@ -173,6 +167,7 @@ class GTestFlagSaver { list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); + print_utf8_ = GTEST_FLAG(print_utf8); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); @@ -194,6 +189,7 @@ class GTestFlagSaver { GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(print_utf8) = print_utf8_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; @@ -215,6 +211,7 @@ class GTestFlagSaver { bool list_tests_; std::string output_; bool print_time_; + bool print_utf8_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; @@ -425,13 +422,17 @@ class OsStackTraceGetterInterface { // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; @@ -439,25 +440,21 @@ class OsStackTraceGetterInterface { // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: - OsStackTraceGetter() : caller_frame_(NULL) {} + OsStackTraceGetter() {} - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); - - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; + virtual std::string CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); private: - Mutex mutex_; // protects all internal state +#if GTEST_HAS_ABSL + Mutex mutex_; // Protects all internal state. // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; + // and any calls to the stack trace code from within the user code. + void* caller_frame_ = nullptr; +#endif // GTEST_HAS_ABSL GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; @@ -673,13 +670,11 @@ class GTEST_API_ UnitTestImpl { tear_down_tc)->AddTestInfo(test_info); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } -#endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { @@ -854,14 +849,12 @@ class GTEST_API_ UnitTestImpl { // shuffled order. std::vector test_case_indices_; -#if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; @@ -968,32 +961,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); // platform. GTEST_API_ std::string GetLastErrnoDescription(); -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use @@ -1027,7 +994,7 @@ bool ParseNaturalNumber(const ::std::string& str, Integer* number) { const bool parse_success = *end == '\0' && errno == 0; - // TODO(vladl@google.com): Convert this to compile time assertion when it is + // FIXME: Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); @@ -1075,21 +1042,19 @@ class StreamingListener : public EmptyTestEventListener { virtual ~AbstractSocketWriter() {} // Sends a string to the socket. - virtual void Send(const string& message) = 0; + virtual void Send(const std::string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } + void SendLn(const std::string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: - SocketWriter(const string& host, const string& port) + SocketWriter(const std::string& host, const std::string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } @@ -1100,7 +1065,7 @@ class StreamingListener : public EmptyTestEventListener { } // Sends a string to the socket. - virtual void Send(const string& message) { + virtual void Send(const std::string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; @@ -1126,17 +1091,19 @@ class StreamingListener : public EmptyTestEventListener { } int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; + const std::string host_name_; + const std::string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); + static std::string UrlEncode(const char* str); - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } + StreamingListener(const std::string& host, const std::string& port) + : socket_writer_(new SocketWriter(host, port)) { + Start(); + } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } @@ -1197,13 +1164,13 @@ class StreamingListener : public EmptyTestEventListener { private: // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } + void SendLn(const std::string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - string FormatBool(bool value) { return value ? "1" : "0"; } + std::string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; @@ -1215,4 +1182,6 @@ class StreamingListener : public EmptyTestEventListener { } // namespace internal } // namespace testing +GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 + #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ diff --git a/test/fmw/gtest/src/gtest-port.cc b/test/fmw/gtest/src/gtest-port.cc index 0c4df5f29a7..fecb5d11c21 100644 --- a/test/fmw/gtest/src/gtest-port.cc +++ b/test/fmw/gtest/src/gtest-port.cc @@ -26,8 +26,7 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/internal/gtest-port.h" @@ -35,15 +34,16 @@ #include #include #include +#include -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS +# include # include # include +# include // Used in ThreadLocal. #else # include -#endif // GTEST_OS_WINDOWS_MOBILE +#endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include @@ -53,22 +53,25 @@ #if GTEST_OS_QNX # include +# include # include #endif // GTEST_OS_QNX +#if GTEST_OS_AIX +# include +# include +#endif // GTEST_OS_AIX + +#if GTEST_OS_FUCHSIA +# include +# include +#endif // GTEST_OS_FUCHSIA + #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.h" #include "gtest/internal/gtest-string.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { @@ -82,10 +85,31 @@ const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER -#if GTEST_OS_MAC +#if GTEST_OS_LINUX + +namespace { +template +T ReadProcFileField(const std::string& filename, int field) { + std::string dummy; + std::ifstream file(filename.c_str()); + while (field-- > 0) { + file >> dummy; + } + T output = 0; + file >> output; + return output; +} +} // namespace + +// Returns the number of active threads, or 0 when there is an error. +size_t GetThreadCount() { + const std::string filename = + (Message() << "/proc/" << getpid() << "/stat").GetString(); + return ReadProcFileField(filename, 19); +} + +#elif GTEST_OS_MAC -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; @@ -123,6 +147,38 @@ size_t GetThreadCount() { } } +#elif GTEST_OS_AIX + +size_t GetThreadCount() { + struct procentry64 entry; + pid_t pid = getpid(); + int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1); + if (status == 1) { + return entry.pi_thcount; + } else { + return 0; + } +} + +#elif GTEST_OS_FUCHSIA + +size_t GetThreadCount() { + int dummy_buffer; + size_t avail; + zx_status_t status = zx_object_get_info( + zx_process_self(), + ZX_INFO_PROCESS_THREADS, + &dummy_buffer, + 0, + nullptr, + &avail); + if (status == ZX_OK) { + return avail; + } else { + return 0; + } +} + #else size_t GetThreadCount() { @@ -131,7 +187,432 @@ size_t GetThreadCount() { return 0; } -#endif // GTEST_OS_MAC +#endif // GTEST_OS_LINUX + +#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS + +void SleepMilliseconds(int n) { + ::Sleep(n); +} + +AutoHandle::AutoHandle() + : handle_(INVALID_HANDLE_VALUE) {} + +AutoHandle::AutoHandle(Handle handle) + : handle_(handle) {} + +AutoHandle::~AutoHandle() { + Reset(); +} + +AutoHandle::Handle AutoHandle::Get() const { + return handle_; +} + +void AutoHandle::Reset() { + Reset(INVALID_HANDLE_VALUE); +} + +void AutoHandle::Reset(HANDLE handle) { + // Resetting with the same handle we already own is invalid. + if (handle_ != handle) { + if (IsCloseable()) { + ::CloseHandle(handle_); + } + handle_ = handle; + } else { + GTEST_CHECK_(!IsCloseable()) + << "Resetting a valid handle to itself is likely a programmer error " + "and thus not allowed."; + } +} + +bool AutoHandle::IsCloseable() const { + // Different Windows APIs may use either of these values to represent an + // invalid handle. + return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; +} + +Notification::Notification() + : event_(::CreateEvent(NULL, // Default security attributes. + TRUE, // Do not reset automatically. + FALSE, // Initially unset. + NULL)) { // Anonymous event. + GTEST_CHECK_(event_.Get() != NULL); +} + +void Notification::Notify() { + GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); +} + +void Notification::WaitForNotification() { + GTEST_CHECK_( + ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); +} + +Mutex::Mutex() + : owner_thread_id_(0), + type_(kDynamic), + critical_section_init_phase_(0), + critical_section_(new CRITICAL_SECTION) { + ::InitializeCriticalSection(critical_section_); +} + +Mutex::~Mutex() { + // Static mutexes are leaked intentionally. It is not thread-safe to try + // to clean them up. + // FIXME: Switch to Slim Reader/Writer (SRW) Locks, which requires + // nothing to clean it up but is available only on Vista and later. + // https://docs.microsoft.com/en-us/windows/desktop/Sync/slim-reader-writer--srw--locks + if (type_ == kDynamic) { + ::DeleteCriticalSection(critical_section_); + delete critical_section_; + critical_section_ = NULL; + } +} + +void Mutex::Lock() { + ThreadSafeLazyInit(); + ::EnterCriticalSection(critical_section_); + owner_thread_id_ = ::GetCurrentThreadId(); +} + +void Mutex::Unlock() { + ThreadSafeLazyInit(); + // We don't protect writing to owner_thread_id_ here, as it's the + // caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_thread_id_ = 0; + ::LeaveCriticalSection(critical_section_); +} + +// Does nothing if the current thread holds the mutex. Otherwise, crashes +// with high probability. +void Mutex::AssertHeld() { + ThreadSafeLazyInit(); + GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) + << "The current thread is not holding the mutex @" << this; +} + +namespace { + +// Use the RAII idiom to flag mem allocs that are intentionally never +// deallocated. The motivation is to silence the false positive mem leaks +// that are reported by the debug version of MS's CRT which can only detect +// if an alloc is missing a matching deallocation. +// Example: +// MemoryIsNotDeallocated memory_is_not_deallocated; +// critical_section_ = new CRITICAL_SECTION; +// +class MemoryIsNotDeallocated +{ + public: + MemoryIsNotDeallocated() : old_crtdbg_flag_(0) { +#ifdef _MSC_VER + old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT + // doesn't report mem leak if there's no matching deallocation. + _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF); +#endif // _MSC_VER + } + + ~MemoryIsNotDeallocated() { +#ifdef _MSC_VER + // Restore the original _CRTDBG_ALLOC_MEM_DF flag + _CrtSetDbgFlag(old_crtdbg_flag_); +#endif // _MSC_VER + } + + private: + int old_crtdbg_flag_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated); +}; + +} // namespace + +// Initializes owner_thread_id_ and critical_section_ in static mutexes. +void Mutex::ThreadSafeLazyInit() { + // Dynamic mutexes are initialized in the constructor. + if (type_ == kStatic) { + switch ( + ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { + case 0: + // If critical_section_init_phase_ was 0 before the exchange, we + // are the first to test it and need to perform the initialization. + owner_thread_id_ = 0; + { + // Use RAII to flag that following mem alloc is never deallocated. + MemoryIsNotDeallocated memory_is_not_deallocated; + critical_section_ = new CRITICAL_SECTION; + } + ::InitializeCriticalSection(critical_section_); + // Updates the critical_section_init_phase_ to 2 to signal + // initialization complete. + GTEST_CHECK_(::InterlockedCompareExchange( + &critical_section_init_phase_, 2L, 1L) == + 1L); + break; + case 1: + // Somebody else is already initializing the mutex; spin until they + // are done. + while (::InterlockedCompareExchange(&critical_section_init_phase_, + 2L, + 2L) != 2L) { + // Possibly yields the rest of the thread's time slice to other + // threads. + ::Sleep(0); + } + break; + + case 2: + break; // The mutex is already initialized and ready for use. + + default: + GTEST_CHECK_(false) + << "Unexpected value of critical_section_init_phase_ " + << "while initializing a static mutex."; + } + } +} + +namespace { + +class ThreadWithParamSupport : public ThreadWithParamBase { + public: + static HANDLE CreateThread(Runnable* runnable, + Notification* thread_can_start) { + ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); + DWORD thread_id; + // FIXME: Consider to use _beginthreadex instead. + HANDLE thread_handle = ::CreateThread( + NULL, // Default security. + 0, // Default stack size. + &ThreadWithParamSupport::ThreadMain, + param, // Parameter to ThreadMainStatic + 0x0, // Default creation flags. + &thread_id); // Need a valid pointer for the call to work under Win98. + GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " + << ::GetLastError() << "."; + if (thread_handle == NULL) { + delete param; + } + return thread_handle; + } + + private: + struct ThreadMainParam { + ThreadMainParam(Runnable* runnable, Notification* thread_can_start) + : runnable_(runnable), + thread_can_start_(thread_can_start) { + } + scoped_ptr runnable_; + // Does not own. + Notification* thread_can_start_; + }; + + static DWORD WINAPI ThreadMain(void* ptr) { + // Transfers ownership. + scoped_ptr param(static_cast(ptr)); + if (param->thread_can_start_ != NULL) + param->thread_can_start_->WaitForNotification(); + param->runnable_->Run(); + return 0; + } + + // Prohibit instantiation. + ThreadWithParamSupport(); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); +}; + +} // namespace + +ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, + Notification* thread_can_start) + : thread_(ThreadWithParamSupport::CreateThread(runnable, + thread_can_start)) { +} + +ThreadWithParamBase::~ThreadWithParamBase() { + Join(); +} + +void ThreadWithParamBase::Join() { + GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) + << "Failed to join the thread with error " << ::GetLastError() << "."; +} + +// Maps a thread to a set of ThreadIdToThreadLocals that have values +// instantiated on that thread and notifies them when the thread exits. A +// ThreadLocal instance is expected to persist until all threads it has +// values on have terminated. +class ThreadLocalRegistryImpl { + public: + // Registers thread_local_instance as having value on the current thread. + // Returns a value that can be used to identify the thread from other threads. + static ThreadLocalValueHolderBase* GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + DWORD current_thread = ::GetCurrentThreadId(); + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(current_thread); + if (thread_local_pos == thread_to_thread_locals->end()) { + thread_local_pos = thread_to_thread_locals->insert( + std::make_pair(current_thread, ThreadLocalValues())).first; + StartWatcherThreadFor(current_thread); + } + ThreadLocalValues& thread_local_values = thread_local_pos->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos == thread_local_values.end()) { + value_pos = + thread_local_values + .insert(std::make_pair( + thread_local_instance, + linked_ptr( + thread_local_instance->NewValueForCurrentThread()))) + .first; + } + return value_pos->second.get(); + } + + static void OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + std::vector > value_holders; + // Clean up the ThreadLocalValues data structure while holding the lock, but + // defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + for (ThreadIdToThreadLocals::iterator it = + thread_to_thread_locals->begin(); + it != thread_to_thread_locals->end(); + ++it) { + ThreadLocalValues& thread_local_values = it->second; + ThreadLocalValues::iterator value_pos = + thread_local_values.find(thread_local_instance); + if (value_pos != thread_local_values.end()) { + value_holders.push_back(value_pos->second); + thread_local_values.erase(value_pos); + // This 'if' can only be successful at most once, so theoretically we + // could break out of the loop here, but we don't bother doing so. + } + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + static void OnThreadExit(DWORD thread_id) { + GTEST_CHECK_(thread_id != 0) << ::GetLastError(); + std::vector > value_holders; + // Clean up the ThreadIdToThreadLocals data structure while holding the + // lock, but defer the destruction of the ThreadLocalValueHolderBases. + { + MutexLock lock(&mutex_); + ThreadIdToThreadLocals* const thread_to_thread_locals = + GetThreadLocalsMapLocked(); + ThreadIdToThreadLocals::iterator thread_local_pos = + thread_to_thread_locals->find(thread_id); + if (thread_local_pos != thread_to_thread_locals->end()) { + ThreadLocalValues& thread_local_values = thread_local_pos->second; + for (ThreadLocalValues::iterator value_pos = + thread_local_values.begin(); + value_pos != thread_local_values.end(); + ++value_pos) { + value_holders.push_back(value_pos->second); + } + thread_to_thread_locals->erase(thread_local_pos); + } + } + // Outside the lock, let the destructor for 'value_holders' deallocate the + // ThreadLocalValueHolderBases. + } + + private: + // In a particular thread, maps a ThreadLocal object to its value. + typedef std::map > ThreadLocalValues; + // Stores all ThreadIdToThreadLocals having values in a thread, indexed by + // thread's ID. + typedef std::map ThreadIdToThreadLocals; + + // Holds the thread id and thread handle that we pass from + // StartWatcherThreadFor to WatcherThreadFunc. + typedef std::pair ThreadIdAndHandle; + + static void StartWatcherThreadFor(DWORD thread_id) { + // The returned handle will be kept in thread_map and closed by + // watcher_thread in WatcherThreadFunc. + HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, + FALSE, + thread_id); + GTEST_CHECK_(thread != NULL); + // We need to pass a valid thread ID pointer into CreateThread for it + // to work correctly under Win98. + DWORD watcher_thread_id; + HANDLE watcher_thread = ::CreateThread( + NULL, // Default security. + 0, // Default stack size + &ThreadLocalRegistryImpl::WatcherThreadFunc, + reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), + CREATE_SUSPENDED, + &watcher_thread_id); + GTEST_CHECK_(watcher_thread != NULL); + // Give the watcher thread the same priority as ours to avoid being + // blocked by it. + ::SetThreadPriority(watcher_thread, + ::GetThreadPriority(::GetCurrentThread())); + ::ResumeThread(watcher_thread); + ::CloseHandle(watcher_thread); + } + + // Monitors exit from a given thread and notifies those + // ThreadIdToThreadLocals about thread termination. + static DWORD WINAPI WatcherThreadFunc(LPVOID param) { + const ThreadIdAndHandle* tah = + reinterpret_cast(param); + GTEST_CHECK_( + ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); + OnThreadExit(tah->first); + ::CloseHandle(tah->second); + delete tah; + return 0; + } + + // Returns map of thread local instances. + static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { + mutex_.AssertHeld(); + MemoryIsNotDeallocated memory_is_not_deallocated; + static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals(); + return map; + } + + // Protects access to GetThreadLocalsMapLocked() and its return value. + static Mutex mutex_; + // Protects access to GetThreadMapLocked() and its return value. + static Mutex thread_map_mutex_; +}; + +Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); +Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); + +ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( + const ThreadLocalBase* thread_local_instance) { + return ThreadLocalRegistryImpl::GetValueOnCurrentThread( + thread_local_instance); +} + +void ThreadLocalRegistry::OnThreadLocalDestroyed( + const ThreadLocalBase* thread_local_instance) { + ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); +} + +#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #if GTEST_USES_POSIX_RE @@ -247,7 +728,7 @@ bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { } // Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { +static std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } @@ -256,7 +737,7 @@ std::string FormatRegexSyntaxError(const char* regex, int index) { // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the + // FIXME: fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; @@ -481,7 +962,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( return file_name + ":" + StreamableToString(line); } - GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = @@ -500,12 +980,10 @@ GTestLog::~GTestLog() { posix::Abort(); } } + // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER +GTEST_DISABLE_MSC_DEPRECATED_PUSH_() #if GTEST_HAS_STREAM_REDIRECTION @@ -581,12 +1059,6 @@ class CapturedStream { } private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. @@ -595,44 +1067,14 @@ class CapturedStream { GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER +GTEST_DISABLE_MSC_DEPRECATED_POP_() static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { +static void CaptureStream(int fd, const char* stream_name, + CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; @@ -641,7 +1083,7 @@ void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { } // Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { +static std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; @@ -672,25 +1114,67 @@ std::string GetCapturedStderr() { #endif // GTEST_HAS_STREAM_REDIRECTION -#if GTEST_HAS_DEATH_TEST -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; + +size_t GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); } -const ::std::vector& GetInjectableArgvs() { +std::string ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +#if GTEST_HAS_DEATH_TEST +static const std::vector* g_injected_test_argvs = NULL; // Owned. + +std::vector GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } - return g_argvs; + return GetArgvs(); +} + +void SetInjectableArgvs(const std::vector* new_argvs) { + if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs; + g_injected_test_argvs = new_argvs; +} + +void SetInjectableArgvs(const std::vector& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} + +#if GTEST_HAS_GLOBAL_STRING +void SetInjectableArgvs(const std::vector< ::string>& new_argvs) { + SetInjectableArgvs( + new std::vector(new_argvs.begin(), new_argvs.end())); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void ClearInjectableArgvs() { + delete g_injected_test_argvs; + g_injected_test_argvs = NULL; } #endif // GTEST_HAS_DEATH_TEST @@ -764,16 +1248,23 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { +#if defined(GTEST_GET_BOOL_FROM_ENV_) + return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; +#endif // defined(GTEST_GET_BOOL_FROM_ENV_) } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { +#if defined(GTEST_GET_INT32_FROM_ENV_) + return GTEST_GET_INT32_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { @@ -791,14 +1282,36 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { } return result; +#endif // defined(GTEST_GET_INT32_FROM_ENV_) +} + +// As a special case for the 'output' flag, if GTEST_OUTPUT is not +// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build +// system. The value of XML_OUTPUT_FILE is a filename without the +// "xml:" prefix of GTEST_OUTPUT. +// Note that this is meant to be called at the call site so it does +// not check that the flag is 'output' +// In essence this checks an env variable called XML_OUTPUT_FILE +// and if it is set we prepend "xml:" to its value, if it not set we return "" +std::string OutputFlagAlsoCheckEnvVar(){ + std::string default_value_for_output_flag = ""; + const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE"); + if (NULL != xml_output_file_env) { + default_value_for_output_flag = std::string("xml:") + xml_output_file_env; + } + return default_value_for_output_flag; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { +#if defined(GTEST_GET_STRING_FROM_ENV_) + return GTEST_GET_STRING_FROM_ENV_(flag, default_value); +#else const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; +#endif // defined(GTEST_GET_STRING_FROM_ENV_) } } // namespace internal diff --git a/test/fmw/gtest/src/gtest-printers.cc b/test/fmw/gtest/src/gtest-printers.cc index 75fa4081009..de4d245e9fc 100644 --- a/test/fmw/gtest/src/gtest-printers.cc +++ b/test/fmw/gtest/src/gtest-printers.cc @@ -26,10 +26,9 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) -// Google Test - The Google C++ Testing Framework + +// Google Test - The Google C++ Testing and Mocking Framework // // This file implements a universal value printer that can print a // value of any type T: @@ -43,11 +42,13 @@ // defines Foo. #include "gtest/gtest-printers.h" -#include #include +#include +#include #include // NOLINT #include #include "gtest/internal/gtest-port.h" +#include "src/gtest-internal-inl.h" namespace testing { @@ -56,6 +57,9 @@ namespace { using ::std::ostream; // Prints a segment of bytes in the given object. +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; @@ -85,7 +89,7 @@ void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. - // TODO(wan): let the user control the threshold using a flag. + // FIXME: let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { @@ -119,7 +123,7 @@ namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a hexadecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, @@ -176,7 +180,10 @@ static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { *os << static_cast(c); return kAsIs; } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); + ostream::fmtflags flags = os->flags(); + *os << "\\x" << std::hex << std::uppercase + << static_cast(static_cast(c)); + os->flags(flags); return kHexEscape; } } @@ -223,7 +230,7 @@ void PrintCharAndCodeTo(Char c, ostream* os) { return; *os << " (" << static_cast(c); - // For more convenience, we print c's code again in hexidecimal, + // For more convenience, we print c's code again in hexadecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { @@ -252,11 +259,15 @@ void PrintTo(wchar_t wc, ostream* os) { // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template -static void PrintCharsAsStringTo( +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ +static CharFormat PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; + CharFormat print_format = kAsIs; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { @@ -266,13 +277,21 @@ static void PrintCharsAsStringTo( *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + // Remember if any characters required hex escaping. + if (is_previous_hex) { + print_format = kHexEscape; + } } *os << "\""; + return print_format; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template +GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ +GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ +GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code @@ -329,20 +348,95 @@ void PrintTo(const wchar_t* s, ostream* os) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, wcslen(s), os); + PrintCharsAsStringTo(s, std::wcslen(s), os); } } #endif // wchar_t is native +namespace { + +bool ContainsUnprintableControlCodes(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length; i++) { + unsigned char ch = *s++; + if (std::iscntrl(ch)) { + switch (ch) { + case '\t': + case '\n': + case '\r': + break; + default: + return true; + } + } + } + return false; +} + +bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; } + +bool IsValidUTF8(const char* str, size_t length) { + const unsigned char *s = reinterpret_cast(str); + + for (size_t i = 0; i < length;) { + unsigned char lead = s[i++]; + + if (lead <= 0x7f) { + continue; // single-byte character (ASCII) 0..7F + } + if (lead < 0xc2) { + return false; // trail byte or non-shortest form + } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) { + ++i; // 2-byte character + } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + // check for non-shortest form and surrogate + (lead != 0xe0 || s[i] >= 0xa0) && + (lead != 0xed || s[i] < 0xa0)) { + i += 2; // 3-byte character + } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length && + IsUTF8TrailByte(s[i]) && + IsUTF8TrailByte(s[i + 1]) && + IsUTF8TrailByte(s[i + 2]) && + // check for non-shortest form + (lead != 0xf0 || s[i] >= 0x90) && + (lead != 0xf4 || s[i] < 0x90)) { + i += 3; // 4-byte character + } else { + return false; + } + } + return true; +} + +void ConditionalPrintAsText(const char* str, size_t length, ostream* os) { + if (!ContainsUnprintableControlCodes(str, length) && + IsValidUTF8(str, length)) { + *os << "\n As Text: \"" << str << "\""; + } +} + +} // anonymous namespace + // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); + if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) { + if (GTEST_FLAG(print_utf8)) { + ConditionalPrintAsText(s.data(), s.size(), os); + } + } } // Prints a ::wstring object. diff --git a/test/fmw/gtest/src/gtest-test-part.cc b/test/fmw/gtest/src/gtest-test-part.cc index c60eef3ab35..c88860d9238 100644 --- a/test/fmw/gtest/src/gtest-test-part.cc +++ b/test/fmw/gtest/src/gtest-test-part.cc @@ -26,21 +26,12 @@ // 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. + // -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest-test-part.h" - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ namespace testing { diff --git a/test/fmw/gtest/src/gtest-typed-test.cc b/test/fmw/gtest/src/gtest-typed-test.cc index f0079f407c5..1dc2ad38bab 100644 --- a/test/fmw/gtest/src/gtest-typed-test.cc +++ b/test/fmw/gtest/src/gtest-typed-test.cc @@ -26,10 +26,10 @@ // 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. -// -// Author: wan@google.com (Zhanyong Wan) + #include "gtest/gtest-typed-test.h" + #include "gtest/gtest.h" namespace testing { @@ -45,33 +45,41 @@ static const char* SkipSpaces(const char* str) { return str; } +static std::vector SplitIntoTestNames(const char* src) { + std::vector name_vec; + src = SkipSpaces(src); + for (; src != NULL; src = SkipComma(src)) { + name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); + } + return name_vec; +} + // Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or +// registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; + typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); + std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const std::string name = GetPrefixUntilComma(names); + + std::set tests; + for (std::vector::const_iterator name_it = name_vec.begin(); + name_it != name_vec.end(); ++name_it) { + const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (name == *it) { + if (name == it->first) { found = true; break; } @@ -85,11 +93,11 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames( } } - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); + for (RegisteredTestIter it = registered_tests_.begin(); + it != registered_tests_.end(); ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; + if (tests.count(it->first) == 0) { + errors << "You forgot to list test " << it->first << ".\n"; } } diff --git a/test/fmw/gtest/src/gtest.cc b/test/fmw/gtest/src/gtest.cc index 4c4ee86fe39..2b7393da679 100644 --- a/test/fmw/gtest/src/gtest.cc +++ b/test/fmw/gtest/src/gtest.cc @@ -26,12 +26,12 @@ // 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. + // -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) +// The Google C++ Testing and Mocking Framework (Google Test) #include "gtest/gtest.h" +#include "gtest/internal/custom/gtest.h" #include "gtest/gtest-spi.h" #include @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include // NOLINT #include #include @@ -55,7 +57,7 @@ #if GTEST_OS_LINUX -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -83,6 +85,7 @@ #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT +# undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. @@ -93,9 +96,9 @@ # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on +// FIXME: There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -105,11 +108,12 @@ // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT +# undef min #else // Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of +// FIXME: Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 @@ -127,21 +131,29 @@ #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT +# include // NOLINT +# include // NOLINT #endif -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 #include "src/gtest-internal-inl.h" -#undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS +#include +#endif +#endif + +#if GTEST_HAS_ABSL +#include "absl/debugging/failure_signal_handler.h" +#include "absl/debugging/stacktrace.h" +#include "absl/debugging/symbolize.h" +#include "absl/strings/str_cat.h" +#endif // GTEST_HAS_ABSL + namespace testing { using internal::CountIf; @@ -163,8 +175,10 @@ static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; +// The default output format. +static const char kDefaultOutputFormat[] = "xml"; +// The default output file. +static const char kDefaultOutputFile[] = "test_detail"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; @@ -183,9 +197,31 @@ const char kStackTraceMarker[] = "\nStack trace:\n"; // specified on the command line. bool g_help_flag = false; +// Utilty function to Open File for Writing +static FILE* OpenFileForWriting(const std::string& output_file) { + FILE* fileout = NULL; + FilePath output_file_path(output_file); + FilePath output_dir(output_file_path.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + fileout = posix::FOpen(output_file.c_str(), "w"); + } + if (fileout == NULL) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\""; + } + return fileout; +} + } // namespace internal +// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY +// environment variable. static const char* GetDefaultFilter() { + const char* const testbridge_test_only = + internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY"); + if (testbridge_test_only != NULL) { + return testbridge_test_only; + } return kUniversalFilter; } @@ -222,15 +258,28 @@ GTEST_DEFINE_string_( "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); +GTEST_DEFINE_bool_( + install_failure_signal_handler, + internal::BoolFromGTestEnv("install_failure_signal_handler", false), + "If true and supported on the current platform, " GTEST_NAME_ " should " + "install a signal handler that dumps debugging information when fatal " + "signals are raised."); + GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); +// The net priority order after flag processing is thus: +// --gtest_output command line flag +// GTEST_OUTPUT environment variable +// XML_OUTPUT_FILE environment variable +// '' GTEST_DEFINE_string_( output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " + internal::StringFromGTestEnv("output", + internal::OutputFlagAlsoCheckEnvVar().c_str()), + "A format (defaults to \"xml\" but can be specified to be \"json\"), " + "optionally followed by a colon and an output file name or directory. " + "A directory is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " @@ -243,6 +292,12 @@ GTEST_DEFINE_bool_( "True iff " GTEST_NAME_ " should display elapsed time in text output."); +GTEST_DEFINE_bool_( + print_utf8, + internal::BoolFromGTestEnv("print_utf8", true), + "True iff " GTEST_NAME_ + " prints UTF8 characters as text."); + GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), @@ -284,7 +339,14 @@ GTEST_DEFINE_bool_( internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); + "otherwise. For use with an external test framework."); + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +GTEST_DEFINE_string_( + flagfile, + internal::StringFromGTestEnv("flagfile", ""), + "This flag specifies the flagfile to read command-line flags from."); +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ namespace internal { @@ -293,7 +355,8 @@ namespace internal { // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; + // Use wider types than necessary to prevent unsigned overflow diagnostics. + state_ = static_cast(1103515245ULL*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; @@ -310,13 +373,7 @@ UInt32 Random::Generate(UInt32 range) { // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } +static bool GTestIsInitialized() { return GetArgvs().size() > 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. @@ -372,8 +429,19 @@ void AssertHelper::operator=(const Message& message) const { // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; +// A copy of all command line arguments. Set by InitGoogleTest(). +static ::std::vector g_argvs; + +::std::vector GetArgvs() { +#if defined(GTEST_CUSTOM_GET_ARGVS_) + // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or + // ::string. This code converts it to the appropriate type. + const auto& custom = GTEST_CUSTOM_GET_ARGVS_(); + return ::std::vector(custom.begin(), custom.end()); +#else // defined(GTEST_CUSTOM_GET_ARGVS_) + return g_argvs; +#endif // defined(GTEST_CUSTOM_GET_ARGVS_) +} // Returns the current application's name, removing directory path if that // is present. @@ -381,9 +449,9 @@ FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); + result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else - result.Set(FilePath(g_executable_path)); + result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); @@ -394,8 +462,6 @@ FilePath GetCurrentExecutableName() { // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : @@ -406,19 +472,22 @@ std::string UnitTestOptions::GetOutputFormat() { // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; + + std::string format = GetOutputFormat(); + if (format.empty()) + format = std::string(kDefaultOutputFormat); const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) - return internal::FilePath::ConcatPaths( + return internal::FilePath::MakeFileName( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); + internal::FilePath(kDefaultOutputFile), 0, + format.c_str()).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute + // FIXME: on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. @@ -609,12 +678,12 @@ extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { +static AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const std::string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); @@ -648,13 +717,10 @@ AssertionResult HasOneFailure(const char* /* results_expr */, // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} +SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const std::string& substr) + : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given @@ -775,8 +841,12 @@ int UnitTestImpl::test_to_run_count() const { // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; + return os_stack_trace_getter()->CurrentStackTrace( + static_cast(GTEST_FLAG(stack_trace_depth)), + skip_count + 1 + // Skips the user-specified number of frames plus this function + // itself. + ); // NOLINT } // Returns the current time in milliseconds. @@ -791,7 +861,7 @@ TimeInMillis GetTimeInMillis() { SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use + // FIXME: Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { @@ -805,21 +875,13 @@ TimeInMillis GetTimeInMillis() { #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; -# ifdef _MSC_VER - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use + // FIXME: Use GetTickCount()? Or use // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. + GTEST_DISABLE_MSC_DEPRECATED_PUSH_() _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - - _ftime64(&now); - -# endif // _MSC_VER + GTEST_DISABLE_MSC_DEPRECATED_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ @@ -904,6 +966,23 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING +void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + } // namespace internal // Constructs an empty Message. @@ -959,6 +1038,13 @@ AssertionResult::AssertionResult(const AssertionResult& other) static_cast< ::std::string*>(NULL)) { } +// Swaps two AssertionResults. +void AssertionResult::swap(AssertionResult& other) { + using std::swap; + swap(success_, other.success_); + swap(message_, other.message_); +} + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); @@ -985,6 +1071,276 @@ AssertionResult AssertionFailure(const Message& message) { namespace internal { +namespace edit_distance { +std::vector CalculateOptimalEdits(const std::vector& left, + const std::vector& right) { + std::vector > costs( + left.size() + 1, std::vector(right.size() + 1)); + std::vector > best_move( + left.size() + 1, std::vector(right.size() + 1)); + + // Populate for empty right. + for (size_t l_i = 0; l_i < costs.size(); ++l_i) { + costs[l_i][0] = static_cast(l_i); + best_move[l_i][0] = kRemove; + } + // Populate for empty left. + for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { + costs[0][r_i] = static_cast(r_i); + best_move[0][r_i] = kAdd; + } + + for (size_t l_i = 0; l_i < left.size(); ++l_i) { + for (size_t r_i = 0; r_i < right.size(); ++r_i) { + if (left[l_i] == right[r_i]) { + // Found a match. Consume it. + costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; + best_move[l_i + 1][r_i + 1] = kMatch; + continue; + } + + const double add = costs[l_i + 1][r_i]; + const double remove = costs[l_i][r_i + 1]; + const double replace = costs[l_i][r_i]; + if (add < remove && add < replace) { + costs[l_i + 1][r_i + 1] = add + 1; + best_move[l_i + 1][r_i + 1] = kAdd; + } else if (remove < add && remove < replace) { + costs[l_i + 1][r_i + 1] = remove + 1; + best_move[l_i + 1][r_i + 1] = kRemove; + } else { + // We make replace a little more expensive than add/remove to lower + // their priority. + costs[l_i + 1][r_i + 1] = replace + 1.00001; + best_move[l_i + 1][r_i + 1] = kReplace; + } + } + } + + // Reconstruct the best path. We do it in reverse order. + std::vector best_path; + for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { + EditType move = best_move[l_i][r_i]; + best_path.push_back(move); + l_i -= move != kAdd; + r_i -= move != kRemove; + } + std::reverse(best_path.begin(), best_path.end()); + return best_path; +} + +namespace { + +// Helper class to convert string into ids with deduplication. +class InternalStrings { + public: + size_t GetId(const std::string& str) { + IdMap::iterator it = ids_.find(str); + if (it != ids_.end()) return it->second; + size_t id = ids_.size(); + return ids_[str] = id; + } + + private: + typedef std::map IdMap; + IdMap ids_; +}; + +} // namespace + +std::vector CalculateOptimalEdits( + const std::vector& left, + const std::vector& right) { + std::vector left_ids, right_ids; + { + InternalStrings intern_table; + for (size_t i = 0; i < left.size(); ++i) { + left_ids.push_back(intern_table.GetId(left[i])); + } + for (size_t i = 0; i < right.size(); ++i) { + right_ids.push_back(intern_table.GetId(right[i])); + } + } + return CalculateOptimalEdits(left_ids, right_ids); +} + +namespace { + +// Helper class that holds the state for one hunk and prints it out to the +// stream. +// It reorders adds/removes when possible to group all removes before all +// adds. It also adds the hunk header before printint into the stream. +class Hunk { + public: + Hunk(size_t left_start, size_t right_start) + : left_start_(left_start), + right_start_(right_start), + adds_(), + removes_(), + common_() {} + + void PushLine(char edit, const char* line) { + switch (edit) { + case ' ': + ++common_; + FlushEdits(); + hunk_.push_back(std::make_pair(' ', line)); + break; + case '-': + ++removes_; + hunk_removes_.push_back(std::make_pair('-', line)); + break; + case '+': + ++adds_; + hunk_adds_.push_back(std::make_pair('+', line)); + break; + } + } + + void PrintTo(std::ostream* os) { + PrintHeader(os); + FlushEdits(); + for (std::list >::const_iterator it = + hunk_.begin(); + it != hunk_.end(); ++it) { + *os << it->first << it->second << "\n"; + } + } + + bool has_edits() const { return adds_ || removes_; } + + private: + void FlushEdits() { + hunk_.splice(hunk_.end(), hunk_removes_); + hunk_.splice(hunk_.end(), hunk_adds_); + } + + // Print a unified diff header for one hunk. + // The format is + // "@@ -, +, @@" + // where the left/right parts are omitted if unnecessary. + void PrintHeader(std::ostream* ss) const { + *ss << "@@ "; + if (removes_) { + *ss << "-" << left_start_ << "," << (removes_ + common_); + } + if (removes_ && adds_) { + *ss << " "; + } + if (adds_) { + *ss << "+" << right_start_ << "," << (adds_ + common_); + } + *ss << " @@\n"; + } + + size_t left_start_, right_start_; + size_t adds_, removes_, common_; + std::list > hunk_, hunk_adds_, hunk_removes_; +}; + +} // namespace + +// Create a list of diff hunks in Unified diff format. +// Each hunk has a header generated by PrintHeader above plus a body with +// lines prefixed with ' ' for no change, '-' for deletion and '+' for +// addition. +// 'context' represents the desired unchanged prefix/suffix around the diff. +// If two hunks are close enough that their contexts overlap, then they are +// joined into one hunk. +std::string CreateUnifiedDiff(const std::vector& left, + const std::vector& right, + size_t context) { + const std::vector edits = CalculateOptimalEdits(left, right); + + size_t l_i = 0, r_i = 0, edit_i = 0; + std::stringstream ss; + while (edit_i < edits.size()) { + // Find first edit. + while (edit_i < edits.size() && edits[edit_i] == kMatch) { + ++l_i; + ++r_i; + ++edit_i; + } + + // Find the first line to include in the hunk. + const size_t prefix_context = std::min(l_i, context); + Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); + for (size_t i = prefix_context; i > 0; --i) { + hunk.PushLine(' ', left[l_i - i].c_str()); + } + + // Iterate the edits until we found enough suffix for the hunk or the input + // is over. + size_t n_suffix = 0; + for (; edit_i < edits.size(); ++edit_i) { + if (n_suffix >= context) { + // Continue only if the next hunk is very close. + std::vector::const_iterator it = edits.begin() + edit_i; + while (it != edits.end() && *it == kMatch) ++it; + if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { + // There is no next edit or it is too far away. + break; + } + } + + EditType edit = edits[edit_i]; + // Reset count when a non match is found. + n_suffix = edit == kMatch ? n_suffix + 1 : 0; + + if (edit == kMatch || edit == kRemove || edit == kReplace) { + hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); + } + if (edit == kAdd || edit == kReplace) { + hunk.PushLine('+', right[r_i].c_str()); + } + + // Advance indices, depending on edit type. + l_i += edit != kAdd; + r_i += edit != kRemove; + } + + if (!hunk.has_edits()) { + // We are done. We don't want this hunk. + break; + } + + hunk.PrintTo(&ss); + } + return ss.str(); +} + +} // namespace edit_distance + +namespace { + +// The string representation of the values received in EqFailure() are already +// escaped. Split them on escaped '\n' boundaries. Leave all other escaped +// characters the same. +std::vector SplitEscapedString(const std::string& str) { + std::vector lines; + size_t start = 0, end = str.size(); + if (end > 2 && str[0] == '"' && str[end - 1] == '"') { + ++start; + --end; + } + bool escaped = false; + for (size_t i = start; i + 1 < end; ++i) { + if (escaped) { + escaped = false; + if (str[i] == 'n') { + lines.push_back(str.substr(start, i - start - 1)); + start = i + 1; + } + } else { + escaped = str[i] == '\\'; + } + } + lines.push_back(str.substr(start, end - start)); + return lines; +} + +} // namespace + // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // @@ -992,31 +1348,43 @@ namespace internal { // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" +// lhs_expression: "foo" +// rhs_expression: "bar" +// lhs_value: "5" +// rhs_value: "6" // // The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// *_STRCASEEQ*. When it's true, the string "Ignoring case" will // be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, +AssertionResult EqFailure(const char* lhs_expression, + const char* rhs_expression, + const std::string& lhs_value, + const std::string& rhs_value, bool ignoring_case) { Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; + msg << "Expected equality of these values:"; + msg << "\n " << lhs_expression; + if (lhs_value != lhs_expression) { + msg << "\n Which is: " << lhs_value; + } + msg << "\n " << rhs_expression; + if (rhs_value != rhs_expression) { + msg << "\n Which is: " << rhs_value; } - msg << "\nExpected: " << expected_expression; if (ignoring_case) { - msg << " (ignoring case)"; + msg << "\nIgnoring case"; } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; + + if (!lhs_value.empty() && !rhs_value.empty()) { + const std::vector lhs_lines = + SplitEscapedString(lhs_value); + const std::vector rhs_lines = + SplitEscapedString(rhs_value); + if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { + msg << "\nWith diff:\n" + << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); + } } return AssertionFailure() << msg; @@ -1048,7 +1416,7 @@ AssertionResult DoubleNearPredFormat(const char* expr1, const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); - // TODO(wan): do not print the value of an expression if it's + // FIXME: do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 @@ -1114,18 +1482,18 @@ namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { +AssertionResult CmpHelperEQ(const char* lhs_expression, + const char* rhs_expression, + BiggestInt lhs, + BiggestInt rhs) { + if (lhs == rhs) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), + return EqFailure(lhs_expression, + rhs_expression, + FormatForComparisonFailureMessage(lhs, rhs), + FormatForComparisonFailureMessage(rhs, lhs), false); } @@ -1164,34 +1532,34 @@ GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, + const char* rhs_expression, + const char* lhs, + const char* rhs) { + if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), true); } @@ -1343,7 +1711,7 @@ namespace { AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; @@ -1400,7 +1768,7 @@ AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT // Utility functions for encoding Unicode text (wide strings) in // UTF-8. -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding @@ -1464,7 +1832,7 @@ std::string CodePointToUtf8(UInt32 code_point) { return str; } -// The following two functions only make sense if the the system +// The following two functions only make sense if the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. @@ -1546,18 +1914,18 @@ bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { } // Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { +AssertionResult CmpHelperSTREQ(const char* lhs_expression, + const char* rhs_expression, + const wchar_t* lhs, + const wchar_t* rhs) { + if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), + return EqFailure(lhs_expression, + rhs_expression, + PrintToString(lhs), + PrintToString(rhs), false); } @@ -1776,13 +2144,8 @@ static const char* const kReservedTestSuiteAttributes[] = { // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; + "classname", "name", "status", "time", + "type_param", "value_param", "file", "line"}; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { @@ -1818,8 +2181,9 @@ static std::string FormatWordList(const std::vector& words) { return word_list.GetString(); } -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { +static bool ValidateTestPropertyName( + const std::string& property_name, + const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name @@ -1890,14 +2254,15 @@ int TestResult::test_property_count() const { // Creates a Test object. -// The c'tor saves the values of all Google Test flags. +// The c'tor saves the states of all flags. Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { + : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } -// The d'tor restores the values of all Google Test flags. +// The d'tor restores the states of all flags. The actual work is +// done by the d'tor of the gtest_flag_saver_ field, and thus not +// visible here. Test::~Test() { - delete gtest_flag_saver_; } // Sets up the test fixture. @@ -1966,8 +2331,8 @@ bool Test::HasSameFixtureClass() { const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. + // Both TEST and TEST_F appear in same test case, which is incorrect. + // Tell the user how to fix this. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as @@ -1987,8 +2352,8 @@ bool Test::HasSameFixtureClass() { << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. + // Two fixture classes with the same name appear in two different + // namespaces, which is not allowed. Tell the user how to fix this. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " @@ -2115,6 +2480,8 @@ Result HandleExceptionsInMethodIfSupported( #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const AssertionException&) { // NOLINT + // This failure was reported already. } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing @@ -2181,12 +2548,14 @@ TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, + internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), + location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), @@ -2210,6 +2579,7 @@ namespace internal { // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. +// code_location: code location where the test is defined // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case @@ -2221,20 +2591,20 @@ TestInfo* MakeAndRegisterTestInfo( const char* name, const char* type_param, const char* value_param, + CodeLocation code_location, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); + code_location, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } -#if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { + CodeLocation code_location) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" @@ -2246,11 +2616,10 @@ void ReportInvalidTestCaseType(const char* test_case_name, << "probably rename one of the classes to put the tests into different\n" << "test cases."; - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); + GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(), + code_location.line) + << " " << errors.GetString(); } -#endif // GTEST_HAS_PARAM_TEST - } // namespace internal namespace { @@ -2288,12 +2657,10 @@ namespace internal { // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } -#endif } } // namespace internal @@ -2321,18 +2688,18 @@ void TestInfo::Run() { factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { + // Runs the test if the constructor didn't generate a fatal failure. + // Note that the object will not be null + if (!Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); @@ -2557,10 +2924,11 @@ enum GTestColor { COLOR_YELLOW }; -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW // Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { +static WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -2569,11 +2937,42 @@ WORD GetColorAttribute(GTestColor color) { } } +static int GetBitOffset(WORD color_mask) { + if (color_mask == 0) return 0; + + int bitOffset = 0; + while ((color_mask & 1) == 0) { + color_mask >>= 1; + ++bitOffset; + } + return bitOffset; +} + +static WORD GetNewColor(GTestColor color, WORD old_color_attrs) { + // Let's reuse the BG + static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN | + BACKGROUND_RED | BACKGROUND_INTENSITY; + static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_RED | FOREGROUND_INTENSITY; + const WORD existing_bg = old_color_attrs & background_mask; + + WORD new_color = + GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY; + static const int bg_bitOffset = GetBitOffset(background_mask); + static const int fg_bitOffset = GetBitOffset(foreground_mask); + + if (((new_color & background_mask) >> bg_bitOffset) == + ((new_color & foreground_mask) >> fg_bitOffset)) { + new_color ^= FOREGROUND_INTENSITY; // invert intensity + } + return new_color; +} + #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. -const char* GetAnsiColorCode(GTestColor color) { +static const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; @@ -2589,7 +2988,7 @@ bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; @@ -2602,6 +3001,10 @@ bool ShouldUseColor(bool stdout_is_tty) { String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "tmux") || + String::CStringEquals(term, "tmux-256color") || + String::CStringEquals(term, "rxvt-unicode") || + String::CStringEquals(term, "rxvt-unicode-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; @@ -2621,12 +3024,13 @@ bool ShouldUseColor(bool stdout_is_tty) { // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { +static void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS - const bool use_color = false; +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \ + GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT + const bool use_color = AlwaysFalse(); #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); @@ -2640,20 +3044,22 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { return; } -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ + !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; + const WORD new_color = GetNewColor(color, old_color_attrs); // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); + SetConsoleTextAttribute(stdout_handle, new_color); + vprintf(fmt, args); fflush(stdout); @@ -2667,12 +3073,12 @@ void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_end(args); } -// Text printed in Google Test's text output and --gunit_list_tests +// Text printed in Google Test's text output and --gtest_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { +static void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); @@ -2943,7 +3349,7 @@ void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +// FIXME: Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { @@ -3017,6 +3423,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + void ListTestsMatchingFilter(const std::vector& test_cases); + + // Prints an XML summary of all unit tests. + static void PrintXmlTestsList(std::ostream* stream, + const std::vector& test_cases); private: // Is c a whitespace character that is normalized to a space character @@ -3078,6 +3489,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + // Streams an XML representation of the test properties of a TestResult + // object. + static void OutputXmlTestProperties(std::ostream* stream, + const TestResult& result); + // The output file. const std::string output_file_; @@ -3087,46 +3503,30 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "XML output file may not be null"; } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } + FILE* xmlout = OpenFileForWriting(output_file_); std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } +void XmlUnitTestResultPrinter::ListTestsMatchingFilter( + const std::vector& test_cases) { + FILE* xmlout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintXmlTestsList(&stream, test_cases); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character @@ -3137,7 +3537,7 @@ void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable +// FIXME: It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { @@ -3198,6 +3598,7 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // The following routines generate an XML representation of a UnitTest // object. +// GOOGLETEST_CM0009 DO NOT DELETE // // This is how Google Test concepts map to the DTD: // @@ -3215,34 +3616,39 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; - ss << ms/1000.0; + ss << (static_cast(ms) * 1e-3); return ss.str(); } +static bool PortableLocaltime(time_t seconds, struct tm* out) { +#if defined(_MSC_VER) + return localtime_s(out, &seconds) == 0; +#elif defined(__MINGW32__) || defined(__MINGW64__) + // MINGW provides neither localtime_r nor localtime_s, but uses + // Windows' localtime(), which has a thread-local tm buffer. + struct tm* tm_ptr = localtime(&seconds); // NOLINT + if (tm_ptr == NULL) + return false; + *out = *tm_ptr; + return true; +#else + return localtime_r(&seconds, out) != NULL; +#endif +} + // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - // Using non-reentrant version as localtime_r is not portable. - time_t seconds = static_cast(ms / 1000); -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe). - const struct tm* const time_struct = localtime(&seconds); // NOLINT -# pragma warning(pop) // Restores the warning state again. -#else - const struct tm* const time_struct = localtime(&seconds); // NOLINT -#endif - if (time_struct == NULL) - return ""; // Invalid ms value - + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. @@ -3282,13 +3688,17 @@ void XmlUnitTestResultPrinter::OutputXmlAttribute( } // Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. +// FIXME: There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; + if (test_info.is_in_another_shard()) { + return; + } + *stream << " \n"; + return; + } OutputXmlAttribute(stream, kTestcase, "status", test_info.should_run() ? "run" : "notrun"); OutputXmlAttribute(stream, kTestcase, "time", FormatTimeInMillisAsSeconds(result.elapsed_time())); OutputXmlAttribute(stream, kTestcase, "classname", test_case_name); - *stream << TestPropertiesAsXmlAttributes(result); int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { @@ -3314,22 +3730,28 @@ void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, if (++failures == 1) { *stream << ">\n"; } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string summary = location + "\n" + part.summary(); *stream << " "; - const string detail = location + "\n" + part.message(); + const std::string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } - if (failures == 0) + if (failures == 0 && result.test_property_count() == 0) { *stream << " />\n"; - else + } else { + if (failures == 0) { + *stream << ">\n"; + } + OutputXmlTestProperties(stream, result); *stream << " \n"; + } } // Prints an XML representation of a TestCase object @@ -3340,17 +3762,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - + if (!GTEST_FLAG(list_tests)) { + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()); + } + *stream << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); @@ -3384,7 +3807,6 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); @@ -3397,6 +3819,28 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, *stream << "\n"; } +void XmlUnitTestResultPrinter::PrintXmlTestsList( + std::ostream* stream, const std::vector& test_cases) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(total_tests)); + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + PrintXmlTestCase(stream, *test_cases[i]); + } + *stream << "\n"; +} + // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( @@ -3410,8 +3854,390 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( return attributes.GetString(); } +void XmlUnitTestResultPrinter::OutputXmlTestProperties( + std::ostream* stream, const TestResult& result) { + const std::string kProperties = "properties"; + const std::string kProperty = "property"; + + if (result.test_property_count() <= 0) { + return; + } + + *stream << "<" << kProperties << ">\n"; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + *stream << "<" << kProperty; + *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; + *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; + *stream << "/>\n"; + } + *stream << "\n"; +} + // End XmlUnitTestResultPrinter +// This class generates an JSON output file. +class JsonUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit JsonUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + // Prints an JSON summary of all unit tests. + static void PrintJsonTestList(::std::ostream* stream, + const std::vector& test_cases); + + private: + // Returns an JSON-escaped copy of the input string str. + static std::string EscapeJson(const std::string& str); + + //// Verifies that the given attribute belongs to the given element and + //// streams the attribute as JSON. + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma = true); + static void OutputJsonKey(std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma = true); + + // Streams a JSON representation of a TestInfo object. + static void OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints a JSON representation of a TestCase object + static void PrintJsonTestCase(::std::ostream* stream, + const TestCase& test_case); + + // Prints a JSON summary of unit_test to output stream out. + static void PrintJsonUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as + // a JSON dictionary. + static std::string TestPropertiesAsJson(const TestResult& result, + const std::string& indent); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter); +}; + +// Creates a new JsonUnitTestResultPrinter. +JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.empty()) { + GTEST_LOG_(FATAL) << "JSON output file may not be null"; + } +} + +void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* jsonout = OpenFileForWriting(output_file_); + std::stringstream stream; + PrintJsonUnitTest(&stream, unit_test); + fprintf(jsonout, "%s", StringStreamToString(&stream).c_str()); + fclose(jsonout); +} + +// Returns an JSON-escaped copy of the input string str. +std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '\\': + case '"': + case '/': + m << '\\' << ch; + break; + case '\b': + m << "\\b"; + break; + case '\t': + m << "\\t"; + break; + case '\n': + m << "\\n"; + break; + case '\f': + m << "\\f"; + break; + case '\r': + m << "\\r"; + break; + default: + if (ch < ' ') { + m << "\\u00" << String::FormatByte(static_cast(ch)); + } else { + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// The following routines generate an JSON representation of a UnitTest +// object. + +// Formats the given time in milliseconds as seconds. +static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) { + ::std::stringstream ss; + ss << (static_cast(ms) * 1e-3) << "s"; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the +// RFC3339 format, without the timezone information. +static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) { + struct tm time_struct; + if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) + return ""; + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct.tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct.tm_mday) + "T" + + String::FormatIntWidth2(time_struct.tm_hour) + ":" + + String::FormatIntWidth2(time_struct.tm_min) + ":" + + String::FormatIntWidth2(time_struct.tm_sec) + "Z"; +} + +static inline std::string Indent(int width) { + return std::string(width, ' '); +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\""; + if (comma) + *stream << ",\n"; +} + +void JsonUnitTestResultPrinter::OutputJsonKey( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + int value, + const std::string& indent, + bool comma) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Key \"" << name << "\" is not allowed for value \"" << element_name + << "\"."; + + *stream << indent << "\"" << name << "\": " << StreamableToString(value); + if (comma) + *stream << ",\n"; +} + +// Prints a JSON representation of a TestInfo object. +void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestcase = "testcase"; + const std::string kIndent = Indent(10); + + *stream << Indent(8) << "{\n"; + OutputJsonKey(stream, kTestcase, "name", test_info.name(), kIndent); + + if (test_info.value_param() != NULL) { + OutputJsonKey(stream, kTestcase, "value_param", + test_info.value_param(), kIndent); + } + if (test_info.type_param() != NULL) { + OutputJsonKey(stream, kTestcase, "type_param", test_info.type_param(), + kIndent); + } + if (GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestcase, "file", test_info.file(), kIndent); + OutputJsonKey(stream, kTestcase, "line", test_info.line(), kIndent, false); + *stream << "\n" << Indent(8) << "}"; + return; + } + + OutputJsonKey(stream, kTestcase, "status", + test_info.should_run() ? "RUN" : "NOTRUN", kIndent); + OutputJsonKey(stream, kTestcase, "time", + FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent); + OutputJsonKey(stream, kTestcase, "classname", test_case_name, kIndent, false); + *stream << TestPropertiesAsJson(result, kIndent); + + int failures = 0; + for (int i = 0; i < result.total_part_count(); ++i) { + const TestPartResult& part = result.GetTestPartResult(i); + if (part.failed()) { + *stream << ",\n"; + if (++failures == 1) { + *stream << kIndent << "\"" << "failures" << "\": [\n"; + } + const std::string location = + internal::FormatCompilerIndependentFileLocation(part.file_name(), + part.line_number()); + const std::string message = EscapeJson(location + "\n" + part.message()); + *stream << kIndent << " {\n" + << kIndent << " \"failure\": \"" << message << "\",\n" + << kIndent << " \"type\": \"\"\n" + << kIndent << " }"; + } + } + + if (failures > 0) + *stream << "\n" << kIndent << "]"; + *stream << "\n" << Indent(8) << "}"; +} + +// Prints an JSON representation of a TestCase object +void JsonUnitTestResultPrinter::PrintJsonTestCase(std::ostream* stream, + const TestCase& test_case) { + const std::string kTestsuite = "testsuite"; + const std::string kIndent = Indent(6); + + *stream << Indent(4) << "{\n"; + OutputJsonKey(stream, kTestsuite, "name", test_case.name(), kIndent); + OutputJsonKey(stream, kTestsuite, "tests", test_case.reportable_test_count(), + kIndent); + if (!GTEST_FLAG(list_tests)) { + OutputJsonKey(stream, kTestsuite, "failures", test_case.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuite, "disabled", + test_case.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent); + OutputJsonKey(stream, kTestsuite, "time", + FormatTimeInMillisAsDuration(test_case.elapsed_time()), + kIndent, false); + *stream << TestPropertiesAsJson(test_case.ad_hoc_test_result(), kIndent) + << ",\n"; + } + + *stream << kIndent << "\"" << kTestsuite << "\": [\n"; + + bool comma = false; + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + OutputJsonTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; +} + +// Prints a JSON summary of unit_test to output stream out. +void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + + OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(), + kIndent); + OutputJsonKey(stream, kTestsuites, "disabled", + unit_test.reportable_disabled_test_count(), kIndent); + OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent); + if (GTEST_FLAG(shuffle)) { + OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(), + kIndent); + } + OutputJsonKey(stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()), + kIndent); + OutputJsonKey(stream, kTestsuites, "time", + FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent, + false); + + *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent) + << ",\n"; + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + bool comma = false; + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) { + if (comma) { + *stream << ",\n"; + } else { + comma = true; + } + PrintJsonTestCase(stream, *unit_test.GetTestCase(i)); + } + } + + *stream << "\n" << kIndent << "]\n" << "}\n"; +} + +void JsonUnitTestResultPrinter::PrintJsonTestList( + std::ostream* stream, const std::vector& test_cases) { + const std::string kTestsuites = "testsuites"; + const std::string kIndent = Indent(2); + *stream << "{\n"; + int total_tests = 0; + for (size_t i = 0; i < test_cases.size(); ++i) { + total_tests += test_cases[i]->total_test_count(); + } + OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent); + + OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent); + *stream << kIndent << "\"" << kTestsuites << "\": [\n"; + + for (size_t i = 0; i < test_cases.size(); ++i) { + if (i != 0) { + *stream << ",\n"; + } + PrintJsonTestCase(stream, *test_cases[i]); + } + + *stream << "\n" + << kIndent << "]\n" + << "}\n"; +} +// Produces a string representing the test properties in a result as +// a JSON dictionary. +std::string JsonUnitTestResultPrinter::TestPropertiesAsJson( + const TestResult& result, const std::string& indent) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << ",\n" << indent << "\"" << property.key() << "\": " + << "\"" << EscapeJson(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End JsonUnitTestResultPrinter + #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, @@ -3419,8 +4245,8 @@ std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; +std::string StreamingListener::UrlEncode(const char* str) { + std::string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { @@ -3482,58 +4308,82 @@ void StreamingListener::SocketWriter::MakeConnection() { // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} - - // class OsStackTraceGetter -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { - return ""; -} - -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { -} - -const char* const -OsStackTraceGetter::kElidedFramesMarker = +const char* const OsStackTraceGetterInterface::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; +std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + std::string result; + + if (max_depth <= 0) { + return result; + } + + max_depth = std::min(max_depth, kMaxStackTraceDepth); + + std::vector raw_stack(max_depth); + // Skips the frames requested by the caller, plus this function. + const int raw_stack_size = + absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1); + + void* caller_frame = nullptr; + { + MutexLock lock(&mutex_); + caller_frame = caller_frame_; + } + + for (int i = 0; i < raw_stack_size; ++i) { + if (raw_stack[i] == caller_frame && + !GTEST_FLAG(show_internal_stack_frames)) { + // Add a marker to the trace and stop adding frames. + absl::StrAppend(&result, kElidedFramesMarker, "\n"); + break; + } + + char tmp[1024]; + const char* symbol = "(unknown)"; + if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) { + symbol = tmp; + } + + char line[1024]; + snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol); + result += line; + } + + return result; + +#else // !GTEST_HAS_ABSL + static_cast(max_depth); + static_cast(skip_count); + return ""; +#endif // GTEST_HAS_ABSL +} + +void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { +#if GTEST_HAS_ABSL + void* caller_frame = nullptr; + if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) { + caller_frame = nullptr; + } + + MutexLock lock(&mutex_); + caller_frame_ = caller_frame; +#endif // GTEST_HAS_ABSL +} + // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { + : premature_exit_filepath_(premature_exit_filepath ? + premature_exit_filepath : "") { // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + if (!premature_exit_filepath_.empty()) { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. @@ -3544,13 +4394,18 @@ class ScopedPrematureExitFile { } ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); + if (!premature_exit_filepath_.empty()) { + int retval = remove(premature_exit_filepath_.c_str()); + if (retval) { + GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \"" + << premature_exit_filepath_ << "\" with error " + << retval; + } } } private: - const char* const premature_exit_filepath_; + const std::string premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; @@ -3815,11 +4670,16 @@ void UnitTest::AddTestPartResult( // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); +#elif (!defined(__native_client__)) && \ + ((defined(__clang__) || defined(__GNUC__)) && \ + (defined(__x86_64__) || defined(__i386__))) + // with clang/gcc we can achieve the same effect on x86 by invoking int3 + asm("int3"); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for @@ -3887,13 +4747,13 @@ int UnitTest::Run() { // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); -#if GTEST_HAS_SEH +#if GTEST_OS_WINDOWS // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE +# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -3916,7 +4776,7 @@ int UnitTest::Run() { // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // FIXME: find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( @@ -3924,7 +4784,7 @@ int UnitTest::Run() { _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } -#endif // GTEST_HAS_SEH +#endif // GTEST_OS_WINDOWS return internal::HandleExceptionsInMethodIfSupported( impl(), @@ -3957,7 +4817,6 @@ const TestInfo* UnitTest::current_test_info() const // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } -#if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& @@ -3965,7 +4824,6 @@ internal::ParameterizedTestCaseRegistry& GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } -#endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { @@ -3996,25 +4854,16 @@ namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). + GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER + GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), @@ -4081,10 +4930,12 @@ void UnitTestImpl::ConfigureXmlOutput() { if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format == "json") { + listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \"" + << output_format << "\" ignored."; } } @@ -4099,9 +4950,8 @@ void UnitTestImpl::ConfigureStreamingOutput() { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); + GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target + << "\" ignored."; } } } @@ -4117,6 +4967,11 @@ void UnitTestImpl::PostFlagParsingInit() { if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; +#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + // Register to send notifications about key process state changes. + listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); +#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) + #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); @@ -4135,6 +4990,13 @@ void UnitTestImpl::PostFlagParsingInit() { // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ + +#if GTEST_HAS_ABSL + if (GTEST_FLAG(install_failure_signal_handler)) { + absl::FailureSignalHandlerOptions options; + absl::InstallFailureSignalHandler(options); + } +#endif // GTEST_HAS_ABSL } } @@ -4178,11 +5040,11 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), + const std::vector::reverse_iterator test_case = + std::find_if(test_cases_.rbegin(), test_cases_.rend(), TestCaseNameIs(test_case_name)); - if (test_case != test_cases_.end()) + if (test_case != test_cases_.rend()) return *test_case; // No. Let's create one. @@ -4223,13 +5085,8 @@ static void TearDownEnvironment(Environment* env) { env->TearDown(); } // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } + // True iff Google Test is initialized before RUN_ALL_TESTS() is called. + const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized(); // Do not run any test if the --help flag was specified. if (g_help_flag) @@ -4250,6 +5107,11 @@ bool UnitTestImpl::RunAllTests() { #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) + if (in_subprocess_for_death_test) { + GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); + } +# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, @@ -4352,6 +5214,20 @@ bool UnitTestImpl::RunAllTests() { repeater->OnTestProgramEnd(*parent_); + if (!gtest_is_initialized_before_run_all_tests) { + ColoredPrintf( + COLOR_RED, + "\nIMPORTANT NOTICE - DO NOT IGNORE:\n" + "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_ + "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_ + " will start to enforce the valid usage. " + "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT +#if GTEST_FOR_GOOGLE_ + ColoredPrintf(COLOR_RED, + "For more details, see http://wiki/Main/ValidGUnitMain.\n"); +#endif // GTEST_FOR_GOOGLE_ + } + return !failed; } @@ -4453,8 +5329,8 @@ bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. +// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md +// . Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; @@ -4493,10 +5369,11 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); + const bool is_in_another_shard = + shard_tests != IGNORE_SHARDING_PROTOCOL && + !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests); + test_info->is_in_another_shard_ = is_in_another_shard; + const bool is_selected = is_runnable && !is_in_another_shard; num_runnable_tests += is_runnable; num_selected_tests += is_selected; @@ -4566,6 +5443,23 @@ void UnitTestImpl::ListTestsMatchingFilter() { } } fflush(stdout); + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml" || output_format == "json") { + FILE* fileout = OpenFileForWriting( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()); + std::stringstream stream; + if (output_format == "xml") { + XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintXmlTestsList(&stream, test_cases_); + } else if (output_format == "json") { + JsonUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str()) + .PrintJsonTestList(&stream, test_cases_); + } + fprintf(fileout, "%s", StringStreamToString(&stream).c_str()); + fclose(fileout); + } } // Sets the OS stack trace getter. @@ -4586,17 +5480,25 @@ void UnitTestImpl::set_os_stack_trace_getter( // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { +#ifdef GTEST_OS_STACK_TRACE_GETTER_ + os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; +#else os_stack_trace_getter_ = new OsStackTraceGetter; +#endif // GTEST_OS_STACK_TRACE_GETTER_ } return os_stack_trace_getter_; } -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. +// Returns the most specific TestResult currently running. TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; + if (current_test_info_ != NULL) { + return ¤t_test_info_->result_; + } + if (current_test_case_ != NULL) { + return ¤t_test_case_->ad_hoc_test_result_; + } + return &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, @@ -4677,9 +5579,8 @@ bool SkipPrefix(const char* prefix, const char** pstr) { // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { +static const char* ParseFlagValue(const char* str, const char* flag, + bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; @@ -4715,7 +5616,7 @@ const char* ParseFlagValue(const char* str, // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { +static bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); @@ -4749,7 +5650,9 @@ bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { +template +/* static was removed to workaround SStudio bug 27279066 */ +bool ParseStringFlag(const char* str, const char* flag, String* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); @@ -4785,7 +5688,7 @@ static bool HasGoogleTestFlagPrefix(const char* str) { // @Y changes the color to yellow. // @D changes to the default terminal text color. // -// TODO(wan@google.com): Write tests for this once we add stdout +// FIXME: Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. @@ -4851,24 +5754,25 @@ static const char kColorEncodedHelpMessage[] = " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" +" @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ +" Generate a JSON or XML report in the given directory or with the given\n" +" file name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +# if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ +# endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" +" Turn assertion failures into C++ exceptions for use by an external\n" +" test framework.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" @@ -4885,6 +5789,56 @@ static const char kColorEncodedHelpMessage[] = "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; +static bool ParseGoogleTestFlag(const char* const arg) { + return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseBoolFlag(arg, kPrintUTF8Flag, >EST_FLAG(print_utf8)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)); +} + +#if GTEST_USE_OWN_FLAGFILE_FLAG_ +static void LoadFlagsFromFile(const std::string& path) { + FILE* flagfile = posix::FOpen(path.c_str(), "r"); + if (!flagfile) { + GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile) + << "\""; + } + std::string contents(ReadEntireFile(flagfile)); + posix::FClose(flagfile); + std::vector lines; + SplitString(contents, '\n', &lines); + for (size_t i = 0; i < lines.size(); ++i) { + if (lines[i].empty()) + continue; + if (!ParseGoogleTestFlag(lines[i].c_str())) + g_help_flag = true; + } +} +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. @@ -4898,35 +5852,24 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { using internal::ParseInt32Flag; using internal::ParseStringFlag; - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note + bool remove_flag = false; + if (ParseGoogleTestFlag(arg)) { + remove_flag = true; +#if GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { + LoadFlagsFromFile(GTEST_FLAG(flagfile)); + remove_flag = true; +#endif // GTEST_USE_OWN_FLAGFILE_FLAG_ + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + + if (remove_flag) { + // Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. @@ -4940,12 +5883,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // We also need to decrement the iterator as we just removed // an element. i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; } } @@ -4961,6 +5898,17 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); + + // Fix the value of *_NSGetArgc() on macOS, but iff + // *_NSGetArgv() == argv + // Only applicable to char** version of argv +#if GTEST_OS_MAC +#ifndef GTEST_OS_IOS + if (*_NSGetArgv() == argv) { + *_NSGetArgc() = *argc; + } +#endif +#endif } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); @@ -4972,23 +5920,19 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; + if (GTestIsInitialized()) return; if (*argc <= 0) return; - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } -#endif // GTEST_HAS_DEATH_TEST +#if GTEST_HAS_ABSL + absl::InitializeSymbolizer(g_argvs[0].c_str()); +#endif // GTEST_HAS_ABSL ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); @@ -5006,13 +5950,62 @@ void InitGoogleTestImpl(int* argc, CharType** argv) { // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { +#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) + GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); +#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); +#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) +} + +std::string TempDir() { +#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_) + return GTEST_CUSTOM_TEMPDIR_FUNCTION_(); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + return "\\temp\\"; +#elif GTEST_OS_WINDOWS + const char* temp_dir = internal::posix::GetEnv("TEMP"); + if (temp_dir == NULL || temp_dir[0] == '\0') + return "\\temp\\"; + else if (temp_dir[strlen(temp_dir) - 1] == '\\') + return temp_dir; + else + return std::string(temp_dir) + "\\"; +#elif GTEST_OS_LINUX_ANDROID + return "/sdcard/"; +#else + return "/tmp/"; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +void ScopedTrace::PushTrace(const char* file, int line, std::string message) { + internal::TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message.swap(message); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); } } // namespace testing diff --git a/test/fmw/gtest/src/gtest_main.cc b/test/fmw/gtest/src/gtest_main.cc index f3028225523..2113f621e65 100644 --- a/test/fmw/gtest/src/gtest_main.cc +++ b/test/fmw/gtest/src/gtest_main.cc @@ -28,11 +28,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include - #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { - printf("Running main() from gtest_main.cc\n"); + printf("Running main() from %s\n", __FILE__); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } From 993feb95ea2708fae10418bc76a8275900a04ea1 Mon Sep 17 00:00:00 2001 From: Jesper Wilhelmsson Date: Fri, 17 May 2019 00:21:10 +0200 Subject: [PATCH 035/263] 8223346: Update Graal Reviewed-by: kvn --- .../compiler/asm/amd64/AMD64Assembler.java | 5 +- .../amd64/AMD64ArithmeticLIRGenerator.java | 19 +++ .../core/test/TwoSlotMarkerClearingTest.java | 86 +++++++++++++ .../compiler/graph/spi/Canonicalizable.java | 47 ++++++- .../hotspot/amd64/AMD64HotSpotBackend.java | 11 +- .../amd64/AMD64HotSpotBackendFactory.java | 4 +- .../hotspot/jdk9/test/MathDoubleFMATest.java | 82 ++++++++++++ .../jdk9/test/MathFMAConstantInputTest.java | 62 +++++++++ .../hotspot/jdk9/test/MathFloatFMATest.java | 82 ++++++++++++ .../hotspot/test/CheckGraalIntrinsics.java | 13 +- .../test/WriteBarrierAdditionTest.java | 37 +++++- .../compiler/hotspot/CompilationTask.java | 9 +- .../hotspot/GraalHotSpotVMConfig.java | 1 + .../compiler/hotspot/gc/g1/G1BarrierSet.java | 42 ++++--- .../hotspot/gc/shared/BarrierSet.java | 11 ++ .../gc/shared/CardTableBarrierSet.java | 33 +++-- .../meta/DefaultHotSpotLoweringProvider.java | 17 +-- .../HotSpotObjdumpDisassemblerProvider.java | 118 +++++++++++++----- .../phases/WriteBarrierAdditionPhase.java | 12 +- .../phases/WriteBarrierVerificationPhase.java | 7 +- .../replacements/UnsafeLoadSnippets.java | 2 +- .../compiler/java/FrameStateBuilder.java | 7 ++ .../compiler/lir/amd64/AMD64Ternary.java | 89 +++++++++++++ .../lir/gen/ArithmeticLIRGeneratorTool.java | 5 + .../compiler/nodes/calc/TernaryNode.java | 106 ++++++++++++++++ .../compiler/nodes/memory/HeapAccess.java | 18 ++- .../amd64/AMD64GraphBuilderPlugins.java | 60 +++++++-- .../test/RootMethodSubstitutionTest.java | 7 +- .../DefaultJavaLoweringProvider.java | 67 +++++++--- .../nodes/FusedMultiplyAddNode.java | 92 ++++++++++++++ .../serviceprovider/GraalServices.java | 18 +++ .../compiler/word/WordOperationPlugin.java | 4 +- 32 files changed, 1047 insertions(+), 126 deletions(-) create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TwoSlotMarkerClearingTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFMAConstantInputTest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Ternary.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/TernaryNode.java create mode 100644 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FusedMultiplyAddNode.java diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java index 90489d8acab..2cc64d3bac6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java @@ -906,7 +906,8 @@ public class AMD64Assembler extends AMD64BaseAssembler { CPU_XMM(CPUFeature.AVX, null, CPU, null, XMM, null), AVX1_2_CPU_XMM(CPUFeature.AVX, CPUFeature.AVX2, CPU, null, XMM, null), BMI1(CPUFeature.BMI1, null, CPU, CPU, CPU, null), - BMI2(CPUFeature.BMI2, null, CPU, CPU, CPU, null); + BMI2(CPUFeature.BMI2, null, CPU, CPU, CPU, null), + FMA(CPUFeature.FMA, null, XMM, XMM, XMM, null); private final CPUFeature l128feature; private final CPUFeature l256feature; @@ -1308,6 +1309,8 @@ public class AMD64Assembler extends AMD64BaseAssembler { public static final VexRVMOp VPCMPGTW = new VexRVMOp("VPCMPGTW", P_66, M_0F, WIG, 0x65, VEXOpAssertion.AVX1_2); public static final VexRVMOp VPCMPGTD = new VexRVMOp("VPCMPGTD", P_66, M_0F, WIG, 0x66, VEXOpAssertion.AVX1_2); public static final VexRVMOp VPCMPGTQ = new VexRVMOp("VPCMPGTQ", P_66, M_0F38, WIG, 0x37, VEXOpAssertion.AVX1_2); + public static final VexRVMOp VFMADD231SS = new VexRVMOp("VFMADD231SS", P_66, M_0F38, W0, 0xB9, VEXOpAssertion.FMA); + public static final VexRVMOp VFMADD231SD = new VexRVMOp("VFMADD231SD", P_66, M_0F38, W1, 0xB9, VEXOpAssertion.FMA); // @formatter:on private VexRVMOp(String opcode, int pp, int mmmmm, int w, int op) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java index ba72cd0d27c..ed2c3592787 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java @@ -57,6 +57,8 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VADDSD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VADDSS; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VDIVSD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VDIVSS; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VFMADD231SD; +import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VFMADD231SS; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VMULSD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VMULSS; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp.VORPD; @@ -120,6 +122,7 @@ import org.graalvm.compiler.lir.amd64.AMD64Move; import org.graalvm.compiler.lir.amd64.AMD64MulDivOp; import org.graalvm.compiler.lir.amd64.AMD64ShiftOp; import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp; +import org.graalvm.compiler.lir.amd64.AMD64Ternary; import org.graalvm.compiler.lir.amd64.AMD64Unary; import org.graalvm.compiler.lir.amd64.AMD64ZeroMemoryOp; import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary; @@ -962,6 +965,22 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen return result; } + @Override + public Variable emitFusedMultiplyAdd(Value a, Value b, Value c) { + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b, c)); + assert ((AMD64Kind) a.getPlatformKind()).isXMM() && ((AMD64Kind) b.getPlatformKind()).isXMM() && ((AMD64Kind) c.getPlatformKind()).isXMM(); + assert a.getPlatformKind().equals(b.getPlatformKind()); + assert b.getPlatformKind().equals(c.getPlatformKind()); + + if (a.getPlatformKind() == AMD64Kind.DOUBLE) { + getLIRGen().append(new AMD64Ternary.ThreeOp(VFMADD231SD, AVXSize.XMM, result, asAllocatable(c), asAllocatable(a), asAllocatable(b))); + } else { + assert a.getPlatformKind() == AMD64Kind.SINGLE; + getLIRGen().append(new AMD64Ternary.ThreeOp(VFMADD231SS, AVXSize.XMM, result, asAllocatable(c), asAllocatable(a), asAllocatable(b))); + } + return result; + } + @Override public Value emitCountLeadingZeros(Value value) { Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AMD64Kind.DWORD)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TwoSlotMarkerClearingTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TwoSlotMarkerClearingTest.java new file mode 100644 index 00000000000..78c2ce91d2e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TwoSlotMarkerClearingTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.core.test; + +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Label; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class TwoSlotMarkerClearingTest extends CustomizedBytecodePatternTest { + + @Test + public void testTwoSlotMarkerClearing() throws ClassNotFoundException { + Class testClass = getClass("Test"); + ResolvedJavaMethod t1 = getResolvedJavaMethod(testClass, "t1"); + parseForCompile(t1); + ResolvedJavaMethod t2 = getResolvedJavaMethod(testClass, "t2"); + parseForCompile(t2); + } + + @Override + protected byte[] generateClass(String className) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(52, ACC_SUPER | ACC_PUBLIC, className, null, "java/lang/Object", null); + + String getDescriptor = "(" + "JII" + ")" + "I"; + MethodVisitor t1 = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "t1", getDescriptor, null, null); + t1.visitCode(); + t1.visitVarInsn(ILOAD, 2); + t1.visitVarInsn(ISTORE, 0); + t1.visitVarInsn(ILOAD, 0); + Label label = new Label(); + t1.visitJumpInsn(IFGE, label); + t1.visitVarInsn(ILOAD, 0); + t1.visitInsn(IRETURN); + t1.visitLabel(label); + t1.visitVarInsn(ILOAD, 3); + t1.visitInsn(IRETURN); + t1.visitMaxs(4, 1); + t1.visitEnd(); + + getDescriptor = "(" + "IJIJ" + ")" + "J"; + MethodVisitor t2 = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "t2", getDescriptor, null, null); + t2.visitCode(); + t2.visitVarInsn(LLOAD, 1); + t2.visitVarInsn(LSTORE, 0); + t2.visitVarInsn(ILOAD, 3); + Label label1 = new Label(); + t2.visitJumpInsn(IFGE, label1); + t2.visitVarInsn(LLOAD, 0); + t2.visitInsn(LRETURN); + t2.visitLabel(label1); + t2.visitVarInsn(LLOAD, 4); + t2.visitInsn(LRETURN); + t2.visitMaxs(6, 2); + t2.visitEnd(); + + cw.visitEnd(); + return cw.toByteArray(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java index acb9db52a5e..e2b8126f1b3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/spi/Canonicalizable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -155,4 +155,49 @@ public interface Canonicalizable { */ Node maybeCommuteInputs(); } + + /** + * This sub-interface of {@link Canonicalizable} is intended for nodes that have exactly three + * inputs. It has an additional {@link #canonical(CanonicalizerTool, Node, Node, Node)} method + * that looks at the given inputs instead of the current inputs of the node - which can be used + * to ask "what if this input is changed to this node" - questions. + * + * @param the common supertype of all inputs of this node + */ + public interface Ternary extends Canonicalizable { + + /** + * Similar to {@link Canonicalizable#canonical(CanonicalizerTool)}, except that + * implementations should act as if the current input of the node was the given one, i.e., + * they should never look at the inputs via the this pointer. + */ + Node canonical(CanonicalizerTool tool, T forX, T forY, T forZ); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node, Node, Node)} with the value returned from this + * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getX(); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node, Node, Node)} with the value returned from this + * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getY(); + + /** + * Gets the current value of the input, so that calling + * {@link #canonical(CanonicalizerTool, Node, Node, Node)} with the value returned from this + * method should behave exactly like {@link Canonicalizable#canonical(CanonicalizerTool)}. + */ + T getZ(); + + @SuppressWarnings("unchecked") + @Override + default T canonical(CanonicalizerTool tool) { + return (T) canonical(tool, getX(), getY(), getZ()); + } + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 3602e6887b1..7bad8b5edbd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -263,14 +263,19 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend implements LIRGenera if (config.useCompressedClassPointers) { Register register = r10; - AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config); + Register heapBase = providers.getRegisters().getHeapBaseRegister(); + AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, heapBase, src, config); if (GeneratePIC.getValue(crb.getOptions())) { - asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1)); + asm.movq(heapBase, asm.getPlaceholder(-1)); crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS); } else { if (config.narrowKlassBase != 0) { // The heap base register was destroyed above, so restore it - asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + if (config.narrowOopBase == 0L) { + asm.xorq(heapBase, heapBase); + } else { + asm.movq(heapBase, config.narrowOopBase); + } } } asm.cmpq(inlineCacheKlass, register); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java index 35350e69b46..fbafb4a9bbf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, 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 @@ -161,7 +161,7 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, OptionValues options) { Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements, options); - AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, false, JAVA_SPECIFICATION_VERSION >= 9); + AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, false, JAVA_SPECIFICATION_VERSION >= 9, config.useFMAIntrinsics); return plugins; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java new file mode 100644 index 00000000000..8d0221ed1c0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathDoubleFMATest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.hotspot.jdk9.test; + +import static org.junit.Assume.assumeTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.test.AddExports; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import jdk.vm.ci.amd64.AMD64; + +@AddExports({"java.base/java.lang"}) +@RunWith(Parameterized.class) +public final class MathDoubleFMATest extends GraalCompilerTest { + + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + @Parameters(name = "{0}, {1}, {2}") + public static Collection data() { + double[] inputs = {0.0d, 1.0d, 4.0d, -0.0d, -1.0d, -4.0d, Double.MIN_VALUE, Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, + Double.NaN, Double.longBitsToDouble(0xfff0000000000001L)}; + + List tests = new ArrayList<>(); + for (double a : inputs) { + for (double b : inputs) { + for (double c : inputs) { + tests.add(new Object[]{a, b, c}); + } + } + } + return tests; + } + + @Parameter(value = 0) public double input0; + @Parameter(value = 1) public double input1; + @Parameter(value = 2) public double input2; + + public static double fma(double a, double b, double c) { + return Math.fma(a, b, c); + } + + @Test + public void testFMA() { + test("fma", input0, input1, input2); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFMAConstantInputTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFMAConstantInputTest.java new file mode 100644 index 00000000000..6cdbce1e36a --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFMAConstantInputTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.hotspot.jdk9.test; + +import static org.junit.Assume.assumeTrue; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.test.AddExports; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.amd64.AMD64; + +@AddExports({"java.base/java.lang"}) +public final class MathFMAConstantInputTest extends GraalCompilerTest { + + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + public static float floatFMA() { + return Math.fma(2.0f, 2.0f, 2.0f); + } + + @Test + public void testFloatFMA() { + test("floatFMA"); + } + + public static double doubleFMA() { + return Math.fma(2.0d, 2.0d, 2.0d); + } + + @Test + public void testDoubleFMA() { + test("doubleFMA"); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java new file mode 100644 index 00000000000..dcb69e3ca12 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.jdk9.test/src/org/graalvm/compiler/hotspot/jdk9/test/MathFloatFMATest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.hotspot.jdk9.test; + +import static org.junit.Assume.assumeTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.test.AddExports; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; + +import jdk.vm.ci.amd64.AMD64; + +@AddExports({"java.base/java.lang"}) +@RunWith(Parameterized.class) +public final class MathFloatFMATest extends GraalCompilerTest { + + @Before + public void checkAMD64() { + assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + } + + @Parameters(name = "{0}, {1}, {2}") + public static Collection data() { + float[] inputs = {0.0f, 1.0f, 4.0f, -0.0f, -1.0f, 4.0f, Float.MIN_VALUE, Float.MAX_VALUE, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, + Float.NaN, Float.intBitsToFloat(0xff800001)}; + + List tests = new ArrayList<>(); + for (float a : inputs) { + for (float b : inputs) { + for (float c : inputs) { + tests.add(new Object[]{a, b, c}); + } + } + } + return tests; + } + + @Parameter(value = 0) public float input0; + @Parameter(value = 1) public float input1; + @Parameter(value = 2) public float input2; + + public static float fma(float a, float b, float c) { + return Math.fma(a, b, c); + } + + @Test + public void testFMA() { + test("fma", input0, input1, input2); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java index f3861c4e0d8..e68875c71f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java @@ -272,10 +272,6 @@ public class CheckGraalIntrinsics extends GraalTest { "jdk/jfr/internal/JVM.getClassId(Ljava/lang/Class;)J"); add(toBeInvestigated, - // HotSpot MacroAssembler-based intrinsic - "java/lang/Math.fma(DDD)D", - // HotSpot MacroAssembler-based intrinsic - "java/lang/Math.fma(FFF)F", // Just check if the argument is a compile time constant "java/lang/invoke/MethodHandleImpl.isCompileConstant(Ljava/lang/Object;)Z", // Only used as a marker for vectorization? @@ -371,6 +367,15 @@ public class CheckGraalIntrinsics extends GraalTest { add(ignore, "sun/security/provider/DigestBase.implCompressMultiBlock0([BII)I"); } + if (!config.useFMAIntrinsics) { + add(ignore, + "java/lang/Math.fma(DDD)D", + "java/lang/Math.fma(FFF)F"); + } else if (!(arch instanceof AMD64)) { + add(toBeInvestigated, + "java/lang/Math.fma(DDD)D", + "java/lang/Math.fma(FFF)F"); + } } if (isJDK10OrHigher()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java index 04b4d2b2d8d..954122065e4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java @@ -55,6 +55,8 @@ import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.MidTierContext; import org.graalvm.compiler.replacements.NodeIntrinsificationProvider; +import org.graalvm.compiler.word.Word; +import jdk.internal.vm.compiler.word.WordFactory; import org.junit.Assert; import org.junit.Test; @@ -255,6 +257,34 @@ public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest { test2("testArrayCopy", src, dst, dst.length); } + public static class WordContainer { + public Word word; + } + + public static void testWordFieldSnippet() { + WordContainer wordContainer = new WordContainer(); + wordContainer.word = WordFactory.signed(42); + } + + @Test + public void testWordField() throws Exception { + testHelper("testWordFieldSnippet", 0); + } + + public static Word[] testWordArraySnippet(int length) { + Word fortyTwo = WordFactory.signed(42); + Word[] words = new Word[length]; + for (int i = 0; i < length; i++) { + words[i] = fortyTwo; + } + return words; + } + + @Test + public void testWordArray() throws Exception { + testHelper("testWordArraySnippet", 0); + } + public static Object testUnsafeLoad(Unsafe theUnsafe, Object a, Object b, Object c) throws Exception { final int offset = (c == null ? 0 : ((Integer) c).intValue()); final long displacement = (b == null ? 0 : ((Long) b).longValue()); @@ -315,9 +345,10 @@ public class WriteBarrierAdditionTest extends HotSpotGraalCompilerTest { JavaConstant constDisp = ((OffsetAddressNode) read.getAddress()).getOffset().asJavaConstant(); Assert.assertNotNull(constDisp); Assert.assertEquals(referentOffset(getMetaAccess()), constDisp.asLong()); - Assert.assertTrue(config.useG1GC); - Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType()); - Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier); + Assert.assertEquals(BarrierType.WEAK_FIELD, read.getBarrierType()); + if (config.useG1GC) { + Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier); + } } } } catch (Throwable e) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java index 06850011819..f22a08b77c7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java @@ -56,6 +56,7 @@ import jdk.vm.ci.hotspot.HotSpotInstalledCode; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotNmethod; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.runtime.JVMCICompiler; public class CompilationTask { @@ -169,7 +170,13 @@ public class CompilationTask { } stats.finish(method, installedCode); if (result != null) { - return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize()); + // For compilation of substitutions the method in the compilation request might be + // different than the actual method parsed. The root of the compilation will always + // be the first method in the methods list, so use that instead. + ResolvedJavaMethod rootMethod = result.getMethods()[0]; + int inlinedBytecodes = result.getBytecodeSize() - rootMethod.getCodeSize(); + assert inlinedBytecodes >= 0 : rootMethod + " " + method; + return HotSpotCompilationRequestResult.success(inlinedBytecodes); } return null; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index 69582a391c6..9ee6ddad85f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -108,6 +108,7 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase { private final boolean useMulAddIntrinsic = getFlag("UseMulAddIntrinsic", Boolean.class, false); private final boolean useSquareToLenIntrinsic = getFlag("UseSquareToLenIntrinsic", Boolean.class, false); public final boolean useVectorizedMismatchIntrinsic = getFlag("UseVectorizedMismatchIntrinsic", Boolean.class, false); + public final boolean useFMAIntrinsics = getFlag("UseFMA", Boolean.class, false); /* * These are methods because in some JDKs the flags are visible but the stubs themselves haven't diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java index 4e7729bc445..e0ad4fdbc9c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/g1/G1BarrierSet.java @@ -26,6 +26,7 @@ package org.graalvm.compiler.hotspot.gc.g1; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.gc.shared.BarrierSet; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; @@ -41,10 +42,13 @@ import org.graalvm.compiler.nodes.type.StampTool; public class G1BarrierSet extends BarrierSet { + public G1BarrierSet(GraalHotSpotVMConfig vmConfig) { + super(vmConfig); + } + @Override public void addReadNodeBarriers(ReadNode node, StructuredGraph graph) { - if (node.getBarrierType() != HeapAccess.BarrierType.NONE) { - assert (node.getBarrierType() == HeapAccess.BarrierType.PRECISE); + if (node.getBarrierType() == HeapAccess.BarrierType.WEAK_FIELD) { G1ReferentFieldReadBarrier barrier = graph.add(new G1ReferentFieldReadBarrier(node.getAddress(), node, false)); graph.addAfterFixed(node, barrier); } @@ -57,15 +61,19 @@ public class G1BarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; - if (!node.getLocationIdentity().isInit()) { - // The pre barrier does nothing if the value being read is null, so it can - // be explicitly skipped when this is an initializing store. - addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); + case FIELD: + case ARRAY: + case UNKNOWN: + boolean init = node.getLocationIdentity().isInit(); + if (!init || !getVMConfig().useDeferredInitBarriers) { + if (!init) { + // The pre barrier does nothing if the value being read is null, so it can + // be explicitly skipped when this is an initializing store. + addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); + } + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; + addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); } - addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); break; default: throw new GraalError("unexpected barrier type: " + barrierType); @@ -79,9 +87,10 @@ public class G1BarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; + case FIELD: + case ARRAY: + case UNKNOWN: + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph); addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); break; @@ -97,9 +106,10 @@ public class G1BarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; + case FIELD: + case ARRAY: + case UNKNOWN: + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; addG1PreWriteBarrier(node, node.getAddress(), node.getExpectedValue(), false, false, graph); addG1PostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); break; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java index 10c77863c76..c24a3400883 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/BarrierSet.java @@ -25,6 +25,7 @@ package org.graalvm.compiler.hotspot.gc.shared; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.extended.ArrayRangeWrite; import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode; @@ -33,6 +34,16 @@ import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.WriteNode; public abstract class BarrierSet { + private final GraalHotSpotVMConfig vmConfig; + + protected BarrierSet(GraalHotSpotVMConfig vmConfig) { + this.vmConfig = vmConfig; + } + + public final GraalHotSpotVMConfig getVMConfig() { + return vmConfig; + } + public abstract void addReadNodeBarriers(ReadNode node, StructuredGraph graph); public abstract void addWriteNodeBarriers(WriteNode node, StructuredGraph graph); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java index 401cab8994f..5021d1f6f78 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/gc/shared/CardTableBarrierSet.java @@ -26,6 +26,7 @@ package org.graalvm.compiler.hotspot.gc.shared; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.ArrayRangeWrite; @@ -40,9 +41,13 @@ import org.graalvm.compiler.nodes.type.StampTool; public class CardTableBarrierSet extends BarrierSet { + public CardTableBarrierSet(GraalHotSpotVMConfig vmConfig) { + super(vmConfig); + } + @Override public void addReadNodeBarriers(ReadNode node, StructuredGraph graph) { - assert node.getBarrierType() == HeapAccess.BarrierType.NONE : "Non precise read barrier has been attached to read node."; + // Nothing to do here. } @Override @@ -52,10 +57,14 @@ public class CardTableBarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; - addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); + case FIELD: + case ARRAY: + case UNKNOWN: + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; + boolean init = node.getLocationIdentity().isInit(); + if (!init || !getVMConfig().useDeferredInitBarriers) { + addSerialPostWriteBarrier(node, node.getAddress(), node.value(), precise, graph); + } break; default: throw new GraalError("unexpected barrier type: " + barrierType); @@ -69,9 +78,10 @@ public class CardTableBarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; + case FIELD: + case ARRAY: + case UNKNOWN: + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); break; default: @@ -86,9 +96,10 @@ public class CardTableBarrierSet extends BarrierSet { case NONE: // nothing to do break; - case IMPRECISE: - case PRECISE: - boolean precise = barrierType == HeapAccess.BarrierType.PRECISE; + case FIELD: + case ARRAY: + case UNKNOWN: + boolean precise = barrierType != HeapAccess.BarrierType.FIELD; addSerialPostWriteBarrier(node, node.getAddress(), node.getNewValue(), precise, graph); break; default: diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 4c3576ae376..79d98b77ada 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -583,16 +583,6 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider graph.replaceFixed(storeHub, hub); } - @Override - public BarrierType fieldInitializationBarrier(JavaKind entryKind) { - return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.IMPRECISE : BarrierType.NONE; - } - - @Override - public BarrierType arrayInitializationBarrier(JavaKind entryKind) { - return (entryKind == JavaKind.Object && !runtime.getVMConfig().useDeferredInitBarriers) ? BarrierType.PRECISE : BarrierType.NONE; - } - private void lowerOSRStartNode(OSRStartNode osrStart) { StructuredGraph graph = osrStart.graph(); if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) { @@ -783,12 +773,11 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider @Override protected BarrierType fieldLoadBarrierType(ResolvedJavaField f) { HotSpotResolvedJavaField loadField = (HotSpotResolvedJavaField) f; - BarrierType barrierType = BarrierType.NONE; - if (runtime.getVMConfig().useG1GC && loadField.getJavaKind() == JavaKind.Object && metaAccess.lookupJavaType(Reference.class).equals(loadField.getDeclaringClass()) && + if (loadField.getJavaKind() == JavaKind.Object && metaAccess.lookupJavaType(Reference.class).equals(loadField.getDeclaringClass()) && loadField.getName().equals("referent")) { - barrierType = BarrierType.PRECISE; + return BarrierType.WEAK_FIELD; } - return barrierType; + return super.fieldLoadBarrierType(f); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java index 56d4d9e7364..a37538b91d7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotObjdumpDisassemblerProvider.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.DisassemblerProvider; import org.graalvm.compiler.serviceprovider.ServiceProvider; +import org.graalvm.util.CollectionsUtil; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.CodeUtil; @@ -56,28 +57,31 @@ import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.services.Services; /** - * This disassembles the code immediatly with objdump. + * A provider that uses the {@code GNU objdump} utility to disassemble code. */ @ServiceProvider(DisassemblerProvider.class) public class HotSpotObjdumpDisassemblerProvider extends HotSpotDisassemblerProvider { - /** - * Uses objdump to disassemble the compiled code. - */ + private final String objdump = getObjdump(); + @Override public String disassembleCompiledCode(CodeCacheProvider codeCache, CompilationResult compResult) { + if (objdump == null) { + return null; + } File tmp = null; try { tmp = File.createTempFile("compiledBinary", ".bin"); try (FileOutputStream fos = new FileOutputStream(tmp)) { fos.write(compResult.getTargetCode()); } + String[] cmdline; String arch = Services.getSavedProperties().get("os.arch"); - if (arch.equals("amd64")) { - cmdline = new String[]{"objdump", "-D", "-b", "binary", "-M", "x86-64", "-m", "i386", tmp.getAbsolutePath()}; + if (arch.equals("amd64") || arch.equals("x86_64")) { + cmdline = new String[]{objdump, "-D", "-b", "binary", "-M", "x86-64", "-m", "i386", tmp.getAbsolutePath()}; } else if (arch.equals("aarch64")) { - cmdline = new String[]{"objdump", "-D", "-b", "binary", "-m", "aarch64", tmp.getAbsolutePath()}; + cmdline = new String[]{objdump, "-D", "-b", "binary", "-m", "aarch64", tmp.getAbsolutePath()}; } else { return null; } @@ -116,43 +120,99 @@ public class HotSpotObjdumpDisassemblerProvider extends HotSpotDisassemblerProvi Process proc = Runtime.getRuntime().exec(cmdline); InputStream is = proc.getInputStream(); + StringBuilder sb = new StringBuilder(); InputStreamReader isr = new InputStreamReader(is); - BufferedReader br = new BufferedReader(isr); - String line; - - StringBuilder sb = new StringBuilder(); - while ((line = br.readLine()) != null) { - Matcher m = p.matcher(line); - if (m.find()) { - int address = Integer.parseInt(m.group(2), 16); - String annotation = annotations.get(address); - if (annotation != null) { - annotation = annotation.replace("\n", "\n; "); - sb.append("; ").append(annotation).append('\n'); + try (BufferedReader br = new BufferedReader(isr)) { + String line; + while ((line = br.readLine()) != null) { + Matcher m = p.matcher(line); + if (m.find()) { + int address = Integer.parseInt(m.group(2), 16); + String annotation = annotations.get(address); + if (annotation != null) { + annotation = annotation.replace("\n", "\n; "); + sb.append("; ").append(annotation).append('\n'); + } + line = m.replaceAll("0x$1"); } - line = m.replaceAll("0x$1"); + sb.append(line).append("\n"); } - sb.append(line).append("\n"); } - BufferedReader ebr = new BufferedReader(new InputStreamReader(proc.getErrorStream())); - while ((line = ebr.readLine()) != null) { - System.err.println(line); + try (BufferedReader ebr = new BufferedReader(new InputStreamReader(proc.getErrorStream()))) { + String errLine = ebr.readLine(); + if (errLine != null) { + System.err.println("Error output from executing: " + CollectionsUtil.mapAndJoin(cmdline, e -> quoteShellArg(String.valueOf(e)), " ")); + System.err.println(errLine); + while ((errLine = ebr.readLine()) != null) { + System.err.println(errLine); + } + } } - ebr.close(); return sb.toString(); } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { if (tmp != null) { tmp.delete(); } - e.printStackTrace(); - return null; } } + /** + * Pattern for a single shell command argument that does not need to quoted. + */ + private static final Pattern SAFE_SHELL_ARG = Pattern.compile("[A-Za-z0-9@%_\\-\\+=:,\\./]+"); + + /** + * Reliably quote a string as a single shell command argument. + */ + public static String quoteShellArg(String arg) { + if (arg.isEmpty()) { + return "\"\""; + } + Matcher m = SAFE_SHELL_ARG.matcher(arg); + if (m.matches()) { + return arg; + } + // See http://stackoverflow.com/a/1250279 + return "'" + arg.replace("'", "'\"'\"'") + "'"; + } + + /** + * Searches for a valid GNU objdump executable. + */ + private static String getObjdump() { + // On macOS, `brew install binutils` will provide + // an executable named gobjdump + for (String candidate : new String[]{"objdump", "gobjdump"}) { + try { + String[] cmd = {candidate, "--version"}; + Process proc = Runtime.getRuntime().exec(cmd); + InputStream is = proc.getInputStream(); + int exitValue = proc.waitFor(); + if (exitValue == 0) { + byte[] buf = new byte[is.available()]; + int pos = 0; + while (pos < buf.length) { + int read = is.read(buf, pos, buf.length - pos); + pos += read; + } + String output = new String(buf); + if (output.contains("GNU objdump")) { + return candidate; + } + } + } catch (IOException | InterruptedException e) { + } + } + return null; + } + private static void putAnnotation(Map annotations, int idx, String txt) { - String newAnnoation = annotations.getOrDefault(idx, "") + "\n" + txt; - annotations.put(idx, newAnnoation); + String newAnnotation = annotations.getOrDefault(idx, "") + "\n" + txt; + annotations.put(idx, newAnnotation); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java index 5ae608a5a50..d2628a568c3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java @@ -77,17 +77,17 @@ public class WriteBarrierAdditionPhase extends Phase { private BarrierSet createBarrierSet(GraalHotSpotVMConfig config) { if (config.useG1GC) { - return createG1BarrierSet(); + return createG1BarrierSet(config); } else { - return createCardTableBarrierSet(); + return createCardTableBarrierSet(config); } } - protected BarrierSet createCardTableBarrierSet() { - return new CardTableBarrierSet(); + protected BarrierSet createCardTableBarrierSet(GraalHotSpotVMConfig config) { + return new CardTableBarrierSet(config); } - protected BarrierSet createG1BarrierSet() { - return new G1BarrierSet(); + protected BarrierSet createG1BarrierSet(GraalHotSpotVMConfig config) { + return new G1BarrierSet(config); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java index 34f14fc7c41..f67bcc48d3c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java @@ -44,6 +44,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.ArrayRangeWrite; import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode; import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode; +import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode; import org.graalvm.compiler.nodes.memory.FixedAccessNode; import org.graalvm.compiler.nodes.memory.HeapAccess; import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; @@ -127,6 +128,9 @@ public class WriteBarrierVerificationPhase extends Phase { boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization()); if (node instanceof WriteNode) { WriteNode writeNode = (WriteNode) node; + if (config.useDeferredInitBarriers && writeNode.getLocationIdentity().isInit()) { + return true; + } if (writeNode.getLocationIdentity().isInit()) { validatePreBarrier = false; } @@ -191,7 +195,8 @@ public class WriteBarrierVerificationPhase extends Phase { } private static boolean validateBarrier(FixedAccessNode write, ObjectWriteBarrier barrier) { - assert write instanceof WriteNode || write instanceof LogicCompareAndSwapNode || write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write; + assert write instanceof WriteNode || write instanceof LogicCompareAndSwapNode || write instanceof ValueCompareAndSwapNode || + write instanceof LoweredAtomicReadAndWriteNode : "Node must be of type requiring a write barrier " + write; if (!barrier.usePrecise()) { if (barrier.getAddress() instanceof OffsetAddressNode && write.getAddress() instanceof OffsetAddressNode) { return GraphUtil.unproxify(((OffsetAddressNode) barrier.getAddress()).getBase()) == GraphUtil.unproxify(((OffsetAddressNode) write.getAddress()).getBase()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java index b1b0f8036e2..7959a42c665 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/UnsafeLoadSnippets.java @@ -50,7 +50,7 @@ public class UnsafeLoadSnippets implements Snippets { public static Object lowerUnsafeLoad(Object object, long offset) { Object fixedObject = FixedValueAnchorNode.getObject(object); if (object instanceof java.lang.ref.Reference && referentOffset(INJECTED_METAACCESS) == offset) { - return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.PRECISE); + return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.WEAK_FIELD); } else { return Word.objectToTrackedPointer(fixedObject).readObject((int) offset, BarrierType.NONE); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java index 02ef27057da..5b446ec04b4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java @@ -743,6 +743,13 @@ public final class FrameStateBuilder implements SideEffectsState { } locals[i] = x; if (slotKind.needsTwoSlots()) { + if (i < locals.length - 2 && locals[i + 2] == TWO_SLOT_MARKER) { + /* + * Writing a two-slot marker to an index previously occupied by a two-slot value: + * clear the old marker of the second slot. + */ + locals[i + 2] = null; + } /* Writing a two-slot value: mark the second slot. */ locals[i + 1] = TWO_SLOT_MARKER; } else if (i < locals.length - 1 && locals[i + 1] == TWO_SLOT_MARKER) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Ternary.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Ternary.java new file mode 100644 index 00000000000..ee4042a2e36 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Ternary.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.lir.amd64; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.code.ValueUtil.isRegister; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; + +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.asm.amd64.AVXKind.AVXSize; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +import jdk.vm.ci.meta.AllocatableValue; + +/** + * AMD64 LIR instructions that have three inputs and one output. + */ +public class AMD64Ternary { + + /** + * Instruction that has two {@link AllocatableValue} operands. + */ + public static class ThreeOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ThreeOp.class); + + @Opcode private final VexRVMOp opcode; + private final AVXSize size; + + @Def({REG, HINT}) protected AllocatableValue result; + @Use({REG}) protected AllocatableValue x; + /** + * This argument must be Alive to ensure that result and y are not assigned to the same + * register, which would break the code generation by destroying y too early. + */ + @Alive({REG}) protected AllocatableValue y; + @Alive({REG, STACK}) protected AllocatableValue z; + + public ThreeOp(VexRVMOp opcode, AVXSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y, AllocatableValue z) { + super(TYPE); + this.opcode = opcode; + this.size = size; + + this.result = result; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + AMD64Move.move(crb, masm, result, x); + if (isRegister(z)) { + opcode.emit(masm, size, asRegister(result), asRegister(y), asRegister(z)); + } else { + assert isStackSlot(z); + opcode.emit(masm, size, asRegister(result), asRegister(y), (AMD64Address) crb.asAddress(z)); + } + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java index 7c6937ddb20..df9a48ad483 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGeneratorTool.java @@ -102,6 +102,11 @@ public interface ArithmeticLIRGeneratorTool { void emitStore(ValueKind kind, Value address, Value input, LIRFrameState state); + @SuppressWarnings("unused") + default Value emitFusedMultiplyAdd(Value a, Value b, Value c) { + throw GraalError.unimplemented("No specialized implementation available"); + } + @SuppressWarnings("unused") default Value emitMathLog(Value input, boolean base10) { throw GraalError.unimplemented("No specialized implementation available"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/TernaryNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/TernaryNode.java new file mode 100644 index 00000000000..d503083ca80 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/TernaryNode.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.nodes.calc; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.Canonicalizable; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.ValueNode; + +/** + * The {@code TernaryNode} class is the base of arithmetic and logic operations with three inputs. + */ +@NodeInfo +public abstract class TernaryNode extends FloatingNode implements Canonicalizable.Ternary { + + public static final NodeClass TYPE = NodeClass.create(TernaryNode.class); + @Input protected ValueNode x; + @Input protected ValueNode y; + @Input protected ValueNode z; + + @Override + public ValueNode getX() { + return x; + } + + @Override + public ValueNode getY() { + return y; + } + + @Override + public ValueNode getZ() { + return z; + } + + public void setX(ValueNode x) { + updateUsages(this.x, x); + this.x = x; + } + + public void setY(ValueNode y) { + updateUsages(this.y, y); + this.y = y; + } + + public void setZ(ValueNode z) { + updateUsages(this.z, z); + this.z = z; + } + + /** + * Creates a new TernaryNode instance. + * + * @param stamp the result type of this instruction + * @param x the first input instruction + * @param y the second input instruction + * @param z the second input instruction + */ + protected TernaryNode(NodeClass c, Stamp stamp, ValueNode x, ValueNode y, ValueNode z) { + super(c, stamp); + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public boolean inferStamp() { + return updateStamp(foldStamp(getX().stamp(NodeView.DEFAULT), getY().stamp(NodeView.DEFAULT), getZ().stamp(NodeView.DEFAULT))); + } + + /** + * Compute an improved stamp for this node using the passed in stamps. The stamps must be + * compatible with the current values of {@link #x}, {@link #y} and {@link #z}. This code is + * used to provide the default implementation of {@link #inferStamp()} and may be used by + * external optimizations. + * + * @param stampX + * @param stampY + * @param stampZ + */ + public abstract Stamp foldStamp(Stamp stampX, Stamp stampY, Stamp stampZ); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java index 29b5948378e..a0b908055a1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/HeapAccess.java @@ -34,17 +34,25 @@ public interface HeapAccess { */ enum BarrierType { /** - * Primitive stores which do not necessitate barriers. + * Primitive access which do not necessitate barriers. */ NONE, /** - * Array object stores which necessitate precise barriers. + * Array object access. */ - PRECISE, + ARRAY, /** - * Field object stores which necessitate imprecise barriers. + * Field object access. */ - IMPRECISE + FIELD, + /** + * Unknown (aka field or array) object access. + */ + UNKNOWN, + /** + * Weak field access (e.g. Hotspot's Reference.referent field). + */ + WEAK_FIELD } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index f10fb926300..89fd0e0b648 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -59,6 +59,7 @@ import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafePutPl import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation; import org.graalvm.compiler.replacements.nodes.BitCountNode; +import org.graalvm.compiler.replacements.nodes.FusedMultiplyAddNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation; @@ -70,7 +71,8 @@ import sun.misc.Unsafe; public class AMD64GraphBuilderPlugins { - public static void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, AMD64 arch, boolean explicitUnsafeNullChecks, boolean emitJDK9StringSubstitutions) { + public static void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, AMD64 arch, boolean explicitUnsafeNullChecks, boolean emitJDK9StringSubstitutions, + boolean useFMAIntrinsics) { InvocationPlugins invocationPlugins = plugins.getInvocationPlugins(); invocationPlugins.defer(new Runnable() { @Override @@ -86,7 +88,7 @@ public class AMD64GraphBuilderPlugins { registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider); registerStringUTF16Plugins(invocationPlugins, replacementsBytecodeProvider); } - registerMathPlugins(invocationPlugins, arch, replacementsBytecodeProvider); + registerMathPlugins(invocationPlugins, useFMAIntrinsics, arch, replacementsBytecodeProvider); registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider); } }); @@ -112,7 +114,9 @@ public class AMD64GraphBuilderPlugins { Class declaringClass = kind.toBoxedJavaClass(); Class type = kind.toJavaClass(); Registration r = new Registration(plugins, declaringClass, bytecodeProvider); + r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type); if (arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction)) { + r.setAllowOverwrite(true); r.register1("numberOfLeadingZeros", type, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { @@ -125,11 +129,13 @@ public class AMD64GraphBuilderPlugins { return true; } }); - } else { - r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type); } + + r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type); if (arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction)) { + r.setAllowOverwrite(true); r.register1("numberOfTrailingZeros", type, new InvocationPlugin() { + @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ValueNode folded = AMD64CountTrailingZerosNode.tryFold(value); @@ -141,8 +147,6 @@ public class AMD64GraphBuilderPlugins { return true; } }); - } else { - r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type); } if (arch.getFeatures().contains(AMD64.CPUFeature.POPCNT)) { @@ -154,9 +158,10 @@ public class AMD64GraphBuilderPlugins { } }); } + } - private static void registerMathPlugins(InvocationPlugins plugins, AMD64 arch, BytecodeProvider bytecodeProvider) { + private static void registerMathPlugins(InvocationPlugins plugins, boolean useFMAIntrinsics, AMD64 arch, BytecodeProvider bytecodeProvider) { Registration r = new Registration(plugins, Math.class, bytecodeProvider); registerUnaryMath(r, "log", LOG); registerUnaryMath(r, "log10", LOG10); @@ -171,6 +176,45 @@ public class AMD64GraphBuilderPlugins { registerRound(r, "ceil", RoundingMode.UP); registerRound(r, "floor", RoundingMode.DOWN); } + + if (useFMAIntrinsics && !Java8OrEarlier && arch.getFeatures().contains(CPUFeature.FMA)) { + registerFMA(r); + } + } + + private static void registerFMA(Registration r) { + r.register3("fma", + Double.TYPE, + Double.TYPE, + Double.TYPE, + new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, + ResolvedJavaMethod targetMethod, + Receiver receiver, + ValueNode na, + ValueNode nb, + ValueNode nc) { + b.push(JavaKind.Double, b.append(new FusedMultiplyAddNode(na, nb, nc))); + return true; + } + }); + r.register3("fma", + Float.TYPE, + Float.TYPE, + Float.TYPE, + new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, + ResolvedJavaMethod targetMethod, + Receiver receiver, + ValueNode na, + ValueNode nb, + ValueNode nc) { + b.push(JavaKind.Float, b.append(new FusedMultiplyAddNode(na, nb, nc))); + return true; + } + }); } private static void registerUnaryMath(Registration r, String name, UnaryOperation operation) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java index b5eac892e87..eb3fb403b08 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/RootMethodSubstitutionTest.java @@ -35,6 +35,7 @@ import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; import org.graalvm.compiler.options.OptionValues; @@ -95,7 +96,11 @@ public class RootMethodSubstitutionTest extends GraalCompilerTest { } } if (!original.isNative()) { - ret.add(new Object[]{original}); + // Make sure the plugin we found hasn't been overridden. + InvocationPlugin plugin = providers.getReplacements().getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(original); + if (plugin instanceof MethodSubstitutionPlugin) { + ret.add(new Object[]{original}); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java index 0aba8017a4d..da17f8019d4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java @@ -48,6 +48,7 @@ import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -139,6 +140,7 @@ import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.SnippetLowerableMemoryNode.SnippetLowering; import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode; import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode; +import org.graalvm.compiler.word.WordTypes; import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.CodeUtil; @@ -164,6 +166,7 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { protected final TargetDescription target; private final boolean useCompressedOops; private final ResolvedJavaType objectArrayType; + private final WordTypes wordTypes; private BoxingSnippets.Templates boxingSnippets; private ConstantStringIndexOfSnippets.Templates indexOfSnippets; @@ -174,6 +177,7 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { this.target = target; this.useCompressedOops = useCompressedOops; this.objectArrayType = metaAccess.lookupJavaType(Object[].class); + this.wordTypes = new WordTypes(metaAccess, target.wordJavaKind); } public void initialize(OptionValues options, Iterable factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) { @@ -513,7 +517,7 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { AddressNode address = createArrayIndexAddress(graph, array, elementKind, storeIndexed.index(), boundsCheck); WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value), - arrayStoreBarrierType(storeIndexed.elementKind()))); + arrayStoreBarrierType(array, storeIndexed.elementKind()))); memoryWrite.setGuard(boundsCheck); if (condition != null) { tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile); @@ -788,11 +792,11 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { long offset = fieldOffset(field); if (offset >= 0) { address = createOffsetAddress(graph, newObject, offset); - barrierType = fieldInitializationBarrier(entryKind); + barrierType = fieldInitializationBarrier(field); } } else { address = createOffsetAddress(graph, newObject, metaAccess.getArrayBaseOffset(entryKind) + i * metaAccess.getArrayIndexScale(entryKind)); - barrierType = arrayInitializationBarrier(entryKind); + barrierType = arrayInitializationBarrier(newObject, entryKind); } if (address != null) { WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType); @@ -822,10 +826,10 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { if (virtual instanceof VirtualInstanceNode) { VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual; address = createFieldAddress(graph, newObject, virtualInstance.field(i)); - barrierType = BarrierType.IMPRECISE; + barrierType = fieldStoreBarrierType(virtualInstance.field(i)); } else { address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph)); - barrierType = BarrierType.PRECISE; + barrierType = arrayStoreBarrierType(newObject, virtual.entryKind(i)); } if (address != null) { WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType); @@ -939,25 +943,50 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { } protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) { - if (field.getJavaKind() == JavaKind.Object) { - return BarrierType.IMPRECISE; + JavaKind fieldKind = wordTypes.asKind(field.getType()); + if (fieldKind == JavaKind.Object) { + return BarrierType.FIELD; } return BarrierType.NONE; } - protected BarrierType arrayStoreBarrierType(JavaKind elementKind) { - if (elementKind == JavaKind.Object) { - return BarrierType.PRECISE; + /** + * If the given value is indeed an array, and its elements are of a word type, return the + * correct word kind; in all other cases, return the defaultElementKind. This is needed for + * determining the correct write barrier type. + * + * @param array a value that is expected to have an array stamp + * @param defaultElementKind the array's element kind without taking word types into account + * @return the element kind of the array taking word types into account + */ + protected JavaKind maybeWordArrayElementKind(ValueNode array, JavaKind defaultElementKind) { + JavaKind elementKind = defaultElementKind; + Stamp arrayStamp = array.stamp(NodeView.DEFAULT); + if (arrayStamp instanceof AbstractObjectStamp && arrayStamp.hasValues()) { + ResolvedJavaType arrayType = ((AbstractObjectStamp) arrayStamp).type(); + if (arrayType != null && arrayType.getComponentType() != null) { + elementKind = wordTypes.asKind(arrayType.getComponentType()); + } + } + return elementKind; + } + + protected BarrierType arrayStoreBarrierType(ValueNode array, JavaKind elementKind) { + JavaKind kind = maybeWordArrayElementKind(array, elementKind); + if (kind == JavaKind.Object) { + return BarrierType.ARRAY; } return BarrierType.NONE; } - public BarrierType fieldInitializationBarrier(JavaKind entryKind) { - return entryKind == JavaKind.Object ? BarrierType.IMPRECISE : BarrierType.NONE; + public BarrierType fieldInitializationBarrier(ResolvedJavaField field) { + JavaKind fieldKind = wordTypes.asKind(field.getType()); + return fieldKind == JavaKind.Object ? BarrierType.FIELD : BarrierType.NONE; } - public BarrierType arrayInitializationBarrier(JavaKind entryKind) { - return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE; + public BarrierType arrayInitializationBarrier(ValueNode array, JavaKind entryKind) { + JavaKind kind = maybeWordArrayElementKind(array, entryKind); + return kind == JavaKind.Object ? BarrierType.ARRAY : BarrierType.NONE; } private BarrierType unsafeStoreBarrierType(RawStoreNode store) { @@ -972,10 +1001,14 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { ResolvedJavaType type = StampTool.typeOrNull(object); // Array types must use a precise barrier, so if the type is unknown or is a supertype // of Object[] then treat it as an array. - if (type == null || type.isArray() || type.isAssignableFrom(objectArrayType)) { - return BarrierType.PRECISE; + if (type != null && type.isArray()) { + return arrayStoreBarrierType(object, JavaKind.Object); + } else if (type != null && wordTypes.isWord(type)) { + return BarrierType.NONE; + } else if (type == null || type.isAssignableFrom(objectArrayType)) { + return BarrierType.UNKNOWN; } else { - return BarrierType.IMPRECISE; + return BarrierType.FIELD; } } return BarrierType.NONE; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FusedMultiplyAddNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FusedMultiplyAddNode.java new file mode 100644 index 00000000000..2a81c184c52 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/FusedMultiplyAddNode.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019, 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 org.graalvm.compiler.replacements.nodes; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; + +import org.graalvm.compiler.core.common.type.FloatStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.spi.CanonicalizerTool; +import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.TernaryNode; +import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import org.graalvm.compiler.serviceprovider.GraalServices; + +@NodeInfo(cycles = CYCLES_2, size = SIZE_1) +public final class FusedMultiplyAddNode extends TernaryNode implements ArithmeticLIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(FusedMultiplyAddNode.class); + + public FusedMultiplyAddNode(ValueNode a, ValueNode b, ValueNode c) { + super(TYPE, computeStamp(a.stamp(NodeView.DEFAULT), b.stamp(NodeView.DEFAULT), c.stamp(NodeView.DEFAULT)), a, b, c); + assert a.getStackKind().isNumericFloat(); + assert b.getStackKind().isNumericFloat(); + assert c.getStackKind().isNumericFloat(); + } + + @Override + public Stamp foldStamp(Stamp stampX, Stamp stampY, Stamp stampZ) { + return computeStamp(stampX, stampY, stampZ); + } + + private static Stamp computeStamp(Stamp stampX, Stamp stampY, Stamp stampZ) { + Stamp m = FloatStamp.OPS.getMul().foldStamp(stampX, stampY); + return FloatStamp.OPS.getAdd().foldStamp(m, stampZ); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode a, ValueNode b, ValueNode c) { + if (a.isConstant() && b.isConstant() && c.isConstant()) { + JavaConstant ca = a.asJavaConstant(); + JavaConstant cb = b.asJavaConstant(); + JavaConstant cc = c.asJavaConstant(); + + ValueNode res; + if (a.getStackKind() == JavaKind.Float) { + res = ConstantNode.forFloat(GraalServices.fma(ca.asFloat(), cb.asFloat(), cc.asFloat())); + } else { + assert a.getStackKind() == JavaKind.Double; + res = ConstantNode.forDouble(GraalServices.fma(ca.asDouble(), cb.asDouble(), cc.asDouble())); + } + return res; + } + return this; + } + + @Override + public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) { + builder.setResult(this, gen.emitFusedMultiplyAdd(builder.operand(getX()), builder.operand(getY()), builder.operand(getZ()))); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java index 4ad02f8a385..338db872ba1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java @@ -501,4 +501,22 @@ public final class GraalServices { } return jmx.getInputArguments(); } + + /** + * Returns the fused multiply add of the three arguments; that is, returns the exact product of + * the first two arguments summed with the third argument and then rounded once to the nearest + * {@code float}. + */ + public static float fma(float a, float b, float c) { + return Math.fma(a, b, c); + } + + /** + * Returns the fused multiply add of the three arguments; that is, returns the exact product of + * the first two arguments summed with the third argument and then rounded once to the nearest + * {@code double}. + */ + public static double fma(double a, double b, double c) { + return Math.fma(a, b, c); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java index c3083a4c947..f250e5517d8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java @@ -447,7 +447,7 @@ public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvoke protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) { assert op == Opcode.READ_POINTER || op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED; - final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); + final BarrierType barrier = (op == Opcode.READ_BARRIERED ? BarrierType.UNKNOWN : BarrierType.NONE); final boolean compressible = (op == Opcode.READ_OBJECT || op == Opcode.READ_BARRIERED); return readOp(b, readKind, address, location, barrier, compressible); @@ -465,7 +465,7 @@ public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvoke protected void writeOp(GraphBuilderContext b, JavaKind writeKind, AddressNode address, LocationIdentity location, ValueNode value, Opcode op) { assert op == Opcode.WRITE_POINTER || op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED || op == Opcode.INITIALIZE; - final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.PRECISE : BarrierType.NONE); + final BarrierType barrier = (op == Opcode.WRITE_BARRIERED ? BarrierType.UNKNOWN : BarrierType.NONE); final boolean compressible = (op == Opcode.WRITE_OBJECT || op == Opcode.WRITE_BARRIERED); assert op != Opcode.INITIALIZE || location.isInit() : "must use init location for initializing"; b.add(new JavaWriteNode(writeKind, address, location, value, barrier, compressible)); From 989fa190a601654d203b8af533de9e3b81bb317e Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Thu, 16 May 2019 18:45:30 -0400 Subject: [PATCH 036/263] 8222825: ARM32 SIGILL issue on single core CPU (not supported PLDW instruction) Reviewed-by: dholmes, dlong --- src/hotspot/cpu/arm/arm.ad | 17 ++++++++++- src/hotspot/cpu/arm/assembler_arm_32.hpp | 4 ++- src/hotspot/cpu/arm/vm_version_arm.hpp | 4 +++ src/hotspot/cpu/arm/vm_version_arm_32.cpp | 28 +++++++++++++++++-- src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp | 7 +++-- 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 354749c0d04..50d6a405689 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -4348,7 +4348,8 @@ instruct loadConD(regD dst, immD src, iRegP tmp) %{ // Prefetch instructions. // Must be safe to execute with invalid address (cannot fault). -instruct prefetchAlloc( memoryP mem ) %{ +instruct prefetchAlloc_mp( memoryP mem ) %{ + predicate(VM_Version::has_multiprocessing_extensions()); match( PrefetchAllocation mem ); ins_cost(MEMORY_REF_COST); size(4); @@ -4360,6 +4361,20 @@ instruct prefetchAlloc( memoryP mem ) %{ ins_pipe(iload_mem); %} +instruct prefetchAlloc_sp( memoryP mem ) %{ + predicate(!VM_Version::has_multiprocessing_extensions()); + match( PrefetchAllocation mem ); + ins_cost(MEMORY_REF_COST); + size(4); + + format %{ "PLD $mem\t! Prefetch allocation" %} + ins_encode %{ + __ pld($mem$$Address); + %} + ins_pipe(iload_mem); +%} + + //----------Store Instructions------------------------------------------------- // Store Byte instruct storeB(memoryB mem, store_RegI src) %{ diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp index b972d544b9a..dd2869de605 100644 --- a/src/hotspot/cpu/arm/assembler_arm_32.hpp +++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp @@ -434,7 +434,9 @@ class Assembler : public AbstractAssembler { } void pldw(Address addr) { - assert(VM_Version::arm_arch() >= 7 && os::is_MP(), "no pldw on this processor"); + assert(!VM_Version::is_initialized() || + (VM_Version::arm_arch() >= 7 && VM_Version::has_multiprocessing_extensions()), + "PLDW is available on ARMv7 with Multiprocessing Extensions only"); emit_int32(0xf510f000 | addr.encoding2()); } diff --git a/src/hotspot/cpu/arm/vm_version_arm.hpp b/src/hotspot/cpu/arm/vm_version_arm.hpp index 0b318cfaea5..2609b4fdce0 100644 --- a/src/hotspot/cpu/arm/vm_version_arm.hpp +++ b/src/hotspot/cpu/arm/vm_version_arm.hpp @@ -32,6 +32,7 @@ class VM_Version: public Abstract_VM_Version { friend class JVMCIVMStructs; static bool _has_simd; + static bool _has_mp_ext; protected: // Are we done with vm version initialization @@ -47,6 +48,7 @@ class VM_Version: public Abstract_VM_Version { vfp = 0, vfp3_32 = 1, simd = 2, + mp_ext = 3 }; enum Feature_Flag_Set { @@ -56,6 +58,7 @@ class VM_Version: public Abstract_VM_Version { vfp_m = 1 << vfp, vfp3_32_m = 1 << vfp3_32, simd_m = 1 << simd, + mp_ext_m = 1 << mp_ext }; // The value stored by "STR PC, [addr]" instruction can be either @@ -97,6 +100,7 @@ class VM_Version: public Abstract_VM_Version { static bool has_vfp() { return (_features & vfp_m) != 0; } static bool has_vfp3_32() { return (_features & vfp3_32_m) != 0; } static bool has_simd() { return (_features & simd_m) != 0; } + static bool has_multiprocessing_extensions() { return (_features & mp_ext_m) != 0; } static bool simd_math_is_compliant() { return false; } diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index 5bb3cc624e8..0adb72d026e 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -40,6 +40,7 @@ extern "C" { typedef int (*get_cpu_info_t)(); typedef bool (*check_vfp_t)(double *d); typedef bool (*check_simd_t)(); + typedef bool (*check_mp_ext_t)(int *addr); } #define __ _masm-> @@ -95,6 +96,20 @@ class VM_Version_StubGenerator: public StubCodeGenerator { return start; }; + + address generate_check_mp_ext() { + StubCodeMark mark(this, "VM_Version", "check_mp_ext"); + address start = __ pc(); + + // PLDW is available with Multiprocessing Extensions only + __ pldw(Address(R0)); + // Return true if instruction caused no signals + __ mov(R0, 1); + // JVM_handle_linux_signal moves PC here if SIGILL happens + __ bx(LR); + + return start; + }; }; #undef __ @@ -103,6 +118,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { extern "C" address check_vfp3_32_fault_instr; extern "C" address check_vfp_fault_instr; extern "C" address check_simd_fault_instr; +extern "C" address check_mp_ext_fault_instr; void VM_Version::early_initialize() { @@ -165,6 +181,13 @@ void VM_Version::initialize() { #endif #endif + address check_mp_ext_pc = g.generate_check_mp_ext(); + check_mp_ext_t check_mp_ext = CAST_TO_FN_PTR(check_mp_ext_t, check_mp_ext_pc); + check_mp_ext_fault_instr = (address)check_mp_ext; + int dummy_local_variable; + if (check_mp_ext(&dummy_local_variable)) { + _features |= mp_ext_m; + } if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { warning("AES intrinsics are not available on this CPU"); @@ -247,11 +270,12 @@ void VM_Version::initialize() { && _supports_atomic_getset8 && _supports_atomic_getadd8, "C2: atomic operations must be supported"); #endif char buf[512]; - jio_snprintf(buf, sizeof(buf), "(ARMv%d)%s%s%s", + jio_snprintf(buf, sizeof(buf), "(ARMv%d)%s%s%s%s", _arm_arch, (has_vfp() ? ", vfp" : ""), (has_vfp3_32() ? ", vfp3-32" : ""), - (has_simd() ? ", simd" : "")); + (has_simd() ? ", simd" : ""), + (has_multiprocessing_extensions() ? ", mp_ext" : "")); // buf is started with ", " or is empty _features_string = os::strdup(buf); diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 2c5ca9cce4e..d914efe3ca5 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -248,11 +248,13 @@ frame os::current_frame() { extern "C" address check_vfp_fault_instr; extern "C" address check_vfp3_32_fault_instr; +extern "C" address check_simd_fault_instr; +extern "C" address check_mp_ext_fault_instr; address check_vfp_fault_instr = NULL; address check_vfp3_32_fault_instr = NULL; -extern "C" address check_simd_fault_instr; address check_simd_fault_instr = NULL; +address check_mp_ext_fault_instr = NULL; // Utility functions @@ -271,7 +273,8 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, if (sig == SIGILL && ((info->si_addr == (caddr_t)check_simd_fault_instr) || info->si_addr == (caddr_t)check_vfp_fault_instr - || info->si_addr == (caddr_t)check_vfp3_32_fault_instr)) { + || info->si_addr == (caddr_t)check_vfp3_32_fault_instr + || info->si_addr == (caddr_t)check_mp_ext_fault_instr)) { // skip faulty instruction + instruction that sets return value to // success and set return value to failure. os::Linux::ucontext_set_pc(uc, (address)info->si_addr + 8); From 4af76639794a3644bd7abcfb43d4d7b8ae8ed735 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 16 May 2019 20:14:54 -0400 Subject: [PATCH 037/263] 8160539: Stack frame scanning acquires DerivedPointerTableGC_lock mutex Use lock-free stack for accumulating table entries. Reviewed-by: tschatzl, kvn --- src/hotspot/share/compiler/oopMap.cpp | 74 ++++++++++++----------- src/hotspot/share/compiler/oopMap.hpp | 9 ++- src/hotspot/share/runtime/mutexLocker.cpp | 2 - src/hotspot/share/runtime/mutexLocker.hpp | 1 - 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index 29aa61321f6..37f5b5e54f5 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -38,6 +38,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" #include "utilities/align.hpp" +#include "utilities/lockFreeStack.hpp" #ifdef COMPILER1 #include "c1/c1_Defs.hpp" #endif @@ -337,10 +338,6 @@ void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map, } #endif #endif // !TIERED - // Protect the operation on the derived pointers. This - // protects the addition of derived pointers to the shared - // derived pointer table in DerivedPointerTable::add(). - MutexLocker x(DerivedPointerTableGC_lock, Mutex::_no_safepoint_check_flag); do { omv = oms.current(); oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map); @@ -745,44 +742,56 @@ ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) #if COMPILER2_OR_JVMCI -class DerivedPointerEntry : public CHeapObj { - private: - oop* _location; // Location of derived pointer (also pointing to the base) - intptr_t _offset; // Offset from base pointer - public: - DerivedPointerEntry(oop* location, intptr_t offset) { _location = location; _offset = offset; } - oop* location() { return _location; } - intptr_t offset() { return _offset; } +class DerivedPointerTable::Entry : public CHeapObj { + oop* _location; // Location of derived pointer, also pointing to base + intptr_t _offset; // Offset from base pointer + Entry* volatile _next; + + static Entry* volatile* next_ptr(Entry& entry) { return &entry._next; } + +public: + Entry(oop* location, intptr_t offset) : + _location(location), _offset(offset), _next(NULL) {} + + oop* location() const { return _location; } + intptr_t offset() const { return _offset; } + Entry* next() const { return _next; } + + typedef LockFreeStack List; + static List* _list; }; - -GrowableArray* DerivedPointerTable::_list = NULL; +DerivedPointerTable::Entry::List* DerivedPointerTable::Entry::_list = NULL; bool DerivedPointerTable::_active = false; +bool DerivedPointerTable::is_empty() { + return Entry::_list == NULL || Entry::_list->empty(); +} void DerivedPointerTable::clear() { // The first time, we create the list. Otherwise it should be // empty. If not, then we have probably forgotton to call // update_pointers after last GC/Scavenge. assert (!_active, "should not be active"); - assert(_list == NULL || _list->length() == 0, "table not empty"); - if (_list == NULL) { - _list = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray(10, true); // Allocated on C heap + assert(is_empty(), "table not empty"); + if (Entry::_list == NULL) { + void* mem = NEW_C_HEAP_OBJ(Entry::List, mtCompiler); + Entry::_list = ::new (mem) Entry::List(); } _active = true; } - // Returns value of location as an int -intptr_t value_of_loc(oop *pointer) { return cast_from_oop((*pointer)); } - +inline intptr_t value_of_loc(oop *pointer) { + return cast_from_oop((*pointer)); +} void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) { assert(Universe::heap()->is_in_or_null(*base_loc), "not an oop"); assert(derived_loc != base_loc, "Base and derived in same location"); if (_active) { assert(*derived_loc != (void*)base_loc, "location already added"); - assert(_list != NULL, "list must exist"); + assert(Entry::_list != NULL, "list must exist"); intptr_t offset = value_of_loc(derived_loc) - value_of_loc(base_loc); // This assert is invalid because derived pointers can be // arbitrarily far away from their base. @@ -798,21 +807,21 @@ void DerivedPointerTable::add(oop *derived_loc, oop *base_loc) { } // Set derived oop location to point to base. *derived_loc = (oop)base_loc; - assert_lock_strong(DerivedPointerTableGC_lock); - DerivedPointerEntry *entry = new DerivedPointerEntry(derived_loc, offset); - _list->append(entry); + Entry* entry = new Entry(derived_loc, offset); + Entry::_list->push(*entry); } } - void DerivedPointerTable::update_pointers() { - assert(_list != NULL, "list must exist"); - for(int i = 0; i < _list->length(); i++) { - DerivedPointerEntry* entry = _list->at(i); + assert(Entry::_list != NULL, "list must exist"); + Entry* entries = Entry::_list->pop_all(); + while (entries != NULL) { + Entry* entry = entries; + entries = entry->next(); oop* derived_loc = entry->location(); intptr_t offset = entry->offset(); // The derived oop was setup to point to location of base - oop base = **(oop**)derived_loc; + oop base = **(oop**)derived_loc; assert(Universe::heap()->is_in_or_null(base), "must be an oop"); *derived_loc = (oop)(((address)base) + offset); @@ -826,13 +835,8 @@ void DerivedPointerTable::update_pointers() { // Delete entry delete entry; - _list->at_put(i, NULL); } - // Clear list, so it is ready for next traversal (this is an invariant) - if (TraceDerivedPointers && !_list->is_empty()) { - tty->print_cr("--------------------------"); - } - _list->clear(); + assert(Entry::_list->empty(), "invariant"); _active = false; } diff --git a/src/hotspot/share/compiler/oopMap.hpp b/src/hotspot/share/compiler/oopMap.hpp index 87d681f6108..becd6a30c96 100644 --- a/src/hotspot/share/compiler/oopMap.hpp +++ b/src/hotspot/share/compiler/oopMap.hpp @@ -29,7 +29,6 @@ #include "code/vmreg.hpp" #include "memory/allocation.hpp" #include "oops/oopsHierarchy.hpp" -#include "utilities/growableArray.hpp" // Interface for generating the frame map for compiled code. A frame map // describes for a specific pc whether each register and frame stack slot is: @@ -42,7 +41,6 @@ class frame; class RegisterMap; -class DerivedPointerEntry; class OopClosure; class OopMapValue: public StackObj { @@ -433,13 +431,14 @@ private: class DerivedPointerTable : public AllStatic { friend class VMStructs; private: - static GrowableArray* _list; - static bool _active; // do not record pointers for verify pass etc. + class Entry; + static bool _active; // do not record pointers for verify pass etc. + public: static void clear(); // Called before scavenge/GC static void add(oop *derived, oop *base); // Called during scavenge/GC static void update_pointers(); // Called after scavenge/GC - static bool is_empty() { return _list == NULL || _list->is_empty(); } + static bool is_empty(); static bool is_active() { return _active; } static void set_active(bool value) { _active = value; } }; diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index cea51313883..a5949ec085c 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -89,7 +89,6 @@ Mutex* MarkStackFreeList_lock = NULL; Mutex* MarkStackChunkList_lock = NULL; Mutex* MonitoringSupport_lock = NULL; Mutex* ParGCRareEvent_lock = NULL; -Mutex* DerivedPointerTableGC_lock = NULL; Monitor* CGCPhaseManager_lock = NULL; Mutex* Compile_lock = NULL; Monitor* MethodCompileQueue_lock = NULL; @@ -250,7 +249,6 @@ void mutex_init() { def(StringDedupTable_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never); } def(ParGCRareEvent_lock , PaddedMutex , leaf , true, Monitor::_safepoint_check_always); - def(DerivedPointerTableGC_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never); def(CGCPhaseManager_lock , PaddedMonitor, leaf, false, Monitor::_safepoint_check_always); def(CodeCache_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never); def(RawMonitor_lock , PaddedMutex , special, true, Monitor::_safepoint_check_never); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f6a003a797c..e02f60c0c1c 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -66,7 +66,6 @@ extern Monitor* CodeCache_lock; // a lock on the CodeCache, ran extern Mutex* MethodData_lock; // a lock on installation of method data extern Mutex* TouchedMethodLog_lock; // a lock on allocation of LogExecutedMethods info extern Mutex* RetData_lock; // a lock on installation of RetData inside method data -extern Mutex* DerivedPointerTableGC_lock; // a lock to protect the derived pointer table extern Monitor* CGCPhaseManager_lock; // a lock to protect a concurrent GC's phase management extern Monitor* VMOperationQueue_lock; // a lock on queue of vm_operations waiting to execute extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting for a vm_operation to terminate From 94d7b685b3214ef2e257ef34f1a6399827e4a31b Mon Sep 17 00:00:00 2001 From: Osamu Sakamoto Date: Fri, 17 May 2019 14:14:15 +0900 Subject: [PATCH 038/263] 8223665: SA: debugd options should follow jhsdb style Reviewed-by: dholmes, sspitsyn, ysuenaga, jcbeyler --- .../classes/sun/jvm/hotspot/SALauncher.java | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java index 3d4c2db9362..9fffe4bb010 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -36,8 +36,8 @@ public class SALauncher { private static boolean launcherHelp() { System.out.println(" clhsdb \tcommand line debugger"); - System.out.println(" debugd \tdebug server"); System.out.println(" hsdb \tui debugger"); + System.out.println(" debugd --help\tto get more information"); System.out.println(" jstack --help\tto get more information"); System.out.println(" jmap --help\tto get more information"); System.out.println(" jinfo --help\tto get more information"); @@ -49,25 +49,17 @@ public class SALauncher { // --pid // --exe // --core - System.out.println(" --exe\texecutable image name"); - System.out.println(" --core\tpath to coredump"); - System.out.println(" --pid\tpid of process to attach"); + System.out.println(" --exe\t"); + System.out.println(" --core\t"); + System.out.println(" --pid\t"); return false; } private static boolean debugdHelp() { // [options] [server-id] // [options] [server-id] - java.io.PrintStream out = System.out; - out.print(" [option] [server-id]"); - out.println("\t\t(to connect to a live java process)"); - out.print(" or [option] [server-id]"); - out.println("\t\t(to connect to a core file produced by )"); - out.print("\t\tserver-id is an optional unique id for this debug server, needed "); - out.println("\t\tif multiple debug servers are run on the same machine"); - out.println("where option includes:"); - out.println(" -h | -help\tto print this help message"); - return false; + System.out.println(" --serverid\t"); + return commonHelp(); } private static boolean jinfoHelp() { @@ -398,18 +390,48 @@ public class SALauncher { } private static void runDEBUGD(String[] oldArgs) { - if ((oldArgs.length < 1) || (oldArgs.length > 3)) { - debugdHelp(); - } - // By default SA agent classes prefer Windows process debugger // to windbg debugger. SA expects special properties to be set // to choose other debuggers. We will set those here before // attaching to SA agent. System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true"); + SAGetopt sg = new SAGetopt(oldArgs); + String[] longOpts = {"exe=", "core=", "pid=", "serverid="}; + + ArrayList newArgs = new ArrayList<>(); + String exe = null; + String pid = null; + String core = null; + String s = null; + String serverid = null; + + while((s = sg.next(null, longOpts)) != null) { + if (s.equals("exe")) { + exe = sg.getOptarg(); + continue; + } + if (s.equals("core")) { + core = sg.getOptarg(); + continue; + } + if (s.equals("pid")) { + pid = sg.getOptarg(); + continue; + } + if (s.equals("serverid")) { + serverid = sg.getOptarg(); + continue; + } + } + + buildAttachArgs(newArgs, pid, exe, core, false); + if (serverid != null) { + newArgs.add(serverid); + } + // delegate to the actual SA debug server. - sun.jvm.hotspot.DebugServer.main(oldArgs); + sun.jvm.hotspot.DebugServer.main(newArgs.toArray(new String[newArgs.size()])); } public static void main(String[] args) { From fd58060179917df110de9becdb7ff9bd6d67c454 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 16 May 2019 13:21:41 +0200 Subject: [PATCH 039/263] 8223944: fix zlib related building docu and comments Reviewed-by: alanb, erikj --- doc/building.html | 4 ++-- doc/building.md | 9 ++++++--- make/autoconf/lib-bundled.m4 | 11 +++++++---- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/building.html b/doc/building.html index 96d6ee0e4c8..5246086b98a 100644 --- a/doc/building.html +++ b/doc/building.html @@ -184,7 +184,7 @@ Solaris -Solaris 11.3 +Solaris 11.3 SRU 20 macOS @@ -497,7 +497,7 @@ CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30
  • --with-libffi=<path> - Set the path to libffi
  • --with-jtreg=<path> - Set the path to JTReg. See Running Tests
  • -

    Certain third-party libraries used by the JDK (libjpeg, giflib, libpng, lcms and zlib) are included in the JDK repository. The default behavior of the JDK build is to use this version of these libraries, but they might be replaced by an external version. To do so, specify system as the <source> option in these arguments. (The default is bundled).

    +

    Certain third-party libraries used by the JDK (libjpeg, giflib, libpng, lcms and zlib) are included in the JDK repository. The default behavior of the JDK build is to use the included ("bundled") versions of libjpeg, giflib, libpng and lcms. For zlib, the system lib (if present) is used except on Windows and AIX. However the bundled libraries may be replaced by an external version. To do so, specify system as the <source> option in these arguments. (The default is bundled).