# HG changeset patch # User jwilhelm # Date 1518251135 -3600 # Node ID 7c23209e4873b3adf84c006a0e824e0dcbccadc9 # Parent 0006d97556ba063b7c526b679bcd91a6a1571365# Parent 368d7a786111fd1e02943108968857e37163de45 Merge diff -r 0006d97556ba -r 7c23209e4873 make/CompileJavaModules.gmk --- a/make/CompileJavaModules.gmk Tue Feb 13 14:41:54 2018 -0500 +++ b/make/CompileJavaModules.gmk Sat Feb 10 09:25:35 2018 +0100 @@ -443,6 +443,7 @@ # jdk.internal.vm.compiler_EXCLUDES += \ + org.graalvm.collections.test \ org.graalvm.compiler.core.match.processor \ org.graalvm.compiler.nodeinfo.processor \ org.graalvm.compiler.options.processor \ @@ -461,6 +462,7 @@ org.graalvm.compiler.graph.test \ org.graalvm.compiler.hotspot.amd64.test \ org.graalvm.compiler.hotspot.lir.test \ + org.graalvm.compiler.hotspot.sparc.test \ org.graalvm.compiler.hotspot.test \ org.graalvm.compiler.jtt \ org.graalvm.compiler.lir.jtt \ diff -r 0006d97556ba -r 7c23209e4873 make/CompileToolsHotspot.gmk --- a/make/CompileToolsHotspot.gmk Tue Feb 13 14:41:54 2018 -0500 +++ b/make/CompileToolsHotspot.gmk Sat Feb 10 09:25:35 2018 +0100 @@ -48,6 +48,7 @@ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ $(SRC_DIR)/org.graalvm.word/src \ + $(SRC_DIR)/org.graalvm.collections/src \ $(SRC_DIR)/org.graalvm.compiler.core/src \ $(SRC_DIR)/org.graalvm.compiler.core.common/src \ $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \ @@ -101,6 +102,7 @@ $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ + $(SRC_DIR)/org.graalvm.collections/src \ $(SRC_DIR)/org.graalvm.compiler.options/src \ $(SRC_DIR)/org.graalvm.compiler.options.processor/src \ $(SRC_DIR)/org.graalvm.util/src \ @@ -117,6 +119,7 @@ SETUP := GENERATE_OLDBYTECODE, \ SRC := \ $(SRC_DIR)/org.graalvm.word/src \ + $(SRC_DIR)/org.graalvm.collections/src \ $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \ $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ $(SRC_DIR)/org.graalvm.compiler.code/src \ diff -r 0006d97556ba -r 7c23209e4873 make/conf/jib-profiles.js diff -r 0006d97556ba -r 7c23209e4873 make/test/JtregNativeHotspot.gmk --- a/make/test/JtregNativeHotspot.gmk Tue Feb 13 14:41:54 2018 -0500 +++ b/make/test/JtregNativeHotspot.gmk Sat Feb 10 09:25:35 2018 +0100 @@ -67,6 +67,7 @@ $(TOPDIR)/test/hotspot/jtreg/compiler/calls \ $(TOPDIR)/test/hotspot/jtreg/compiler/runtime/criticalnatives/lookup \ $(TOPDIR)/test/hotspot/jtreg/compiler/runtime/criticalnatives/argumentcorruption \ + $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook \ $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorInfo \ $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorStackDepthInfo \ $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetNamedModule \ @@ -101,6 +102,7 @@ ifeq ($(TOOLCHAIN_TYPE), solstudio) BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_liboverflow := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libSimpleClassFileLoadHook := -lc + BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCanGenerateAllClassHook := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetOwnedMonitorInfoTest := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetOwnedMonitorStackDepthInfoTest := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetNamedModuleTest := -lc diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2532,7 +2532,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); __ mov_metadata(mdo, md->constant_encoding()); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, 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 @@ -3150,7 +3150,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); assert(op->tmp1()->is_register(), "tmp1 must be allocated"); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2017, SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2746,7 +2746,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); #ifdef _LP64 diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017, SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2715,7 +2715,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp --- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -2761,7 +2761,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -3504,7 +3504,7 @@ ciMethodData* md = method->method_data_or_null(); assert(md != NULL, "Sanity"); ciProfileData* data = md->bci_to_data(bci); - assert(data->is_CounterData(), "need CounterData for calls"); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); __ mov_metadata(mdo, md->constant_encoding()); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/cpu/x86/stubGenerator_x86_32.cpp --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -676,6 +676,7 @@ assert_different_registers(start, count); BarrierSet* bs = Universe::heap()->barrier_set(); switch (bs->kind()) { +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!uninitialized_target) { @@ -703,6 +704,7 @@ __ bind(filtered); } break; +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: case BarrierSet::ModRef: @@ -726,6 +728,7 @@ BarrierSet* bs = Universe::heap()->barrier_set(); assert_different_registers(start, count); switch (bs->kind()) { +#if INCLUDE_ALL_GCS case BarrierSet::G1SATBCTLogging: { __ pusha(); // push registers @@ -734,6 +737,7 @@ __ popa(); } break; +#endif // INCLUDE_ALL_GCS case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/aix/os_aix.cpp --- a/src/hotspot/os/aix/os_aix.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/aix/os_aix.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -188,6 +188,7 @@ //////////////////////////////////////////////////////////////////////////////// // local variables +static volatile jlong max_real_time = 0; static jlong initial_time_count = 0; static int clock_tics_per_sec = 100; static sigset_t check_signal_done; // For diagnostics to print a message once (see run_periodic_checks) @@ -1076,32 +1077,50 @@ nanos = jlong(time.tv_usec) * 1000; } +// We use mread_real_time here. +// On AIX: If the CPU has a time register, the result will be RTC_POWER and +// it has to be converted to real time. AIX documentations suggests to do +// this unconditionally, so we do it. +// +// See: https://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.basetrf2/read_real_time.htm +// +// On PASE: mread_real_time will always return RTC_POWER_PC data, so no +// conversion is necessary. However, mread_real_time will not return +// monotonic results but merely matches read_real_time. So we need a tweak +// to ensure monotonic results. +// +// For PASE no public documentation exists, just word by IBM jlong os::javaTimeNanos() { + timebasestruct_t time; + int rc = mread_real_time(&time, TIMEBASE_SZ); if (os::Aix::on_pase()) { - - timeval time; - int status = gettimeofday(&time, NULL); - assert(status != -1, "PASE error at gettimeofday()"); - jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec); - return 1000 * usecs; - + assert(rc == RTC_POWER, "expected time format RTC_POWER from mread_real_time in PASE"); + jlong now = jlong(time.tb_high) * NANOSECS_PER_SEC + jlong(time.tb_low); + jlong prev = max_real_time; + if (now <= prev) { + return prev; // same or retrograde time; + } + jlong obsv = Atomic::cmpxchg(now, &max_real_time, prev); + assert(obsv >= prev, "invariant"); // Monotonicity + // If the CAS succeeded then we're done and return "now". + // If the CAS failed and the observed value "obsv" is >= now then + // we should return "obsv". If the CAS failed and now > obsv > prv then + // some other thread raced this thread and installed a new value, in which case + // we could either (a) retry the entire operation, (b) retry trying to install now + // or (c) just return obsv. We use (c). No loop is required although in some cases + // we might discard a higher "now" value in deference to a slightly lower but freshly + // installed obsv value. That's entirely benign -- it admits no new orderings compared + // to (a) or (b) -- and greatly reduces coherence traffic. + // We might also condition (c) on the magnitude of the delta between obsv and now. + // Avoiding excessive CAS operations to hot RW locations is critical. + // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate + return (prev == obsv) ? now : obsv; } else { - // On AIX use the precision of processors real time clock - // or time base registers. - timebasestruct_t time; - int rc; - - // If the CPU has a time register, it will be used and - // we have to convert to real time first. After convertion we have following data: - // time.tb_high [seconds since 00:00:00 UTC on 1.1.1970] - // time.tb_low [nanoseconds after the last full second above] - // We better use mread_real_time here instead of read_real_time - // to ensure that we will get a monotonic increasing time. - if (mread_real_time(&time, TIMEBASE_SZ) != RTC_POWER) { + if (rc != RTC_POWER) { rc = time_base_to_time(&time, TIMEBASE_SZ); - assert(rc != -1, "aix error at time_base_to_time()"); + assert(rc != -1, "error calling time_base_to_time()"); } - return jlong(time.tb_high) * (1000 * 1000 * 1000) + jlong(time.tb_low); + return jlong(time.tb_high) * NANOSECS_PER_SEC + jlong(time.tb_low); } } diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/bsd/jvm_bsd.cpp --- a/src/hotspot/os/bsd/jvm_bsd.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/bsd/jvm_bsd.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, 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 @@ -51,6 +51,12 @@ case SIGILL: case SIGSEGV: +#if defined(__APPLE__) + /* On Darwin, memory access errors commonly results in SIGBUS instead + * of SIGSEGV. */ + case SIGBUS: +#endif + /* The following signal is used by the VM to dump thread stacks unless ReduceSignalUsage is set, in which case the user is allowed to set his own _native_ handler for this signal; thus, in either case, diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/bsd/os_bsd.cpp --- a/src/hotspot/os/bsd/os_bsd.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/bsd/os_bsd.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -2206,7 +2206,7 @@ bool os::release_memory_special(char* base, size_t bytes) { if (MemTracker::tracking_level() > NMT_minimal) { - Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + Tracker tkr(Tracker::release); // detaching the SHM segment will also delete it, see reserve_memory_special() int rslt = shmdt(base); if (rslt == 0) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/linux/osContainer_linux.cpp --- a/src/hotspot/os/linux/osContainer_linux.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/linux/osContainer_linux.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -122,35 +122,40 @@ char file[MAXPATHLEN+1]; char buf[MAXPATHLEN+1]; - if (c != NULL && c->subsystem_path() != NULL) { - strncpy(file, c->subsystem_path(), MAXPATHLEN); - file[MAXPATHLEN-1] = '\0'; - int filelen = strlen(file); - if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { - log_debug(os, container)("File path too long %s, %s", file, filename); - return OSCONTAINER_ERROR; - } - strncat(file, filename, MAXPATHLEN-filelen); - log_trace(os, container)("Path to %s is %s", filename, file); - fp = fopen(file, "r"); - if (fp != NULL) { - p = fgets(buf, MAXPATHLEN, fp); - if (p != NULL) { - int matched = sscanf(p, scan_fmt, returnval); - if (matched == 1) { - fclose(fp); - return 0; - } else { - log_debug(os, container)("Type %s not found in file %s", - scan_fmt , file); - } + if (c == NULL) { + log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL"); + return OSCONTAINER_ERROR; + } + if (c->subsystem_path() == NULL) { + log_debug(os, container)("subsystem_file_contents: subsystem path is NULL"); + return OSCONTAINER_ERROR; + } + + strncpy(file, c->subsystem_path(), MAXPATHLEN); + file[MAXPATHLEN-1] = '\0'; + int filelen = strlen(file); + if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) { + log_debug(os, container)("File path too long %s, %s", file, filename); + return OSCONTAINER_ERROR; + } + strncat(file, filename, MAXPATHLEN-filelen); + log_trace(os, container)("Path to %s is %s", filename, file); + fp = fopen(file, "r"); + if (fp != NULL) { + p = fgets(buf, MAXPATHLEN, fp); + if (p != NULL) { + int matched = sscanf(p, scan_fmt, returnval); + if (matched == 1) { + fclose(fp); + return 0; } else { - log_debug(os, container)("Empty file %s", file); + log_debug(os, container)("Type %s not found in file %s", scan_fmt, file); } } else { - log_debug(os, container)("Open of file %s failed, %s", file, - os::strerror(errno)); + log_debug(os, container)("Empty file %s", file); } + } else { + log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno)); } if (fp != NULL) fclose(fp); @@ -273,7 +278,7 @@ else { log_debug(os, container)("Incompatible str containing cgroup and cpuset: %s", p); } - } else if (strstr(p, "cpu,cpuacct") != NULL) { + } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) { int matched = sscanf(p, "%d %d %d:%d %s %s", &mountid, &parentid, @@ -322,8 +327,20 @@ fclose(mntinfo); - if (memory == NULL || cpuset == NULL || cpu == NULL || cpuacct == NULL) { - log_debug(os, container)("Required cgroup subsystems not found"); + if (memory == NULL) { + log_debug(os, container)("Required cgroup memory subsystem not found"); + return; + } + if (cpuset == NULL) { + log_debug(os, container)("Required cgroup cpuset subsystem not found"); + return; + } + if (cpu == NULL) { + log_debug(os, container)("Required cgroup cpu subsystem not found"); + return; + } + if (cpuacct == NULL) { + log_debug(os, container)("Required cgroup cpuacct subsystem not found"); return; } @@ -374,7 +391,7 @@ memory->set_subsystem_path(base); } else if (strstr(controller, "cpuset") != NULL) { cpuset->set_subsystem_path(base); - } else if (strstr(controller, "cpu,cpuacct") != NULL) { + } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) { cpu->set_subsystem_path(base); cpuacct->set_subsystem_path(base); } else if (strstr(controller, "cpuacct") != NULL) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/linux/os_linux.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -3862,7 +3862,7 @@ bool os::release_memory_special(char* base, size_t bytes) { bool res; if (MemTracker::tracking_level() > NMT_minimal) { - Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + Tracker tkr(Tracker::release); res = os::Linux::release_memory_special_impl(base, bytes); if (res) { tkr.record((address)base, bytes); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/os/windows/perfMemory_windows.cpp --- a/src/hotspot/os/windows/perfMemory_windows.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/os/windows/perfMemory_windows.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, 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 @@ -1840,7 +1840,7 @@ if (MemTracker::tracking_level() > NMT_minimal) { // it does not go through os api, the operation has to record from here - Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + Tracker tkr(Tracker::release); remove_file_mapping(addr); tkr.record((address)addr, bytes); } else { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/c1/c1_GraphBuilder.cpp --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, 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 @@ -1556,8 +1556,6 @@ } if (profile_return() && x->type()->is_object_kind()) { ciMethod* caller = state()->scope()->method(); - ciMethodData* md = caller->method_data_or_null(); - ciProfileData* data = md->bci_to_data(invoke_bci); profile_return_type(x, method(), caller, invoke_bci); } } diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/classfile/classLoaderData.cpp --- a/src/hotspot/share/classfile/classLoaderData.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/classfile/classLoaderData.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -80,6 +80,9 @@ #include "trace/tracing.hpp" #endif +volatile size_t ClassLoaderDataGraph::_num_array_classes = 0; +volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0; + ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) : @@ -329,36 +332,36 @@ ClassLoaderData * const from_cld = this; ClassLoaderData * const to_cld = k->class_loader_data(); - // Dependency to the null class loader data doesn't need to be recorded - // because the null class loader data never goes away. - if (to_cld->is_the_null_class_loader_data()) { + // Do not need to record dependency if the dependency is to a class whose + // class loader data is never freed. (i.e. the dependency's class loader + // is one of the three builtin class loaders and the dependency is not + // anonymous.) + if (to_cld->is_permanent_class_loader_data()) { return; } oop to; if (to_cld->is_anonymous()) { + // Just return if an anonymous class is attempting to record a dependency + // to itself. (Note that every anonymous class has its own unique class + // loader data.) + if (to_cld == from_cld) { + return; + } // Anonymous class dependencies are through the mirror. to = k->java_mirror(); } else { to = to_cld->class_loader(); - - // If from_cld is anonymous, even if it's class_loader is a parent of 'to' - // we still have to add it. The class_loader won't keep from_cld alive. - if (!from_cld->is_anonymous()) { - // Check that this dependency isn't from the same or parent class_loader - oop from = from_cld->class_loader(); + oop from = from_cld->class_loader(); - oop curr = from; - while (curr != NULL) { - if (curr == to) { - return; // this class loader is in the parent list, no need to add it. - } - curr = java_lang_ClassLoader::parent(curr); - } + // Just return if this dependency is to a class with the same or a parent + // class_loader. + if (from == to || java_lang_ClassLoader::isAncestor(from, to)) { + return; // this class loader is in the parent list, no need to add it. } } - // It's a dependency we won't find through GC, add it. This is relatively rare + // It's a dependency we won't find through GC, add it. This is relatively rare. // Must handle over GC point. Handle dependency(THREAD, to); from_cld->_dependencies.add(dependency, CHECK); @@ -443,6 +446,11 @@ // Link the new item into the list, making sure the linked class is stable // since the list can be walked without a lock OrderAccess::release_store(&_klasses, k); + if (k->is_array_klass()) { + ClassLoaderDataGraph::inc_array_classes(1); + } else { + ClassLoaderDataGraph::inc_instance_classes(1); + } } if (publicize && k->class_loader_data() != NULL) { @@ -468,9 +476,9 @@ InstanceKlass* try_get_next_class() { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); - int max_classes = InstanceKlass::number_of_instance_classes(); + size_t max_classes = ClassLoaderDataGraph::num_instance_classes(); assert(max_classes > 0, "should not be called with no instance classes"); - for (int i = 0; i < max_classes; ) { + for (size_t i = 0; i < max_classes; ) { if (_current_class_entry != NULL) { Klass* k = _current_class_entry; @@ -545,6 +553,13 @@ Klass* next = k->next_link(); prev->set_next_link(next); } + + if (k->is_array_klass()) { + ClassLoaderDataGraph::dec_array_classes(1); + } else { + ClassLoaderDataGraph::dec_instance_classes(1); + } + return; } prev = k; @@ -639,9 +654,34 @@ return alive; } +class ReleaseKlassClosure: public KlassClosure { +private: + size_t _instance_class_released; + size_t _array_class_released; +public: + ReleaseKlassClosure() : _instance_class_released(0), _array_class_released(0) { } + + size_t instance_class_released() const { return _instance_class_released; } + size_t array_class_released() const { return _array_class_released; } + + void do_klass(Klass* k) { + if (k->is_array_klass()) { + _array_class_released ++; + } else { + assert(k->is_instance_klass(), "Must be"); + _instance_class_released ++; + InstanceKlass::release_C_heap_structures(InstanceKlass::cast(k)); + } + } +}; + ClassLoaderData::~ClassLoaderData() { // Release C heap structures for all the classes. - classes_do(InstanceKlass::release_C_heap_structures); + ReleaseKlassClosure cl; + classes_do(&cl); + + ClassLoaderDataGraph::dec_array_classes(cl.array_class_released()); + ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released()); // Release C heap allocated hashtable for all the packages. if (_packages != NULL) { @@ -693,25 +733,37 @@ } } -// Returns true if this class loader data is for the system class loader. +// Returns true if this class loader data is for the app class loader +// or a user defined system class loader. (Note that the class loader +// data may be anonymous.) bool ClassLoaderData::is_system_class_loader_data() const { return SystemDictionary::is_system_class_loader(class_loader()); } // Returns true if this class loader data is for the platform class loader. +// (Note that the class loader data may be anonymous.) bool ClassLoaderData::is_platform_class_loader_data() const { return SystemDictionary::is_platform_class_loader(class_loader()); } -// Returns true if this class loader data is one of the 3 builtin -// (boot, application/system or platform) class loaders. Note, the -// builtin loaders are not freed by a GC. +// Returns true if the class loader for this class loader data is one of +// the 3 builtin (boot application/system or platform) class loaders, +// including a user-defined system class loader. Note that if the class +// loader data is for an anonymous class then it may get freed by a GC +// even if its class loader is one of these loaders. bool ClassLoaderData::is_builtin_class_loader_data() const { - return (is_the_null_class_loader_data() || + return (is_boot_class_loader_data() || SystemDictionary::is_system_class_loader(class_loader()) || SystemDictionary::is_platform_class_loader(class_loader())); } +// Returns true if this class loader data is a class loader data +// that is not ever freed by a GC. It must be one of the builtin +// class loaders and not anonymous. +bool ClassLoaderData::is_permanent_class_loader_data() const { + return is_builtin_class_loader_data() && !is_anonymous(); +} + Metaspace* ClassLoaderData::metaspace_non_null() { // If the metaspace has not been allocated, create a new one. Might want // to create smaller arena for Reflection class loaders also. diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/classfile/classLoaderData.hpp --- a/src/hotspot/share/classfile/classLoaderData.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/classfile/classLoaderData.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -80,6 +80,9 @@ // allocations until class unloading static bool _metaspace_oom; + static volatile size_t _num_instance_classes; + static volatile size_t _num_array_classes; + static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); static void post_class_unload_events(); public: @@ -154,6 +157,15 @@ static void print_creation(outputStream* out, Handle loader, ClassLoaderData* cld, TRAPS); static bool unload_list_contains(const void* x); + + // instance and array class counters + static inline size_t num_instance_classes(); + static inline size_t num_array_classes(); + static inline void inc_instance_classes(size_t count); + static inline void dec_instance_classes(size_t count); + static inline void inc_array_classes(size_t count); + static inline void dec_array_classes(size_t count); + #ifndef PRODUCT static bool contains_loader_data(ClassLoaderData* loader_data); #endif @@ -344,7 +356,15 @@ } bool is_system_class_loader_data() const; bool is_platform_class_loader_data() const; + + // Returns true if this class loader data is for the boot class loader. + // (Note that the class loader data may be anonymous.) + bool is_boot_class_loader_data() const { + return class_loader() == NULL; + } + bool is_builtin_class_loader_data() const; + bool is_permanent_class_loader_data() const; // The Metaspace is created lazily so may be NULL. This // method will allocate a Metaspace if needed. diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/classfile/classLoaderData.inline.hpp --- a/src/hotspot/share/classfile/classLoaderData.inline.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/classfile/classLoaderData.inline.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,3 +50,29 @@ } return ClassLoaderDataGraph::add(loader, false, THREAD); } + +size_t ClassLoaderDataGraph::num_instance_classes() { + return _num_instance_classes; +} + +size_t ClassLoaderDataGraph::num_array_classes() { + return _num_array_classes; +} + +void ClassLoaderDataGraph::inc_instance_classes(size_t count) { + Atomic::add(count, &_num_instance_classes); +} + +void ClassLoaderDataGraph::dec_instance_classes(size_t count) { + assert(count <= _num_instance_classes, "Sanity"); + Atomic::sub(count, &_num_instance_classes); +} + +void ClassLoaderDataGraph::inc_array_classes(size_t count) { + Atomic::add(count, &_num_array_classes); +} + +void ClassLoaderDataGraph::dec_array_classes(size_t count) { + assert(count <= _num_array_classes, "Sanity"); + Atomic::sub(count, &_num_array_classes); +} diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/classfile/moduleEntry.hpp --- a/src/hotspot/share/classfile/moduleEntry.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/classfile/moduleEntry.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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,7 +103,11 @@ void set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd); ClassLoaderData* loader_data() const { return _loader_data; } - void set_loader_data(ClassLoaderData* l) { _loader_data = l; } + + void set_loader_data(ClassLoaderData* cld) { + assert(!cld->is_anonymous(), "Unexpected anonymous class loader data"); + _loader_data = cld; + } Symbol* version() const { return _version; } void set_version(Symbol* version); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/code/compiledIC.cpp --- a/src/hotspot/share/code/compiledIC.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/code/compiledIC.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -417,7 +417,7 @@ bool static_bound = info.is_optimized() || (info.cached_metadata() == NULL); #ifdef ASSERT CodeBlob* cb = CodeCache::find_blob_unsafe(info.entry()); - assert (cb->is_compiled(), "must be compiled!"); + assert (cb != NULL && cb->is_compiled(), "must be compiled!"); #endif /* ASSERT */ // This is MT safe if we come from a clean-cache and go through a diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/code/nmethod.cpp --- a/src/hotspot/share/code/nmethod.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/code/nmethod.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -955,6 +955,7 @@ CompiledIC *ic = CompiledIC_at(&iter); // Ok, to lookup references to zombies here CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination()); + assert(cb != NULL, "destination not in CodeBlob?"); nmethod* nm = cb->as_nmethod_or_null(); if( nm != NULL ) { // Verify that inline caches pointing to both zombie and not_entrant methods are clean @@ -967,6 +968,7 @@ case relocInfo::static_call_type: { CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc()); CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination()); + assert(cb != NULL, "destination not in CodeBlob?"); nmethod* nm = cb->as_nmethod_or_null(); if( nm != NULL ) { // Verify that inline caches pointing to both zombie and not_entrant methods are clean @@ -2732,7 +2734,7 @@ virtual void verify_resolve_call(address dest) const { CodeBlob* db = CodeCache::find_blob_unsafe(dest); - assert(!db->is_adapter_blob(), "must use stub!"); + assert(db != NULL && !db->is_adapter_blob(), "must use stub!"); } virtual bool is_call_to_interpreted(address dest) const { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/gc/shared/oopStorage.cpp --- a/src/hotspot/share/gc/shared/oopStorage.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/gc/shared/oopStorage.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -26,7 +26,9 @@ #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" +#include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" @@ -107,7 +109,7 @@ } // Blocks start with an array of BitsPerWord oop entries. That array -// is divided into conceptual BytesPerWord sections of BitsPerWord +// is divided into conceptual BytesPerWord sections of BitsPerByte // entries. Blocks are allocated aligned on section boundaries, for // the convenience of mapping from an entry to the containing block; // see block_for_ptr(). Aligning on section boundary rather than on @@ -130,7 +132,9 @@ _owner(owner), _memory(memory), _active_entry(), - _allocate_entry() + _allocate_entry(), + _deferred_updates_next(NULL), + _release_refcount(0) { STATIC_ASSERT(_data_pos == 0); STATIC_ASSERT(section_size * section_count == ARRAY_SIZE(_data)); @@ -143,6 +147,8 @@ #endif OopStorage::Block::~Block() { + assert(_release_refcount == 0, "deleting block while releasing"); + assert(_deferred_updates_next == NULL, "deleting block with deferred update"); // Clear fields used by block_for_ptr and entry validation, which // might help catch bugs. Volatile to prevent dead-store elimination. const_cast(_allocated_bitmask) = 0; @@ -182,8 +188,24 @@ return bitmask_for_index(get_index(ptr)); } -uintx OopStorage::Block::cmpxchg_allocated_bitmask(uintx new_value, uintx compare_value) { - return Atomic::cmpxchg(new_value, &_allocated_bitmask, compare_value); +// A block is deletable if +// (1) It is empty. +// (2) There is not a release() operation currently operating on it. +// (3) It is not in the deferred updates list. +// The order of tests is important for proper interaction between release() +// and concurrent deletion. +bool OopStorage::Block::is_deletable() const { + return (OrderAccess::load_acquire(&_allocated_bitmask) == 0) && + (OrderAccess::load_acquire(&_release_refcount) == 0) && + (OrderAccess::load_acquire(&_deferred_updates_next) == NULL); +} + +OopStorage::Block* OopStorage::Block::deferred_updates_next() const { + return _deferred_updates_next; +} + +void OopStorage::Block::set_deferred_updates_next(Block* block) { + _deferred_updates_next = block; } bool OopStorage::Block::contains(const oop* ptr) const { @@ -203,7 +225,7 @@ assert(!is_full_bitmask(allocated), "attempt to allocate from full block"); unsigned index = count_trailing_zeros(~allocated); uintx new_value = allocated | bitmask_for_index(index); - uintx fetched = cmpxchg_allocated_bitmask(new_value, allocated); + uintx fetched = Atomic::cmpxchg(new_value, &_allocated_bitmask, allocated); if (fetched == allocated) { return get_pointer(index); // CAS succeeded; return entry for index. } @@ -261,20 +283,6 @@ return NULL; } -bool OopStorage::is_valid_block_locked_or_safepoint(const Block* check_block) const { - assert_locked_or_safepoint(_allocate_mutex); - // For now, simple linear search. Do something more clever if this - // is a performance bottleneck, particularly for allocation_status. - for (const Block* block = _active_list.chead(); - block != NULL; - block = _active_list.next(*block)) { - if (check_block == block) { - return true; - } - } - return false; -} - #ifdef ASSERT void OopStorage::assert_at_safepoint() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); @@ -291,39 +299,49 @@ // kept at the end of the _allocate_list, to make it easy for empty block // deletion to find them. // -// allocate(), release(), and delete_empty_blocks_concurrent() all lock the +// allocate(), and delete_empty_blocks_concurrent() lock the // _allocate_mutex while performing any list modifications. // // allocate() and release() update a block's _allocated_bitmask using CAS -// loops. This prevents loss of updates even though release() may perform -// some updates without any locking. +// loops. This prevents loss of updates even though release() performs +// its updates without any locking. // // allocate() obtains the entry from the first block in the _allocate_list, // and updates that block's _allocated_bitmask to indicate the entry is in // use. If this makes the block full (all entries in use), the block is // removed from the _allocate_list so it won't be considered by future -// allocations until some entries in it are relased. +// allocations until some entries in it are released. // -// release() looks up the block for the entry without locking. Once the block -// has been determined, its _allocated_bitmask needs to be updated, and its -// position in the _allocate_list may need to be updated. There are two -// cases: +// release() is performed lock-free. release() first looks up the block for +// the entry, using address alignment to find the enclosing block (thereby +// avoiding iteration over the _active_list). Once the block has been +// determined, its _allocated_bitmask needs to be updated, and its position in +// the _allocate_list may need to be updated. There are two cases: // // (a) If the block is neither full nor would become empty with the release of // the entry, only its _allocated_bitmask needs to be updated. But if the CAS // update fails, the applicable case may change for the retry. // -// (b) Otherwise, the _allocate_list will also need to be modified. This -// requires locking the _allocate_mutex, and then attempting to CAS the -// _allocated_bitmask. If the CAS fails, the applicable case may change for -// the retry. If the CAS succeeds, then update the _allocate_list according -// to the the state changes. If the block changed from full to not full, then -// it needs to be added to the _allocate_list, for use in future allocations. -// If the block changed from not empty to empty, then it is moved to the end -// of the _allocate_list, for ease of empty block deletion processing. +// (b) Otherwise, the _allocate_list also needs to be modified. This requires +// locking the _allocate_mutex. To keep the release() operation lock-free, +// rather than updating the _allocate_list itself, it instead performs a +// lock-free push of the block onto the _deferred_updates list. Entries on +// that list are processed by allocate() and delete_empty_blocks_XXX(), while +// they already hold the necessary lock. That processing makes the block's +// list state consistent with its current _allocated_bitmask. The block is +// added to the _allocate_list if not already present and the bitmask is not +// full. The block is moved to the end of the _allocated_list if the bitmask +// is empty, for ease of empty block deletion processing. oop* OopStorage::allocate() { MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); + // Do some deferred update processing every time we allocate. + // Continue processing deferred updates if _allocate_list is empty, + // in the hope that we'll get a block from that, rather than + // allocating a new block. + while (reduce_deferred_updates() && (_allocate_list.head() == NULL)) {} + + // Use the first block in _allocate_list for the allocation. Block* block = _allocate_list.head(); if (block == NULL) { // No available blocks; make a new one, and add to storage. @@ -331,7 +349,17 @@ MutexUnlockerEx mul(_allocate_mutex, Mutex::_no_safepoint_check_flag); block = Block::new_block(this); } - if (block != NULL) { + if (block == NULL) { + while (_allocate_list.head() == NULL) { + if (!reduce_deferred_updates()) { + // Failed to make new block, no other thread made a block + // available while the mutex was released, and didn't get + // one from a deferred update either, so return failure. + log_info(oopstorage, ref)("%s: failed allocation", name()); + return NULL; + } + } + } else { // Add new block to storage. log_info(oopstorage, blocks)("%s: new block " PTR_FORMAT, name(), p2i(block)); @@ -340,22 +368,14 @@ // to allocate from non-empty blocks, to allow empty blocks to // be deleted. _allocate_list.push_back(*block); - ++_empty_block_count; // Add to front of _active_list, and then record as the head // block, for concurrent iteration protocol. _active_list.push_front(*block); ++_block_count; // Ensure all setup of block is complete before making it visible. OrderAccess::release_store(&_active_head, block); - } else { - log_info(oopstorage, blocks)("%s: failed new block allocation", name()); } block = _allocate_list.head(); - if (block == NULL) { - // Failed to make new block, and no other thread made a block - // available while the mutex was released, so return failure. - return NULL; - } } // Allocate from first block. assert(block != NULL, "invariant"); @@ -363,7 +383,6 @@ if (block->is_empty()) { // Transitioning from empty to not empty. log_debug(oopstorage, blocks)("%s: block not empty " PTR_FORMAT, name(), p2i(block)); - --_empty_block_count; } oop* result = block->allocate(); assert(result != NULL, "allocation failed"); @@ -384,72 +403,115 @@ return Block::block_for_ptr(this, ptr); } -void OopStorage::release_from_block(Block& block, uintx releasing) { - assert(releasing != 0, "invariant"); - uintx allocated = block.allocated_bitmask(); - while (true) { - assert(releasing == (allocated & releasing), "invariant"); - uintx new_value = allocated ^ releasing; - // CAS new_value into block's allocated bitmask, retrying with - // updated allocated bitmask until the CAS succeeds. - uintx fetched; - if (!is_full_bitmask(allocated) && !is_empty_bitmask(new_value)) { - fetched = block.cmpxchg_allocated_bitmask(new_value, allocated); - if (fetched == allocated) return; - } else { - // Need special handling if transitioning from full to not full, - // or from not empty to empty. For those cases, must hold the - // _allocation_mutex when updating the allocated bitmask, to - // ensure the associated list manipulations will be consistent - // with the allocation bitmask that is visible to other threads - // in allocate() or deleting empty blocks. - MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); - fetched = block.cmpxchg_allocated_bitmask(new_value, allocated); - if (fetched == allocated) { - // CAS succeeded; handle special cases, which might no longer apply. - if (is_full_bitmask(allocated)) { - // Transitioning from full to not-full; add to _allocate_list. - log_debug(oopstorage, blocks)("%s: block not full " PTR_FORMAT, name(), p2i(&block)); - _allocate_list.push_front(block); - assert(!block.is_full(), "invariant"); // Still not full. - } - if (is_empty_bitmask(new_value)) { - // Transitioning from not-empty to empty; move to end of - // _allocate_list, to make it a deletion candidate. - log_debug(oopstorage, blocks)("%s: block empty " PTR_FORMAT, name(), p2i(&block)); - _allocate_list.unlink(block); - _allocate_list.push_back(block); - ++_empty_block_count; - assert(block.is_empty(), "invariant"); // Still empty. - } - return; // Successful CAS and transitions handled. - } - } - // CAS failed; retry with latest value. - allocated = fetched; +static void log_release_transitions(uintx releasing, + uintx old_allocated, + const OopStorage* owner, + const void* block) { + ResourceMark rm; + Log(oopstorage, blocks) log; + LogStream ls(log.debug()); + if (is_full_bitmask(old_allocated)) { + ls.print_cr("%s: block not full " PTR_FORMAT, owner->name(), p2i(block)); + } + if (releasing == old_allocated) { + ls.print_cr("%s: block empty " PTR_FORMAT, owner->name(), p2i(block)); } } -#ifdef ASSERT -void OopStorage::check_release(const Block* block, const oop* ptr) const { - switch (allocation_status_validating_block(block, ptr)) { - case INVALID_ENTRY: - fatal("Releasing invalid entry: " PTR_FORMAT, p2i(ptr)); - break; +void OopStorage::Block::release_entries(uintx releasing, Block* volatile* deferred_list) { + assert(releasing != 0, "preconditon"); + // Prevent empty block deletion when transitioning to empty. + Atomic::inc(&_release_refcount); + + // Atomically update allocated bitmask. + uintx old_allocated = _allocated_bitmask; + while (true) { + assert((releasing & ~old_allocated) == 0, "releasing unallocated entries"); + uintx new_value = old_allocated ^ releasing; + uintx fetched = Atomic::cmpxchg(new_value, &_allocated_bitmask, old_allocated); + if (fetched == old_allocated) break; // Successful update. + old_allocated = fetched; // Retry with updated bitmask. + } - case UNALLOCATED_ENTRY: - fatal("Releasing unallocated entry: " PTR_FORMAT, p2i(ptr)); - break; + // Now that the bitmask has been updated, if we have a state transition + // (updated bitmask is empty or old bitmask was full), atomically push + // this block onto the deferred updates list. Some future call to + // reduce_deferred_updates will make any needed changes related to this + // block and _allocate_list. This deferral avoids list updates and the + // associated locking here. + if ((releasing == old_allocated) || is_full_bitmask(old_allocated)) { + // Log transitions. Both transitions are possible in a single update. + if (log_is_enabled(Debug, oopstorage, blocks)) { + log_release_transitions(releasing, old_allocated, _owner, this); + } + // Attempt to claim responsibility for adding this block to the deferred + // list, by setting the link to non-NULL by self-looping. If this fails, + // then someone else has made such a claim and the deferred update has not + // yet been processed and will include our change, so we don't need to do + // anything further. + if (Atomic::replace_if_null(this, &_deferred_updates_next)) { + // Successfully claimed. Push, with self-loop for end-of-list. + Block* head = *deferred_list; + while (true) { + _deferred_updates_next = (head == NULL) ? this : head; + Block* fetched = Atomic::cmpxchg(this, deferred_list, head); + if (fetched == head) break; // Successful update. + head = fetched; // Retry with updated head. + } + log_debug(oopstorage, blocks)("%s: deferred update " PTR_FORMAT, + _owner->name(), p2i(this)); + } + } + // Release hold on empty block deletion. + Atomic::dec(&_release_refcount); +} - case ALLOCATED_ENTRY: - assert(block->contains(ptr), "invariant"); - break; +// Process one available deferred update. Returns true if one was processed. +bool OopStorage::reduce_deferred_updates() { + assert_locked_or_safepoint(_allocate_mutex); + // Atomically pop a block off the list, if any available. + // No ABA issue because this is only called by one thread at a time. + // The atomicity is wrto pushes by release(). + Block* block = OrderAccess::load_acquire(&_deferred_updates); + while (true) { + if (block == NULL) return false; + // Try atomic pop of block from list. + Block* tail = block->deferred_updates_next(); + if (block == tail) tail = NULL; // Handle self-loop end marker. + Block* fetched = Atomic::cmpxchg(tail, &_deferred_updates, block); + if (fetched == block) break; // Update successful. + block = fetched; // Retry with updated block. + } + block->set_deferred_updates_next(NULL); // Clear tail after updating head. + // Ensure bitmask read after pop is complete, including clearing tail, for + // ordering with release(). Without this, we may be processing a stale + // bitmask state here while blocking a release() operation from recording + // the deferred update needed for its bitmask change. + OrderAccess::storeload(); + // Process popped block. + uintx allocated = block->allocated_bitmask(); - default: - ShouldNotReachHere(); + // Make membership in list consistent with bitmask state. + if ((_allocate_list.ctail() != NULL) && + ((_allocate_list.ctail() == block) || + (_allocate_list.next(*block) != NULL))) { + // Block is in the allocate list. + assert(!is_full_bitmask(allocated), "invariant"); + } else if (!is_full_bitmask(allocated)) { + // Block is not in the allocate list, but now should be. + _allocate_list.push_front(*block); + } // Else block is full and not in list, which is correct. + + // Move empty block to end of list, for possible deletion. + if (is_empty_bitmask(allocated)) { + _allocate_list.unlink(*block); + _allocate_list.push_back(*block); } + + log_debug(oopstorage, blocks)("%s: processed deferred update " PTR_FORMAT, + name(), p2i(block)); + return true; // Processed one pending update. } -#endif // ASSERT inline void check_release_entry(const oop* entry) { assert(entry != NULL, "Releasing NULL"); @@ -459,9 +521,9 @@ void OopStorage::release(const oop* ptr) { check_release_entry(ptr); Block* block = find_block_or_null(ptr); - check_release(block, ptr); + assert(block != NULL, "%s: invalid release " PTR_FORMAT, name(), p2i(ptr)); log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(ptr)); - release_from_block(*block, block->bitmask_for_entry(ptr)); + block->release_entries(block->bitmask_for_entry(ptr), &_deferred_updates); Atomic::dec(&_allocation_count); } @@ -470,15 +532,15 @@ while (i < size) { check_release_entry(ptrs[i]); Block* block = find_block_or_null(ptrs[i]); - check_release(block, ptrs[i]); + assert(block != NULL, "%s: invalid release " PTR_FORMAT, name(), p2i(ptrs[i])); log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(ptrs[i])); size_t count = 0; uintx releasing = 0; for ( ; i < size; ++i) { const oop* entry = ptrs[i]; + check_release_entry(entry); // If entry not in block, finish block and resume outer loop with entry. if (!block->contains(entry)) break; - check_release_entry(entry); // Add entry to releasing bitmap. log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(entry)); uintx entry_bitmask = block->bitmask_for_entry(entry); @@ -488,7 +550,7 @@ ++count; } // Release the contiguous entries that are in block. - release_from_block(*block, releasing); + block->release_entries(releasing, &_deferred_updates); Atomic::sub(count, &_allocation_count); } } @@ -506,11 +568,11 @@ _active_list(&Block::get_active_entry), _allocate_list(&Block::get_allocate_entry), _active_head(NULL), + _deferred_updates(NULL), _allocate_mutex(allocate_mutex), _active_mutex(active_mutex), _allocation_count(0), _block_count(0), - _empty_block_count(0), _concurrent_iteration_active(false) { assert(_active_mutex->rank() < _allocate_mutex->rank(), @@ -529,6 +591,10 @@ OopStorage::~OopStorage() { Block* block; + while ((block = _deferred_updates) != NULL) { + _deferred_updates = block->deferred_updates_next(); + block->set_deferred_updates_next(NULL); + } while ((block = _allocate_list.head()) != NULL) { _allocate_list.unlink(*block); } @@ -539,43 +605,47 @@ FREE_C_HEAP_ARRAY(char, _name); } -void OopStorage::delete_empty_blocks_safepoint(size_t retain) { +void OopStorage::delete_empty_blocks_safepoint() { assert_at_safepoint(); + // Process any pending release updates, which may make more empty + // blocks available for deletion. + while (reduce_deferred_updates()) {} // Don't interfere with a concurrent iteration. if (_concurrent_iteration_active) return; - // Compute the number of blocks to remove, to minimize volatile accesses. - size_t empty_blocks = _empty_block_count; - if (retain < empty_blocks) { - size_t remove_count = empty_blocks - retain; - // Update volatile counters once. - _block_count -= remove_count; - _empty_block_count -= remove_count; - do { - const Block* block = _allocate_list.ctail(); - assert(block != NULL, "invariant"); - assert(block->is_empty(), "invariant"); - // Remove block from lists, and delete it. - _active_list.unlink(*block); - _allocate_list.unlink(*block); - delete_empty_block(*block); - } while (--remove_count > 0); - // Update _active_head, in case current value was in deleted set. - _active_head = _active_list.head(); + // Delete empty (and otherwise deletable) blocks from end of _allocate_list. + for (const Block* block = _allocate_list.ctail(); + (block != NULL) && block->is_deletable(); + block = _allocate_list.ctail()) { + _active_list.unlink(*block); + _allocate_list.unlink(*block); + delete_empty_block(*block); + --_block_count; } + // Update _active_head, in case current value was in deleted set. + _active_head = _active_list.head(); } -void OopStorage::delete_empty_blocks_concurrent(size_t retain) { +void OopStorage::delete_empty_blocks_concurrent() { MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); // Other threads could be adding to the empty block count while we // release the mutex across the block deletions. Set an upper bound // on how many blocks we'll try to release, so other threads can't // cause an unbounded stay in this function. - if (_empty_block_count <= retain) return; - size_t limit = _empty_block_count - retain; - for (size_t i = 0; (i < limit) && (retain < _empty_block_count); ++i) { + size_t limit = _block_count; + + for (size_t i = 0; i < limit; ++i) { + // Additional updates might become available while we dropped the + // lock. But limit number processed to limit lock duration. + reduce_deferred_updates(); + const Block* block = _allocate_list.ctail(); - assert(block != NULL, "invariant"); - assert(block->is_empty(), "invariant"); + if ((block == NULL) || !block->is_deletable()) { + // No block to delete, so done. There could be more pending + // deferred updates that could give us more work to do; deal with + // that in some later call, to limit lock duration here. + return; + } + { MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag); // Don't interfere with a concurrent iteration. @@ -589,28 +659,31 @@ } // Remove block from _allocate_list and delete it. _allocate_list.unlink(*block); - --_empty_block_count; // Release mutex while deleting block. MutexUnlockerEx ul(_allocate_mutex, Mutex::_no_safepoint_check_flag); delete_empty_block(*block); } } -OopStorage::EntryStatus -OopStorage::allocation_status_validating_block(const Block* block, - const oop* ptr) const { - MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); - if ((block == NULL) || !is_valid_block_locked_or_safepoint(block)) { - return INVALID_ENTRY; - } else if ((block->allocated_bitmask() & block->bitmask_for_entry(ptr)) != 0) { - return ALLOCATED_ENTRY; - } else { - return UNALLOCATED_ENTRY; +OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const { + const Block* block = find_block_or_null(ptr); + if (block != NULL) { + // Verify block is a real block. For now, simple linear search. + // Do something more clever if this is a performance bottleneck. + MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); + for (const Block* check_block = _active_list.chead(); + check_block != NULL; + check_block = _active_list.next(*check_block)) { + if (check_block == block) { + if ((block->allocated_bitmask() & block->bitmask_for_entry(ptr)) != 0) { + return ALLOCATED_ENTRY; + } else { + return UNALLOCATED_ENTRY; + } + } + } } -} - -OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const { - return allocation_status_validating_block(find_block_or_null(ptr), ptr); + return INVALID_ENTRY; } size_t OopStorage::allocation_count() const { @@ -621,10 +694,6 @@ return _block_count; } -size_t OopStorage::empty_block_count() const { - return _empty_block_count; -} - size_t OopStorage::total_memory_usage() const { size_t total_size = sizeof(OopStorage); total_size += strlen(name()) + 1; @@ -690,17 +759,12 @@ void OopStorage::print_on(outputStream* st) const { size_t allocations = _allocation_count; size_t blocks = _block_count; - size_t empties = _empty_block_count; - // Comparison is being careful about racy accesses. - size_t used = (blocks < empties) ? 0 : (blocks - empties); double data_size = section_size * section_count; - double alloc_percentage = percent_of((double)allocations, used * data_size); + double alloc_percentage = percent_of((double)allocations, blocks * data_size); - st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " - SIZE_FORMAT " empties, " SIZE_FORMAT " bytes", - name(), allocations, used, alloc_percentage, - empties, total_memory_usage()); + st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " SIZE_FORMAT " bytes", + name(), allocations, blocks, alloc_percentage, total_memory_usage()); if (_concurrent_iteration_active) { st->print(", concurrent iteration active"); } diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/gc/shared/oopStorage.hpp --- a/src/hotspot/share/gc/shared/oopStorage.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/gc/shared/oopStorage.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -84,10 +84,6 @@ // The number of blocks of entries. Useful for sizing parallel iteration. size_t block_count() const; - // The number of blocks with no allocated entries. Useful for sizing - // parallel iteration and scheduling block deletion. - size_t empty_block_count() const; - // Total number of blocks * memory allocation per block, plus // bookkeeping overhead, including this storage object. size_t total_memory_usage() const; @@ -107,14 +103,13 @@ // postcondition: *result == NULL. oop* allocate(); - // Deallocates ptr, after setting its value to NULL. Locks _allocate_mutex. + // Deallocates ptr. No locking. // precondition: ptr is a valid allocated entry. // precondition: *ptr == NULL. void release(const oop* ptr); // Releases all the ptrs. Possibly faster than individual calls to - // release(oop*). Best if ptrs is sorted by address. Locks - // _allocate_mutex. + // release(oop*). Best if ptrs is sorted by address. No locking. // precondition: All elements of ptrs are valid allocated entries. // precondition: *ptrs[i] == NULL, for i in [0,size). void release(const oop* const* ptrs, size_t size); @@ -160,8 +155,8 @@ // Block cleanup functions are for the exclusive use of the GC. // Both stop deleting if there is an in-progress concurrent iteration. // Concurrent deletion locks both the allocate_mutex and the active_mutex. - void delete_empty_blocks_safepoint(size_t retain = 1); - void delete_empty_blocks_concurrent(size_t retain = 1); + void delete_empty_blocks_safepoint(); + void delete_empty_blocks_concurrent(); // Debugging and logging support. const char* name() const; @@ -231,6 +226,7 @@ BlockList _active_list; BlockList _allocate_list; Block* volatile _active_head; + Block* volatile _deferred_updates; Mutex* _allocate_mutex; Mutex* _active_mutex; @@ -238,16 +234,12 @@ // Counts are volatile for racy unlocked accesses. volatile size_t _allocation_count; volatile size_t _block_count; - volatile size_t _empty_block_count; // mutable because this gets set even for const iteration. mutable bool _concurrent_iteration_active; Block* find_block_or_null(const oop* ptr) const; - bool is_valid_block_locked_or_safepoint(const Block* block) const; - EntryStatus allocation_status_validating_block(const Block* block, const oop* ptr) const; - void check_release(const Block* block, const oop* ptr) const NOT_DEBUG_RETURN; - void release_from_block(Block& block, uintx release_bitmask); void delete_empty_block(const Block& block); + bool reduce_deferred_updates(); static void assert_at_safepoint() NOT_DEBUG_RETURN; diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/gc/shared/oopStorage.inline.hpp --- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -44,6 +44,8 @@ void* _memory; // Unaligned storage containing block. BlockEntry _active_entry; BlockEntry _allocate_entry; + Block* volatile _deferred_updates_next; + volatile uintx _release_refcount; Block(const OopStorage* owner, void* memory); ~Block(); @@ -75,7 +77,10 @@ bool is_full() const; bool is_empty() const; uintx allocated_bitmask() const; - uintx cmpxchg_allocated_bitmask(uintx new_value, uintx compare_value); + bool is_deletable() const; + + Block* deferred_updates_next() const; + void set_deferred_updates_next(Block* new_next); bool contains(const oop* ptr) const; @@ -86,6 +91,8 @@ static Block* new_block(const OopStorage* owner); static void delete_block(const Block& block); + void release_entries(uintx releasing, Block* volatile* deferred_list); + template bool iterate(F f); template bool iterate(F f) const; }; // class Block diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/interpreter/bytecodeInterpreter.cpp --- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -594,10 +594,6 @@ VERIFY_OOP(rcvr); } #endif -// #define HACK -#ifdef HACK - bool interesting = false; -#endif // HACK /* QQQ this should be a stack method so we don't know actual direction */ guarantee(istate->msg() == initialize || @@ -649,19 +645,6 @@ os::breakpoint(); } -#ifdef HACK - { - ResourceMark rm; - char *method_name = istate->method()->name_and_sig_as_C_string(); - if (strstr(method_name, "runThese$TestRunner.run()V") != NULL) { - tty->print_cr("entering: depth %d bci: %d", - (istate->_stack_base - istate->_stack), - istate->_bcp - istate->_method->code_base()); - interesting = true; - } - } -#endif // HACK - // Lock method if synchronized. if (METHOD->is_synchronized()) { // oop rcvr = locals[0].j.r; @@ -793,18 +776,6 @@ // resume os::breakpoint(); } -#ifdef HACK - { - ResourceMark rm; - char *method_name = istate->method()->name_and_sig_as_C_string(); - if (strstr(method_name, "runThese$TestRunner.run()V") != NULL) { - tty->print_cr("resume: depth %d bci: %d", - (istate->_stack_base - istate->_stack) , - istate->_bcp - istate->_method->code_base()); - interesting = true; - } - } -#endif // HACK // returned from a java call, continue executing. if (THREAD->pop_frame_pending() && !THREAD->pop_frame_in_process()) { goto handle_Pop_Frame; diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/logging/logTag.hpp --- a/src/hotspot/share/logging/logTag.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/logging/logTag.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -66,6 +66,7 @@ LOG_TAG(exceptions) \ LOG_TAG(exit) \ LOG_TAG(fingerprint) \ + LOG_TAG(free) \ LOG_TAG(freelist) \ LOG_TAG(gc) \ LOG_TAG(handshake) \ @@ -85,6 +86,7 @@ LOG_TAG(load) /* Trace all classes loaded */ \ LOG_TAG(loader) \ LOG_TAG(logging) \ + LOG_TAG(malloc) \ LOG_TAG(mark) \ LOG_TAG(marking) \ LOG_TAG(membername) \ diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/memory/allocation.cpp --- a/src/hotspot/share/memory/allocation.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/memory/allocation.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -210,18 +210,6 @@ } #endif // ASSERT - -void trace_heap_malloc(size_t size, const char* name, void* p) { - // A lock is not needed here - tty uses a lock internally - tty->print_cr("Heap malloc " INTPTR_FORMAT " " SIZE_FORMAT " %s", p2i(p), size, name == NULL ? "" : name); -} - - -void trace_heap_free(void* p) { - // A lock is not needed here - tty uses a lock internally - tty->print_cr("Heap free " INTPTR_FORMAT, p2i(p)); -} - //-------------------------------------------------------------------------------------- // Non-product code diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/memory/allocation.inline.hpp --- a/src/hotspot/share/memory/allocation.inline.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/memory/allocation.inline.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -33,9 +33,6 @@ // Explicit C-heap memory management -void trace_heap_malloc(size_t size, const char* name, void *p); -void trace_heap_free(void *p); - #ifndef PRODUCT // Increments unsigned long value for statistics (not atomic on MP). inline void inc_stat_counter(volatile julong* dest, julong add_value) { @@ -56,9 +53,6 @@ const NativeCallStack& stack, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { char* p = (char*) os::malloc(size, flags, stack); - #ifdef ASSERT - if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p); - #endif if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) { vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap"); } @@ -73,9 +67,6 @@ ALWAYSINLINE char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { char* p = (char*) os::realloc(old, size, flag, CURRENT_PC); - #ifdef ASSERT - if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p); - #endif if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) { vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "ReallocateHeap"); } @@ -83,20 +74,13 @@ } inline void FreeHeap(void* p) { - #ifdef ASSERT - if (PrintMallocFree) trace_heap_free(p); - #endif os::free(p); } template void* CHeapObj::operator new(size_t size, const NativeCallStack& stack) throw() { - void* p = (void*)AllocateHeap(size, F, stack); -#ifdef ASSERT - if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); -#endif - return p; + return (void*)AllocateHeap(size, F, stack); } template void* CHeapObj::operator new(size_t size) throw() { @@ -104,14 +88,9 @@ } template void* CHeapObj::operator new (size_t size, - const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw() { - void* p = (void*)AllocateHeap(size, F, stack, - AllocFailStrategy::RETURN_NULL); -#ifdef ASSERT - if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); -#endif - return p; - } + const std::nothrow_t& nothrow_constant, const NativeCallStack& stack) throw() { + return (void*)AllocateHeap(size, F, stack, AllocFailStrategy::RETURN_NULL); +} template void* CHeapObj::operator new (size_t size, const std::nothrow_t& nothrow_constant) throw() { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/memory/arena.cpp --- a/src/hotspot/share/memory/arena.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/memory/arena.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -299,23 +299,11 @@ // dynamic memory type binding void* Arena::operator new(size_t size, MEMFLAGS flags) throw() { -#ifdef ASSERT - void* p = (void*)AllocateHeap(size, flags, CALLER_PC); - if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p); - return p; -#else return (void *) AllocateHeap(size, flags, CALLER_PC); -#endif } void* Arena::operator new(size_t size, const std::nothrow_t& nothrow_constant, MEMFLAGS flags) throw() { -#ifdef ASSERT - void* p = os::malloc(size, flags, CALLER_PC); - if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p); - return p; -#else - return os::malloc(size, flags, CALLER_PC); -#endif + return (void*)AllocateHeap(size, flags, CALLER_PC, AllocFailStrategy::RETURN_NULL); } void Arena::operator delete(void* p) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/oops/instanceKlass.cpp --- a/src/hotspot/share/oops/instanceKlass.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/oops/instanceKlass.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -124,8 +124,6 @@ #endif // ndef DTRACE_ENABLED -volatile int InstanceKlass::_total_instanceKlass_count = 0; - static inline bool is_class_loader(const Symbol* class_name, const ClassFileParser& parser) { assert(class_name != NULL, "invariant"); @@ -193,8 +191,6 @@ // Add all classes to our internal class loader list here, // including classes in the bootstrap (NULL) class loader. loader_data->add_class(ik, publicize); - Atomic::inc(&_total_instanceKlass_count); - return ik; } @@ -2241,9 +2237,6 @@ // class can't be referenced anymore). if (_array_name != NULL) _array_name->decrement_refcount(); if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(char, _source_debug_extension); - - assert(_total_instanceKlass_count >= 1, "Sanity check"); - Atomic::dec(&_total_instanceKlass_count); } void InstanceKlass::set_source_debug_extension(const char* array, int length) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/oops/instanceKlass.hpp --- a/src/hotspot/share/oops/instanceKlass.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/oops/instanceKlass.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -135,10 +135,7 @@ initialization_error // error happened during initialization }; - static int number_of_instance_classes() { return _total_instanceKlass_count; } - private: - static volatile int _total_instanceKlass_count; static InstanceKlass* allocate_instance_klass(const ClassFileParser& parser, TRAPS); protected: diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/opto/escape.cpp --- a/src/hotspot/share/opto/escape.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/opto/escape.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -3226,7 +3226,7 @@ n->Opcode() == Op_EncodeISOArray) { // get the memory projection n = n->find_out_with(Op_SCMemProj); - assert(n->Opcode() == Op_SCMemProj, "memory projection required"); + assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required"); } else { assert(n->is_Mem(), "memory node required."); Node *addr = n->in(MemNode::Address); @@ -3250,7 +3250,7 @@ } else if (n->is_LoadStore()) { // get the memory projection n = n->find_out_with(Op_SCMemProj); - assert(n->Opcode() == Op_SCMemProj, "memory projection required"); + assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required"); } } // push user on appropriate worklist diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/opto/parse2.cpp --- a/src/hotspot/share/opto/parse2.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/opto/parse2.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -2264,7 +2264,7 @@ ciMethodData* methodData = method()->method_data(); if (!methodData->is_mature()) break; ciProfileData* data = methodData->bci_to_data(bci()); - assert( data->is_JumpData(), "" ); + assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch"); int taken = ((ciJumpData*)data)->taken(); taken = method()->scale_count(taken); target_block->set_count(taken); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/opto/parseHelper.cpp --- a/src/hotspot/share/opto/parseHelper.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/opto/parseHelper.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ -459,7 +459,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(cur_bci); - assert(data->is_JumpData(), "need JumpData for taken branch"); + assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch"); increment_md_counter_at(md, data, JumpData::taken_offset()); } @@ -470,6 +470,7 @@ ciMethodData* md = method()->method_data(); if (osr_site) { ciProfileData* data = md->bci_to_data(cur_bci); + assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch"); int limit = (CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100; test_for_osr_md_counter_at(md, data, JumpData::taken_offset(), limit); @@ -495,7 +496,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_BranchData(), "need BranchData for not taken branch"); + assert(data != NULL && data->is_BranchData(), "need BranchData for not taken branch"); increment_md_counter_at(md, data, BranchData::not_taken_offset()); } @@ -526,7 +527,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_CounterData(), "need CounterData for not taken branch"); + assert(data != NULL && data->is_CounterData(), "need CounterData for not taken branch"); increment_md_counter_at(md, data, CounterData::count_offset()); } @@ -537,7 +538,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here"); + assert(data != NULL && data->is_ReceiverTypeData(), "need ReceiverTypeData here"); // Skip if we aren't tracking receivers if (TypeProfileWidth < 1) { @@ -568,7 +569,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_RetData(), "need RetData for ret"); + assert(data != NULL && data->is_RetData(), "need RetData for ret"); ciRetData* ret_data = (ciRetData*)data->as_RetData(); // Look for the target_bci is already in the table @@ -601,7 +602,7 @@ ciMethodData* md = method()->method_data(); assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_BitData(), "need BitData for checkcast"); + assert(data != NULL && data->is_BitData(), "need BitData for checkcast"); set_md_flag_at(md, data, BitData::null_seen_byte_constant()); } @@ -613,7 +614,7 @@ assert(md != NULL, "expected valid ciMethodData"); ciProfileData* data = md->bci_to_data(bci()); - assert(data->is_MultiBranchData(), "need MultiBranchData for switch case"); + assert(data != NULL && data->is_MultiBranchData(), "need MultiBranchData for switch case"); if (table_index >= 0) { increment_md_counter_at(md, data, MultiBranchData::case_count_offset(table_index)); } else { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/prims/jvmtiExport.cpp --- a/src/hotspot/share/prims/jvmtiExport.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/prims/jvmtiExport.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -597,12 +597,10 @@ } void JvmtiExport::enter_early_start_phase() { - JvmtiManageCapabilities::recompute_always_capabilities(); set_early_vmstart_recorded(true); } void JvmtiExport::enter_start_phase() { - JvmtiManageCapabilities::recompute_always_capabilities(); JvmtiEnvBase::set_phase(JVMTI_PHASE_START); } diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp --- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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,6 +29,9 @@ #include "prims/jvmtiGetLoadedClasses.hpp" #include "runtime/thread.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif // The closure for GetLoadedClasses @@ -38,6 +41,20 @@ JvmtiEnv* _env; Thread* _cur_thread; +// Tell the GC to keep this klass alive +static void ensure_klass_alive(oop o) { + // A klass that was previously considered dead can be looked up in the + // CLD/SD, and its _java_mirror or _class_loader can be stored in a root + // or a reachable object making it alive again. The SATB part of G1 needs + // to get notified about this potential resurrection, otherwise the marking + // might not find the object. +#if INCLUDE_ALL_GCS + if (UseG1GC && o != NULL) { + G1SATBCardTableModRefBS::enqueue(o); + } +#endif +} + public: LoadedClassesClosure(Thread* thread, JvmtiEnv* env) : _cur_thread(thread), _env(env) { assert(_cur_thread == Thread::current(), "must be current thread"); @@ -46,6 +63,7 @@ void do_klass(Klass* k) { // Collect all jclasses _classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror()))); + ensure_klass_alive(k->java_mirror()); } int extract(jclass* result_list) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/prims/jvmtiManageCapabilities.cpp --- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -57,9 +57,6 @@ void JvmtiManageCapabilities::initialize() { always_capabilities = init_always_capabilities(); - if (JvmtiEnv::get_phase() != JVMTI_PHASE_ONLOAD) { - recompute_always_capabilities(); - } onload_capabilities = init_onload_capabilities(); always_solo_capabilities = init_always_solo_capabilities(); onload_solo_capabilities = init_onload_solo_capabilities(); @@ -68,19 +65,6 @@ memset(&acquired_capabilities, 0, sizeof(acquired_capabilities)); } -// if the capability sets are initialized in the onload phase then -// it happens before class data sharing (CDS) is initialized. If it -// turns out that CDS gets disabled then we must adjust the always -// capabilities. To ensure a consistent view of the capabililties -// anything we add here should already be in the onload set. -void JvmtiManageCapabilities::recompute_always_capabilities() { - if (!UseSharedSpaces) { - jvmtiCapabilities jc = always_capabilities; - jc.can_generate_all_class_hook_events = 1; - always_capabilities = jc; - } -} - // corresponding init functions jvmtiCapabilities JvmtiManageCapabilities::init_always_capabilities() { @@ -94,6 +78,7 @@ jc.can_get_synthetic_attribute = 1; jc.can_get_monitor_info = 1; jc.can_get_constant_pool = 1; + jc.can_generate_all_class_hook_events = 1; jc.can_generate_monitor_events = 1; jc.can_generate_garbage_collection_events = 1; jc.can_generate_compiled_method_load_events = 1; @@ -126,7 +111,6 @@ jc.can_get_source_debug_extension = 1; jc.can_access_local_variables = 1; jc.can_maintain_original_method_order = 1; - jc.can_generate_all_class_hook_events = 1; jc.can_generate_single_step_events = 1; jc.can_generate_exception_events = 1; jc.can_generate_frame_pop_events = 1; diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/prims/jvmtiManageCapabilities.hpp --- a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -64,9 +64,6 @@ public: static void initialize(); - // may have to adjust always capabilities when VM initialization has completed - static void recompute_always_capabilities(); - // queries and actions static void get_potential_capabilities(const jvmtiCapabilities *current, const jvmtiCapabilities *prohibited, diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/arguments.cpp --- a/src/hotspot/share/runtime/arguments.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/arguments.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -514,7 +514,9 @@ { "DeferThrSuspendLoopCount", JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) }, { "DeferPollingPageLoopCount", JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) }, { "IgnoreUnverifiableClassesDuringDump", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, - { "CheckEndorsedAndExtDirs", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, + { "CheckEndorsedAndExtDirs", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() }, + { "CompilerThreadHintNoPreempt", JDK_Version::jdk(11), JDK_Version::jdk(12), JDK_Version::jdk(13) }, + { "VMThreadHintNoPreempt", JDK_Version::jdk(11), JDK_Version::jdk(12), JDK_Version::jdk(13) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -527,6 +529,8 @@ { "ConvertYieldToSleep", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) }, { "MinSleepInterval", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) }, { "CheckAssertionStatusDirectives",JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, + { "PrintMallocFree", JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, + { "PrintMalloc", JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) }, { "PermSize", JDK_Version::undefined(), JDK_Version::jdk(8), JDK_Version::undefined() }, { "MaxPermSize", JDK_Version::undefined(), JDK_Version::jdk(8), JDK_Version::undefined() }, { "SharedReadWriteSize", JDK_Version::undefined(), JDK_Version::jdk(10), JDK_Version::undefined() }, diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/compilationPolicy.cpp --- a/src/hotspot/share/runtime/compilationPolicy.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/compilationPolicy.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2018, 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 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "code/compiledIC.hpp" #include "code/nmethod.hpp" #include "code/scopeDesc.hpp" @@ -312,10 +313,10 @@ // and hence GC's will not be going on, all Java mutators are suspended // at this point and hence SystemDictionary_lock is also not needed. assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint"); - int nclasses = InstanceKlass::number_of_instance_classes(); - int classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / + size_t nclasses = ClassLoaderDataGraph::num_instance_classes(); + size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 / CounterHalfLifeTime); - for (int i = 0; i < classes_per_tick; i++) { + for (size_t i = 0; i < classes_per_tick; i++) { InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class(); if (k != NULL) { k->methods_do(do_method); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/globals.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -893,18 +893,12 @@ develop(bool, TraceJavaAssertions, false, \ "Trace java language assertions") \ \ - notproduct(bool, PrintMallocFree, false, \ - "Trace calls to C heap malloc/free allocation") \ - \ notproduct(bool, VerifyCodeCache, false, \ "Verify code cache on memory allocation/deallocation") \ \ develop(bool, UseMallocOnly, false, \ "Use only malloc/free for allocation (no resource area/arena)") \ \ - develop(bool, PrintMalloc, false, \ - "Print all malloc/free calls") \ - \ develop(bool, PrintMallocStatistics, false, \ "Print malloc/free statistics") \ \ @@ -3545,7 +3539,7 @@ "(-1 means no change)") \ range(-1, 127) \ \ - product(bool, CompilerThreadHintNoPreempt, true, \ + product(bool, CompilerThreadHintNoPreempt, false, \ "(Solaris only) Give compiler threads an extra quanta") \ \ product(bool, VMThreadHintNoPreempt, false, \ diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/memprofiler.cpp --- a/src/hotspot/share/runtime/memprofiler.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/memprofiler.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, 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 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/collectedHeap.inline.hpp" @@ -116,10 +117,10 @@ } // Print trace line in log - fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",", + fprintf(_log_fp, "%6.1f,%5d," SIZE_FORMAT_W(5) "," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",", os::elapsedTime(), jtiwh.length(), - InstanceKlass::number_of_instance_classes(), + ClassLoaderDataGraph::num_instance_classes(), Universe::heap()->used() / K, Universe::heap()->capacity() / K); } diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/mutexLocker.cpp --- a/src/hotspot/share/runtime/mutexLocker.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/mutexLocker.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -253,10 +253,10 @@ // of some places which hold other locks while releasing a handle, including // the Patching_lock, which is of "special" rank. As a temporary workaround, // lower the JNI oopstorage lock ranks to make them super-special. - def(JNIGlobalAlloc_lock , PaddedMutex , special-1, true, Monitor::_safepoint_check_never); - def(JNIGlobalActive_lock , PaddedMutex , special-2, true, Monitor::_safepoint_check_never); - def(JNIWeakAlloc_lock , PaddedMutex , special-1, true, Monitor::_safepoint_check_never); - def(JNIWeakActive_lock , PaddedMutex , special-2, true, Monitor::_safepoint_check_never); + def(JNIGlobalAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never); + def(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never); + def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never); + def(JNIWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never); def(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/runtime/os.cpp --- a/src/hotspot/share/runtime/os.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/runtime/os.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -33,6 +33,7 @@ #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" #include "gc/shared/vmGCOperations.hpp" +#include "logging/log.hpp" #include "interpreter/interpreter.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -610,9 +611,12 @@ static void verify_memory(void* ptr) { GuardedMemory guarded(ptr); if (!guarded.verify_guards()) { - tty->print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees); - tty->print_cr("## memory stomp:"); - guarded.print_on(tty); + LogTarget(Warning, malloc, free) lt; + ResourceMark rm; + LogStream ls(lt); + ls.print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees); + ls.print_cr("## memory stomp:"); + guarded.print_on(&ls); fatal("memory stomping error"); } } @@ -684,13 +688,10 @@ ptr = guarded.get_user_ptr(); #endif if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); + log_warning(malloc, free)("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } debug_only(if (paranoid) verify_memory(ptr)); - if (PrintMalloc && tty != NULL) { - tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); - } // we do not track guard memory return MemTracker::record_malloc((address)ptr, size, memflags, stack, level); @@ -727,7 +728,7 @@ return os::malloc(size, memflags, stack); } if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught " PTR_FORMAT, p2i(memblock)); + log_warning(malloc, free)("os::realloc caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } // NMT support @@ -735,18 +736,15 @@ verify_memory(membase); // always move the block void* ptr = os::malloc(size, memflags, stack); - if (PrintMalloc && tty != NULL) { - tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, p2i(memblock), p2i(ptr)); - } // Copy to new memory if malloc didn't fail - if ( ptr != NULL ) { + if (ptr != NULL ) { GuardedMemory guarded(MemTracker::malloc_base(memblock)); // Guard's user data contains NMT header size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock); memcpy(ptr, memblock, MIN2(size, memblock_size)); if (paranoid) verify_memory(MemTracker::malloc_base(ptr)); if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) { - tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); + log_warning(malloc, free)("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr)); breakpoint(); } os::free(memblock); @@ -761,7 +759,7 @@ #ifdef ASSERT if (memblock == NULL) return; if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { - if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, p2i(memblock)); + log_warning(malloc, free)("os::free caught " PTR_FORMAT, p2i(memblock)); breakpoint(); } void* membase = MemTracker::record_free(memblock); @@ -771,9 +769,6 @@ size_t size = guarded.get_user_size(); inc_stat_counter(&free_bytes, size); membase = guarded.release_for_freeing(); - if (PrintMalloc && tty != NULL) { - fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)membase); - } ::free(membase); #else void* membase = MemTracker::record_free(memblock); @@ -1754,7 +1749,7 @@ bool os::uncommit_memory(char* addr, size_t bytes) { bool res; if (MemTracker::tracking_level() > NMT_minimal) { - Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker(); + Tracker tkr(Tracker::uncommit); res = pd_uncommit_memory(addr, bytes); if (res) { tkr.record((address)addr, bytes); @@ -1768,7 +1763,7 @@ bool os::release_memory(char* addr, size_t bytes) { bool res; if (MemTracker::tracking_level() > NMT_minimal) { - Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + Tracker tkr(Tracker::release); res = pd_release_memory(addr, bytes); if (res) { tkr.record((address)addr, bytes); @@ -1805,7 +1800,7 @@ bool os::unmap_memory(char *addr, size_t bytes) { bool result; if (MemTracker::tracking_level() > NMT_minimal) { - Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); + Tracker tkr(Tracker::release); result = pd_unmap_memory(addr, bytes); if (result) { tkr.record((address)addr, bytes); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/services/memBaseline.cpp --- a/src/hotspot/share/services/memBaseline.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/services/memBaseline.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "memory/allocation.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" @@ -180,7 +181,8 @@ bool MemBaseline::baseline(bool summaryOnly) { reset(); - _class_count = InstanceKlass::number_of_instance_classes(); + _instance_class_count = ClassLoaderDataGraph::num_instance_classes(); + _array_class_count = ClassLoaderDataGraph::num_array_classes(); if (!baseline_summary()) { return false; diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/services/memBaseline.hpp --- a/src/hotspot/share/services/memBaseline.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/services/memBaseline.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -67,7 +67,8 @@ VirtualMemorySnapshot _virtual_memory_snapshot; MetaspaceSnapshot _metaspace_snapshot; - size_t _class_count; + size_t _instance_class_count; + size_t _array_class_count; // Allocation sites information // Malloc allocation sites @@ -89,7 +90,7 @@ // create a memory baseline MemBaseline(): _baseline_type(Not_baselined), - _class_count(0) { + _instance_class_count(0), _array_class_count(0) { } bool baseline(bool summaryOnly = true); @@ -160,7 +161,17 @@ size_t class_count() const { assert(baseline_type() != Not_baselined, "Not yet baselined"); - return _class_count; + return _instance_class_count + _array_class_count; + } + + size_t instance_class_count() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + return _instance_class_count; + } + + size_t array_class_count() const { + assert(baseline_type() != Not_baselined, "Not yet baselined"); + return _array_class_count; } size_t thread_count() const { @@ -172,7 +183,8 @@ void reset() { _baseline_type = Not_baselined; // _malloc_memory_snapshot and _virtual_memory_snapshot are copied over. - _class_count = 0; + _instance_class_count = 0; + _array_class_count = 0; _malloc_sites.clear(); _virtual_memory_sites.clear(); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/services/memReporter.cpp --- a/src/hotspot/share/services/memReporter.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/services/memReporter.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -145,7 +145,10 @@ if (flag == mtClass) { // report class count - out->print_cr("%27s (classes #" SIZE_FORMAT ")", " ", _class_count); + out->print_cr("%27s (classes #" SIZE_FORMAT ")", + " ", (_instance_class_count + _array_class_count)); + out->print_cr("%27s ( instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")", + " ", _instance_class_count, _array_class_count); } else if (flag == mtThread) { // report thread count out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count()); @@ -459,6 +462,17 @@ out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count())); } out->print_cr(")"); + + out->print("%27s ( instance classes #" SIZE_FORMAT, " ", _current_baseline.instance_class_count()); + if (_current_baseline.instance_class_count() != _early_baseline.instance_class_count()) { + out->print(" %+d", (int)(_current_baseline.instance_class_count() - _early_baseline.instance_class_count())); + } + out->print(", array classes #" SIZE_FORMAT, _current_baseline.array_class_count()); + if (_current_baseline.array_class_count() != _early_baseline.array_class_count()) { + out->print(" %+d", (int)(_current_baseline.array_class_count() - _early_baseline.array_class_count())); + } + out->print_cr(")"); + } else if (flag == mtThread) { // report thread count out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count()); diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/services/memReporter.hpp --- a/src/hotspot/share/services/memReporter.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/services/memReporter.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -94,7 +94,8 @@ private: MallocMemorySnapshot* _malloc_snapshot; VirtualMemorySnapshot* _vm_snapshot; - size_t _class_count; + size_t _instance_class_count; + size_t _array_class_count; public: // This constructor is for normal reporting from a recent baseline. @@ -102,7 +103,8 @@ size_t scale = K) : MemReporterBase(output, scale), _malloc_snapshot(baseline.malloc_memory_snapshot()), _vm_snapshot(baseline.virtual_memory_snapshot()), - _class_count(baseline.class_count()) { } + _instance_class_count(baseline.instance_class_count()), + _array_class_count(baseline.array_class_count()) { } // Generate summary report diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/services/memTracker.hpp --- a/src/hotspot/share/services/memTracker.hpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/services/memTracker.hpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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,14 @@ class Tracker : public StackObj { public: - Tracker() { } - void record(address addr, size_t size) { } + enum TrackerType { + uncommit, + release + }; + Tracker(enum TrackerType type) : _type(type) { } + void record(address addr, size_t size); + private: + enum TrackerType _type; }; class MemTracker : AllStatic { @@ -63,8 +69,6 @@ static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size, const NativeCallStack& stack, MEMFLAGS flag = mtNone) { } static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { } - static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); } - static inline Tracker get_virtual_memory_release_tracker() { return Tracker(); } static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { } static inline void record_thread_stack(void* addr, size_t size) { } static inline void release_thread_stack(void* addr, size_t size) { } @@ -227,16 +231,6 @@ } } - static inline Tracker get_virtual_memory_uncommit_tracker() { - assert(tracking_level() >= NMT_summary, "Check by caller"); - return Tracker(Tracker::uncommit); - } - - static inline Tracker get_virtual_memory_release_tracker() { - assert(tracking_level() >= NMT_summary, "Check by caller"); - return Tracker(Tracker::release); - } - static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { if (tracking_level() < NMT_summary) return; if (addr != NULL) { diff -r 0006d97556ba -r 7c23209e4873 src/hotspot/share/utilities/ostream.cpp --- a/src/hotspot/share/utilities/ostream.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/src/hotspot/share/utilities/ostream.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, 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 @@ -947,18 +947,11 @@ delete classlist_file; } #endif - { - // we temporaly disable PrintMallocFree here - // as otherwise it'll lead to using of almost deleted - // tty or defaultStream::instance in logging facility - // of HeapFree(), see 6391258 - DEBUG_ONLY(FlagSetting fs(PrintMallocFree, false);) - if (tty != defaultStream::instance) { - delete tty; - } - if (defaultStream::instance != NULL) { - delete defaultStream::instance; - } + if (tty != defaultStream::instance) { + delete tty; + } + if (defaultStream::instance != NULL) { + delete defaultStream::instance; } tty = NULL; xtty = NULL; diff -r 0006d97556ba -r 7c23209e4873 src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java Sat Feb 10 09:25:35 2018 +0100 @@ -37,7 +37,7 @@ * unless the argument is specified to be unused or specified to accept a * {@code null} value. * - * @since 10 + * @since 11 */ public final class ConstantBootstraps { // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant: diff -r 0006d97556ba -r 7c23209e4873 src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java Sat Feb 10 09:25:35 2018 +0100 @@ -143,7 +143,7 @@ int alignment = data.getAlignment(); byte[] value = new byte[size]; ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder()); - DataSection.emit(buffer, data, p -> { + DataSection.emit(buffer, data, (p, c) -> { }); String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset; Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/.mx.graal/suite.py --- a/src/jdk.internal.vm.compiler/.mx.graal/suite.py Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/.mx.graal/suite.py Sat Feb 10 09:25:35 2018 +0100 @@ -82,6 +82,24 @@ "javaCompliance" : "1.8", "workingSets" : "API,SDK", }, + "org.graalvm.collections" : { + "subDir" : "share/classes", + "sourceDirs" : ["src"], + "checkstyle" : "org.graalvm.word", + "javaCompliance" : "1.8", + "workingSets" : "API,SDK", + }, + "org.graalvm.collections.test" : { + "subDir" : "share/classes", + "sourceDirs" : ["src"], + "dependencies" : [ + "mx:JUNIT", + "org.graalvm.collections", + ], + "checkstyle" : "org.graalvm.word", + "javaCompliance" : "1.8", + "workingSets" : "API,SDK,Test", + }, # ------------- Graal ------------- @@ -190,6 +208,9 @@ "org.graalvm.util" : { "subDir" : "share/classes", "sourceDirs" : ["src"], + "dependencies" : [ + "org.graalvm.collections", + ], "checkstyle" : "org.graalvm.compiler.graph", "javaCompliance" : "1.8", "workingSets" : "API,Graal", @@ -201,6 +222,7 @@ "dependencies" : [ "mx:JUNIT", "org.graalvm.util", + "org.graalvm.compiler.core.test", ], "checkstyle" : "org.graalvm.compiler.graph", "javaCompliance" : "1.8", @@ -970,10 +992,11 @@ "workingSets" : "Graal,SPARC", }, - "org.graalvm.compiler.core.sparc.test" : { + "org.graalvm.compiler.hotspot.sparc.test" : { "subDir" : "share/classes", "sourceDirs" : ["src"], "dependencies" : [ + "org.graalvm.compiler.hotspot", "org.graalvm.compiler.lir.jtt", "JVMCI_HOTSPOT" ], @@ -1007,6 +1030,7 @@ "subDir" : "share/classes", "sourceDirs" : ["src"], "dependencies" : [ + "org.graalvm.collections", "org.graalvm.compiler.debug", "org.graalvm.word", ], @@ -1037,7 +1061,6 @@ "sourceDirs" : ["src"], "dependencies" : [ "org.graalvm.compiler.debug", - "org.graalvm.util", "mx:JUNIT", ], "checkstyle" : "org.graalvm.compiler.graph", @@ -1225,11 +1248,11 @@ "org.graalvm.compiler.asm.amd64.test", "org.graalvm.compiler.core.aarch64.test", "org.graalvm.compiler.core.amd64.test", - "org.graalvm.compiler.core.sparc.test", "org.graalvm.compiler.debug.test", "org.graalvm.compiler.hotspot.aarch64.test", "org.graalvm.compiler.hotspot.amd64.test", "org.graalvm.compiler.hotspot.lir.test", + "org.graalvm.compiler.hotspot.sparc.test", "org.graalvm.compiler.options.test", "org.graalvm.compiler.jtt", "org.graalvm.compiler.lir.jtt", diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import java.util.Arrays; +import java.util.Iterator; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicSet; +import org.junit.Assert; +import org.junit.Test; + +public class EconomicMapImplTest { + + @Test(expected = UnsupportedOperationException.class) + public void testRemoveNull() { + EconomicMap map = EconomicMap.create(10); + map.removeKey(null); + } + + @Test + public void testInitFromHashSet() { + UnmodifiableEconomicSet set = new UnmodifiableEconomicSet() { + + @Override + public boolean contains(Integer element) { + return element == 0; + } + + @Override + public int size() { + return 1; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + private boolean visited = false; + + @Override + public boolean hasNext() { + return !visited; + } + + @Override + public Integer next() { + if (visited) { + return null; + } else { + visited = true; + return 1; + } + } + }; + } + }; + + EconomicSet newSet = EconomicSet.create(Equivalence.DEFAULT, set); + Assert.assertEquals(newSet.size(), 1); + } + + @Test + public void testCopyHash() { + EconomicSet set = EconomicSet.create(Equivalence.IDENTITY); + set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); + EconomicSet newSet = EconomicSet.create(Equivalence.IDENTITY, set); + Assert.assertEquals(newSet.size(), 10); + newSet.remove(8); + newSet.remove(9); + Assert.assertEquals(newSet.size(), 8); + } + + @Test + public void testNewEquivalence() { + EconomicSet set = EconomicSet.create(new Equivalence() { + @Override + public boolean equals(Object a, Object b) { + return false; + } + + @Override + public int hashCode(Object o) { + return 0; + } + }); + set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); + Assert.assertTrue(set.add(new Integer(0))); + } + + @Test(expected = UnsupportedOperationException.class) + public void testMapPutNull() { + EconomicMap map = EconomicMap.create(); + map.put(null, null); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Objects; +import java.util.Random; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.UnmodifiableMapCursor; +import org.junit.Assert; +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; + +@RunWith(Parameterized.class) +public class EconomicMapLargeTest { + + @Parameter(value = 0) public EconomicMap testMap; + @Parameter(value = 1) public EconomicMap referenceMap; + @Parameter(value = 2) public String name; + + @Parameters(name = "{2}") + public static Collection data() { + return Arrays.asList(new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.create(Equivalence.DEFAULT), "EconomicMap"}, + new Object[]{EconomicMap.create(Equivalence.IDENTITY), EconomicMap.create(Equivalence.IDENTITY), "EconomicMap(IDENTITY)"}, + new Object[]{EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE), EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE), + "EconomicMap(IDENTITY_WITH_SYSTEM_HASHCODE)"}, + new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.wrapMap(new LinkedHashMap<>()), "EconomicMap<->wrapMap"}, + new Object[]{EconomicMap.wrapMap(new LinkedHashMap<>()), EconomicMap.wrapMap(new LinkedHashMap<>()), "wrapMap"}); + } + + private static int[] createRandomRange(Random random, int count) { + int[] result = new int[count]; + for (int i = 0; i < count; ++i) { + int range = random.nextInt(14); + if (range == 0 || range > 10) { + range = Integer.MAX_VALUE; + } else if (range == 10) { + range = 100; + } + result[i] = range; + } + return result; + } + + private static final class BadHashClass { + private int value; + + BadHashClass(int randomInt) { + this.value = randomInt; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object other) { + if (other instanceof BadHashClass) { + BadHashClass badHashClass = (BadHashClass) other; + return badHashClass.value == value; + } + return false; + } + } + + interface MapAction { + Object perform(EconomicMap map, int randomInt); + } + + static final Object EXISTING_VALUE = new Object(); + + static final MapAction[] INCREASE_ACTIONS = new MapAction[]{ + (map, randomInt) -> map.put(randomInt, "value"), + (map, randomInt) -> map.get(randomInt) + }; + + static final MapAction[] ACTIONS = new MapAction[]{ + (map, randomInt) -> map.removeKey(randomInt), + (map, randomInt) -> map.put(randomInt, "value"), + (map, randomInt) -> map.put(randomInt, null), + (map, randomInt) -> map.put(EXISTING_VALUE, randomInt), + (map, randomInt) -> { + if (randomInt == 0) { + map.clear(); + } + return map.isEmpty(); + }, + (map, randomInt) -> map.containsKey(randomInt), + (map, randomInt) -> map.get(randomInt), + (map, randomInt) -> map.put(new BadHashClass(randomInt), "unique"), + (map, randomInt) -> { + if (randomInt == 0) { + map.replaceAll((key, value) -> Objects.toString(value) + "!"); + } + return map.isEmpty(); + } + + }; + + @Test + public void testVeryLarge() { + testMap.clear(); + referenceMap.clear(); + + Random random = new Random(0); + for (int i = 0; i < 200000; ++i) { + for (int j = 0; j < INCREASE_ACTIONS.length; ++j) { + int nextInt = random.nextInt(10000000); + MapAction action = INCREASE_ACTIONS[j]; + Object result = action.perform(testMap, nextInt); + Object referenceResult = action.perform(referenceMap, nextInt); + Assert.assertEquals(result, referenceResult); + } + } + } + + /** + * Tests a sequence of random operations on the map. + */ + @Test + public void testAddRemove() { + testMap.clear(); + referenceMap.clear(); + + for (int seed = 0; seed < 10; ++seed) { + Random random = new Random(seed); + int[] ranges = createRandomRange(random, ACTIONS.length); + int value = random.nextInt(10000); + for (int i = 0; i < value; ++i) { + for (int j = 0; j < ACTIONS.length; ++j) { + if (random.nextInt(ranges[j]) == 0) { + int nextInt = random.nextInt(100); + MapAction action = ACTIONS[j]; + Object result = action.perform(testMap, nextInt); + Object referenceResult = action.perform(referenceMap, nextInt); + Assert.assertEquals(result, referenceResult); + if (j % 100 == 0) { + checkEquality(testMap, referenceMap); + } + } + } + + if (random.nextInt(20) == 0) { + removeElement(random.nextInt(100), testMap, referenceMap); + } + } + } + } + + private static void removeElement(int index, EconomicMap map, EconomicMap referenceMap) { + Assert.assertEquals(referenceMap.size(), map.size()); + MapCursor cursor = map.getEntries(); + MapCursor referenceCursor = referenceMap.getEntries(); + int z = 0; + while (cursor.advance()) { + Assert.assertTrue(referenceCursor.advance()); + Assert.assertEquals(referenceCursor.getKey(), cursor.getKey()); + Assert.assertEquals(referenceCursor.getValue(), cursor.getValue()); + if (index == z) { + cursor.remove(); + referenceCursor.remove(); + } + ++z; + } + + Assert.assertFalse(referenceCursor.advance()); + } + + private static void checkEquality(EconomicMap map, EconomicMap referenceMap) { + Assert.assertEquals(referenceMap.size(), map.size()); + + // Check entries. + UnmodifiableMapCursor cursor = map.getEntries(); + UnmodifiableMapCursor referenceCursor = referenceMap.getEntries(); + while (cursor.advance()) { + Assert.assertTrue(referenceCursor.advance()); + Assert.assertEquals(referenceCursor.getKey(), cursor.getKey()); + Assert.assertEquals(referenceCursor.getValue(), cursor.getValue()); + } + + // Check keys. + Iterator iterator = map.getKeys().iterator(); + Iterator referenceIterator = referenceMap.getKeys().iterator(); + while (iterator.hasNext()) { + Assert.assertTrue(referenceIterator.hasNext()); + Assert.assertEquals(iterator.next(), referenceIterator.next()); + } + + // Check values. + iterator = map.getValues().iterator(); + referenceIterator = referenceMap.getValues().iterator(); + while (iterator.hasNext()) { + Assert.assertTrue(referenceIterator.hasNext()); + Assert.assertEquals(iterator.next(), referenceIterator.next()); + } + Assert.assertFalse(referenceIterator.hasNext()); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import java.util.LinkedHashMap; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.junit.Assert; +import org.junit.Test; + +public class EconomicMapTest { + + @Test + public void testMapGetDefault() { + EconomicMap map = EconomicMap.create(); + map.put(0, 1); + Assert.assertEquals(map.get(0, 2), Integer.valueOf(1)); + Assert.assertEquals(map.get(1, 2), Integer.valueOf(2)); + } + + @Test + public void testMapPutAll() { + EconomicMap map = EconomicMap.create(); + EconomicMap newMap = EconomicMap.wrapMap(new LinkedHashMap<>()); + newMap.put(1, 1); + newMap.put(2, 4); + map.putAll(newMap); + Assert.assertEquals(map.size(), 2); + + UnmodifiableEconomicMap unmodifiableEconomicMap = EconomicMap.create(newMap); + + map.removeKey(1); + map.put(2, 2); + map.put(3, 9); + + map.putAll(unmodifiableEconomicMap); + Assert.assertEquals(map.size(), 3); + Assert.assertEquals(map.get(2), Integer.valueOf(4)); + } + + @Test + public void testToString() { + EconomicMap map = EconomicMap.create(); + map.put(0, 0); + map.put(1, 1); + Assert.assertEquals(map.toString(), "map(size=2, {(0,0),(1,1)})"); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.junit.Assert; +import org.junit.Test; + +public class EconomicSetTest { + + @Test + public void testUtilities() { + EconomicSet set = EconomicSet.create(0); + set.add(0); + Assert.assertTrue(set.add(1)); + Assert.assertEquals(set.size(), 2); + Assert.assertFalse(set.add(1)); + Assert.assertEquals(set.size(), 2); + set.remove(1); + Assert.assertEquals(set.size(), 1); + set.remove(2); + Assert.assertEquals(set.size(), 1); + Assert.assertTrue(set.add(1)); + set.clear(); + Assert.assertEquals(set.size(), 0); + } + + @Test + public void testAddAll() { + EconomicSet set = EconomicSet.create(); + set.addAll(Arrays.asList(0, 1, 0)); + Assert.assertEquals(set.size(), 2); + + EconomicSet newSet = EconomicSet.create(); + newSet.addAll(Arrays.asList(1, 2)); + Assert.assertEquals(newSet.size(), 2); + newSet.addAll(set); + Assert.assertEquals(newSet.size(), 3); + } + + @Test + public void testRemoveAll() { + EconomicSet set = EconomicSet.create(); + set.addAll(Arrays.asList(0, 1)); + + set.removeAll(Arrays.asList(1, 2)); + Assert.assertEquals(set.size(), 1); + + set.removeAll(EconomicSet.create(set)); + Assert.assertEquals(set.size(), 0); + } + + @Test + public void testRetainAll() { + EconomicSet set = EconomicSet.create(); + set.addAll(Arrays.asList(0, 1, 2)); + + EconomicSet newSet = EconomicSet.create(); + newSet.addAll(Arrays.asList(2, 3)); + + set.retainAll(newSet); + Assert.assertEquals(set.size(), 1); + } + + @Test + public void testToArray() { + EconomicSet set = EconomicSet.create(); + set.addAll(Arrays.asList(0, 1)); + Assert.assertArrayEquals(set.toArray(new Integer[2]), new Integer[]{0, 1}); + } + + @Test + public void testToString() { + EconomicSet set = EconomicSet.create(); + set.addAll(Arrays.asList(0, 1)); + Assert.assertEquals(set.toString(), "set(size=2, {0,1})"); + } + + @Test(expected = UnsupportedOperationException.class) + public void testToUnalignedArray() { + Assert.assertArrayEquals(EconomicSet.create().toArray(new Integer[2]), new Integer[0]); + } + + @Test + public void testSetRemoval() { + ArrayList initialList = new ArrayList<>(); + ArrayList removalList = new ArrayList<>(); + ArrayList finalList = new ArrayList<>(); + EconomicSet set = EconomicSet.create(Equivalence.IDENTITY); + set.add(1); + set.add(2); + set.add(3); + set.add(4); + set.add(5); + set.add(6); + set.add(7); + set.add(8); + set.add(9); + Iterator i1 = set.iterator(); + while (i1.hasNext()) { + initialList.add(i1.next()); + } + int size = 0; + Iterator i2 = set.iterator(); + while (i2.hasNext()) { + Integer elem = i2.next(); + if (size++ < 8) { + i2.remove(); + } + removalList.add(elem); + } + Iterator i3 = set.iterator(); + while (i3.hasNext()) { + finalList.add(i3.next()); + } + Assert.assertEquals(initialList, removalList); + Assert.assertEquals(1, finalList.size()); + Assert.assertEquals(new Integer(9), finalList.get(0)); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import org.graalvm.collections.Equivalence; +import org.junit.Assert; +import org.junit.Test; + +public class EquivalenceTest { + + private static final String TEST_STRING = "Graal"; + private static final String TEST_STRING2 = "Graal2"; + + @Test + public void testDEFAULT() { + Assert.assertTrue(Equivalence.DEFAULT.equals(TEST_STRING, new String(TEST_STRING))); + Assert.assertEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(new String(TEST_STRING))); + Assert.assertFalse(Equivalence.DEFAULT.equals(TEST_STRING, TEST_STRING2)); + Assert.assertNotEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(TEST_STRING2)); + } + + @Test + public void testIDENTITY() { + Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, new String(TEST_STRING))); + Assert.assertEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(new String(TEST_STRING))); + Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, TEST_STRING2)); + Assert.assertNotEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(TEST_STRING2)); + } + + @Test + public void testIDENTITYWITHSYSTEMHASHCODE() { + Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, new String(TEST_STRING))); + Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(new String(TEST_STRING))); + Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, TEST_STRING2)); + Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING2)); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections.test; + +import org.graalvm.collections.Pair; +import org.junit.Assert; +import org.junit.Test; + +public class PairTest { + + @Test + public void testCreate() { + Assert.assertEquals(Pair.create(null, null), Pair.empty()); + Assert.assertNotEquals(Pair.create(null, null), null); + Assert.assertEquals(Pair.createLeft(null), Pair.empty()); + Assert.assertEquals(Pair.createRight(null), Pair.empty()); + Assert.assertEquals(Pair.create(1, null), Pair.createLeft(1)); + Assert.assertEquals(Pair.create(null, 1), Pair.createRight(1)); + } + + @Test + public void testUtilities() { + Pair pair = Pair.create(1, null); + Assert.assertEquals(pair.getLeft(), Integer.valueOf(1)); + Assert.assertEquals(pair.getRight(), null); + Assert.assertEquals(pair.toString(), "(1, null)"); + Assert.assertEquals(pair.hashCode(), Pair.createLeft(1).hashCode()); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +import java.util.Iterator; +import java.util.Map; +import java.util.function.BiFunction; + +/** + * Memory efficient map data structure. + * + * @since 1.0 + */ +public interface EconomicMap extends UnmodifiableEconomicMap { + + /** + * Associates {@code value} with {@code key} in this map. If the map previously contained a + * mapping for {@code key}, the old value is replaced by {@code value}. + * + * @return the previous value associated with {@code key}, or {@code null} if there was no + * mapping for {@code key}. + * @since 1.0 + */ + V put(K key, V value); + + /** + * Copies all of the mappings from {@code other} to this map. + * + * @since 1.0 + */ + default void putAll(EconomicMap other) { + MapCursor e = other.getEntries(); + while (e.advance()) { + put(e.getKey(), e.getValue()); + } + } + + /** + * Copies all of the mappings from {@code other} to this map. + * + * @since 1.0 + */ + default void putAll(UnmodifiableEconomicMap other) { + UnmodifiableMapCursor entry = other.getEntries(); + while (entry.advance()) { + put(entry.getKey(), entry.getValue()); + } + } + + /** + * Removes all of the mappings from this map. The map will be empty after this call returns. + * + * @since 1.0 + */ + void clear(); + + /** + * Removes the mapping for {@code key} from this map if it is present. The map will not contain + * a mapping for {@code key} once the call returns. + * + * @return the previous value associated with {@code key}, or {@code null} if there was no + * mapping for {@code key}. + * @since 1.0 + */ + V removeKey(K key); + + /** + * Returns a {@link MapCursor} view of the mappings contained in this map. + * + * @since 1.0 + */ + @Override + MapCursor getEntries(); + + /** + * Replaces each entry's value with the result of invoking {@code function} on that entry until + * all entries have been processed or the function throws an exception. Exceptions thrown by the + * function are relayed to the caller. + * + * @since 1.0 + */ + void replaceAll(BiFunction function); + + /** + * Creates a new map that guarantees insertion order on the key set with the default + * {@link Equivalence#DEFAULT} comparison strategy for keys. + * + * @since 1.0 + */ + static EconomicMap create() { + return EconomicMap.create(Equivalence.DEFAULT); + } + + /** + * Creates a new map that guarantees insertion order on the key set with the default + * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified + * capacity. + * + * @since 1.0 + */ + static EconomicMap create(int initialCapacity) { + return EconomicMap.create(Equivalence.DEFAULT, initialCapacity); + } + + /** + * Creates a new map that guarantees insertion order on the key set with the given comparison + * strategy for keys. + * + * @since 1.0 + */ + static EconomicMap create(Equivalence strategy) { + return EconomicMapImpl.create(strategy, false); + } + + /** + * Creates a new map that guarantees insertion order on the key set with the default + * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the + * specified existing map. + * + * @since 1.0 + */ + static EconomicMap create(UnmodifiableEconomicMap m) { + return EconomicMap.create(Equivalence.DEFAULT, m); + } + + /** + * Creates a new map that guarantees insertion order on the key set and copies all elements from + * the specified existing map. + * + * @since 1.0 + */ + static EconomicMap create(Equivalence strategy, UnmodifiableEconomicMap m) { + return EconomicMapImpl.create(strategy, m, false); + } + + /** + * Creates a new map that guarantees insertion order on the key set and initializes with a + * specified capacity. + * + * @since 1.0 + */ + static EconomicMap create(Equivalence strategy, int initialCapacity) { + return EconomicMapImpl.create(strategy, initialCapacity, false); + } + + /** + * Wraps an existing {@link Map} as an {@link EconomicMap}. + * + * @since 1.0 + */ + static EconomicMap wrapMap(Map map) { + return new EconomicMap() { + + @Override + public V get(K key) { + V result = map.get(key); + return result; + } + + @Override + public V put(K key, V value) { + V result = map.put(key, value); + return result; + } + + @Override + public int size() { + int result = map.size(); + return result; + } + + @Override + public boolean containsKey(K key) { + return map.containsKey(key); + } + + @Override + public void clear() { + map.clear(); + } + + @Override + public V removeKey(K key) { + V result = map.remove(key); + return result; + } + + @Override + public Iterable getValues() { + return map.values(); + } + + @Override + public Iterable getKeys() { + return map.keySet(); + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public MapCursor getEntries() { + Iterator> iterator = map.entrySet().iterator(); + return new MapCursor() { + + private Map.Entry current; + + @Override + public boolean advance() { + boolean result = iterator.hasNext(); + if (result) { + current = iterator.next(); + } + + return result; + } + + @Override + public K getKey() { + return current.getKey(); + } + + @Override + public V getValue() { + return current.getValue(); + } + + @Override + public void remove() { + iterator.remove(); + } + }; + } + + @Override + public void replaceAll(BiFunction function) { + map.replaceAll(function); + } + }; + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,857 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +import java.util.Iterator; +import java.util.Objects; +import java.util.function.BiFunction; + +/** + * Implementation of a map with a memory-efficient structure that always preserves insertion order + * when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal + * {@link #INITIAL_CAPACITY} or smaller 256. + * + * The key/value pairs are kept in an expanding flat object array with keys at even indices and + * values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there + * is no additional hash data structure and comparisons are done via linear checking of the + * key/value pairs. For the case where the equality check is particularly cheap (e.g., just an + * object identity comparison), this limit below which the map is without an actual hash table is + * higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}. + * + * When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash + * array where an entry of 0 means no hit and otherwise denotes the entry number in the + * {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit + * within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of + * integer values in other cases. + * + * Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take + * the place of the values in the {@link #entries} array. + * + * Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the + * map falls below a specific threshold, the map will be compressed via the + * {@link #maybeCompress(int)} method. + */ +final class EconomicMapImpl implements EconomicMap, EconomicSet { + + /** + * Initial number of key/value pair entries that is allocated in the first entries array. + */ + private static final int INITIAL_CAPACITY = 4; + + /** + * Maximum number of entries that are moved linearly forward if a key is removed. + */ + private static final int COMPRESS_IMMEDIATE_CAPACITY = 8; + + /** + * Minimum number of key/value pair entries added when the entries array is increased in size. + */ + private static final int MIN_CAPACITY_INCREASE = 8; + + /** + * Number of entries above which a hash table is created. + */ + private static final int HASH_THRESHOLD = 4; + + /** + * Number of entries above which a hash table is created when equality can be checked with + * object identity. + */ + private static final int HASH_THRESHOLD_IDENTITY_COMPARE = 8; + + /** + * Maximum number of entries allowed in the map. + */ + private static final int MAX_ELEMENT_COUNT = Integer.MAX_VALUE >> 1; + + /** + * Number of entries above which more than 1 byte is necessary for the hash index. + */ + private static final int LARGE_HASH_THRESHOLD = ((1 << Byte.SIZE) << 1); + + /** + * Number of entries above which more than 2 bytes are are necessary for the hash index. + */ + private static final int VERY_LARGE_HASH_THRESHOLD = (LARGE_HASH_THRESHOLD << Byte.SIZE); + + /** + * Total number of entries (actual entries plus deleted entries). + */ + private int totalEntries; + + /** + * Number of deleted entries. + */ + private int deletedEntries; + + /** + * Entries array with even indices storing keys and odd indices storing values. + */ + private Object[] entries; + + /** + * Hash array that is interpreted either as byte or short or int array depending on number of + * map entries. + */ + private byte[] hashArray; + + /** + * The strategy used for comparing keys or {@code null} for denoting special strategy + * {@link Equivalence#IDENTITY}. + */ + private final Equivalence strategy; + + /** + * Intercept method for debugging purposes. + */ + private static EconomicMapImpl intercept(EconomicMapImpl map) { + return map; + } + + public static EconomicMapImpl create(Equivalence strategy, boolean isSet) { + return intercept(new EconomicMapImpl<>(strategy, isSet)); + } + + public static EconomicMapImpl create(Equivalence strategy, int initialCapacity, boolean isSet) { + return intercept(new EconomicMapImpl<>(strategy, initialCapacity, isSet)); + } + + public static EconomicMapImpl create(Equivalence strategy, UnmodifiableEconomicMap other, boolean isSet) { + return intercept(new EconomicMapImpl<>(strategy, other, isSet)); + } + + public static EconomicMapImpl create(Equivalence strategy, UnmodifiableEconomicSet other, boolean isSet) { + return intercept(new EconomicMapImpl<>(strategy, other, isSet)); + } + + private EconomicMapImpl(Equivalence strategy, boolean isSet) { + if (strategy == Equivalence.IDENTITY) { + this.strategy = null; + } else { + this.strategy = strategy; + } + this.isSet = isSet; + } + + private EconomicMapImpl(Equivalence strategy, int initialCapacity, boolean isSet) { + this(strategy, isSet); + init(initialCapacity); + } + + private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicMap other, boolean isSet) { + this(strategy, isSet); + if (!initFrom(other)) { + init(other.size()); + putAll(other); + } + } + + private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicSet other, boolean isSet) { + this(strategy, isSet); + if (!initFrom(other)) { + init(other.size()); + addAll(other); + } + } + + @SuppressWarnings("unchecked") + private boolean initFrom(Object o) { + if (o instanceof EconomicMapImpl) { + EconomicMapImpl otherMap = (EconomicMapImpl) o; + // We are only allowed to directly copy if the strategies of the two maps are the same. + if (strategy == otherMap.strategy) { + totalEntries = otherMap.totalEntries; + deletedEntries = otherMap.deletedEntries; + if (otherMap.entries != null) { + entries = otherMap.entries.clone(); + } + if (otherMap.hashArray != null) { + hashArray = otherMap.hashArray.clone(); + } + return true; + } + } + return false; + } + + private void init(int size) { + if (size > INITIAL_CAPACITY) { + entries = new Object[size << 1]; + } + } + + /** + * Links the collisions. Needs to be immutable class for allowing efficient shallow copy from + * other map on construction. + */ + private static final class CollisionLink { + + CollisionLink(Object value, int next) { + this.value = value; + this.next = next; + } + + final Object value; + + /** + * Index plus one of the next entry in the collision link chain. + */ + final int next; + } + + @SuppressWarnings("unchecked") + @Override + public V get(K key) { + Objects.requireNonNull(key); + + int index = find(key); + if (index != -1) { + return (V) getValue(index); + } + return null; + } + + private int find(K key) { + if (hasHashArray()) { + return findHash(key); + } else { + return findLinear(key); + } + } + + private int findLinear(K key) { + for (int i = 0; i < totalEntries; i++) { + Object entryKey = entries[i << 1]; + if (entryKey != null && compareKeys(key, entryKey)) { + return i; + } + } + return -1; + } + + private boolean compareKeys(Object key, Object entryKey) { + if (key == entryKey) { + return true; + } + if (strategy != null && strategy != Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { + if (strategy == Equivalence.DEFAULT) { + return key.equals(entryKey); + } else { + return strategy.equals(key, entryKey); + } + } + return false; + } + + private int findHash(K key) { + int index = getHashArray(getHashIndex(key)) - 1; + if (index != -1) { + Object entryKey = getKey(index); + if (compareKeys(key, entryKey)) { + return index; + } else { + Object entryValue = getRawValue(index); + if (entryValue instanceof CollisionLink) { + return findWithCollision(key, (CollisionLink) entryValue); + } + } + } + + return -1; + } + + private int findWithCollision(K key, CollisionLink initialEntryValue) { + int index; + Object entryKey; + CollisionLink entryValue = initialEntryValue; + while (true) { + CollisionLink collisionLink = entryValue; + index = collisionLink.next; + entryKey = getKey(index); + if (compareKeys(key, entryKey)) { + return index; + } else { + Object value = getRawValue(index); + if (value instanceof CollisionLink) { + entryValue = (CollisionLink) getRawValue(index); + } else { + return -1; + } + } + } + } + + private int getHashArray(int index) { + if (entries.length < LARGE_HASH_THRESHOLD) { + return (hashArray[index] & 0xFF); + } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { + int adjustedIndex = index << 1; + return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8); + } else { + int adjustedIndex = index << 2; + return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8) | ((hashArray[adjustedIndex + 2] & 0xFF) << 16) | ((hashArray[adjustedIndex + 3] & 0xFF) << 24); + } + } + + private void setHashArray(int index, int value) { + if (entries.length < LARGE_HASH_THRESHOLD) { + hashArray[index] = (byte) value; + } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { + int adjustedIndex = index << 1; + hashArray[adjustedIndex] = (byte) value; + hashArray[adjustedIndex + 1] = (byte) (value >> 8); + } else { + int adjustedIndex = index << 2; + hashArray[adjustedIndex] = (byte) value; + hashArray[adjustedIndex + 1] = (byte) (value >> 8); + hashArray[adjustedIndex + 2] = (byte) (value >> 16); + hashArray[adjustedIndex + 3] = (byte) (value >> 24); + } + } + + private int findAndRemoveHash(Object key) { + int hashIndex = getHashIndex(key); + int index = getHashArray(hashIndex) - 1; + if (index != -1) { + Object entryKey = getKey(index); + if (compareKeys(key, entryKey)) { + Object value = getRawValue(index); + int nextIndex = -1; + if (value instanceof CollisionLink) { + CollisionLink collisionLink = (CollisionLink) value; + nextIndex = collisionLink.next; + } + setHashArray(hashIndex, nextIndex + 1); + return index; + } else { + Object entryValue = getRawValue(index); + if (entryValue instanceof CollisionLink) { + return findAndRemoveWithCollision(key, (CollisionLink) entryValue, index); + } + } + } + + return -1; + } + + private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryValue, int initialIndexValue) { + int index; + Object entryKey; + CollisionLink entryValue = initialEntryValue; + int lastIndex = initialIndexValue; + while (true) { + CollisionLink collisionLink = entryValue; + index = collisionLink.next; + entryKey = getKey(index); + if (compareKeys(key, entryKey)) { + Object value = getRawValue(index); + if (value instanceof CollisionLink) { + CollisionLink thisCollisionLink = (CollisionLink) value; + setRawValue(lastIndex, new CollisionLink(collisionLink.value, thisCollisionLink.next)); + } else { + setRawValue(lastIndex, collisionLink.value); + } + return index; + } else { + Object value = getRawValue(index); + if (value instanceof CollisionLink) { + entryValue = (CollisionLink) getRawValue(index); + lastIndex = index; + } else { + return -1; + } + } + } + } + + private int getHashIndex(Object key) { + int hash; + if (strategy != null && strategy != Equivalence.DEFAULT) { + if (strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { + hash = System.identityHashCode(key); + } else { + hash = strategy.hashCode(key); + } + } else { + hash = key.hashCode(); + } + hash = hash ^ (hash >>> 16); + return hash & (getHashTableSize() - 1); + } + + @SuppressWarnings("unchecked") + @Override + public V put(K key, V value) { + if (key == null) { + throw new UnsupportedOperationException("null not supported as key!"); + } + int index = find(key); + if (index != -1) { + Object oldValue = getValue(index); + setValue(index, value); + return (V) oldValue; + } + + int nextEntryIndex = totalEntries; + if (entries == null) { + entries = new Object[INITIAL_CAPACITY << 1]; + } else if (entries.length == nextEntryIndex << 1) { + grow(); + + assert entries.length > totalEntries << 1; + // Can change if grow is actually compressing. + nextEntryIndex = totalEntries; + } + + setKey(nextEntryIndex, key); + setValue(nextEntryIndex, value); + totalEntries++; + + if (hasHashArray()) { + // Rehash on collision if hash table is more than three quarters full. + boolean rehashOnCollision = (getHashTableSize() < (size() + (size() >> 1))); + putHashEntry(key, nextEntryIndex, rehashOnCollision); + } else if (totalEntries > getHashThreshold()) { + createHash(); + } + + return null; + } + + /** + * Number of entries above which a hash table should be constructed. + */ + private int getHashThreshold() { + if (strategy == null || strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { + return HASH_THRESHOLD_IDENTITY_COMPARE; + } else { + return HASH_THRESHOLD; + } + } + + private void grow() { + int entriesLength = entries.length; + int newSize = (entriesLength >> 1) + Math.max(MIN_CAPACITY_INCREASE, entriesLength >> 2); + if (newSize > MAX_ELEMENT_COUNT) { + throw new UnsupportedOperationException("map grown too large!"); + } + Object[] newEntries = new Object[newSize << 1]; + System.arraycopy(entries, 0, newEntries, 0, entriesLength); + entries = newEntries; + if ((entriesLength < LARGE_HASH_THRESHOLD && newEntries.length >= LARGE_HASH_THRESHOLD) || + (entriesLength < VERY_LARGE_HASH_THRESHOLD && newEntries.length > VERY_LARGE_HASH_THRESHOLD)) { + // Rehash in order to change number of bits reserved for hash indices. + createHash(); + } + } + + /** + * Compresses the graph if there is a large number of deleted entries and returns the translated + * new next index. + */ + private int maybeCompress(int nextIndex) { + if (entries.length != INITIAL_CAPACITY << 1 && deletedEntries >= (totalEntries >> 1) + (totalEntries >> 2)) { + return compressLarge(nextIndex); + } + return nextIndex; + } + + /** + * Compresses the graph and returns the translated new next index. + */ + private int compressLarge(int nextIndex) { + int size = INITIAL_CAPACITY; + int remaining = totalEntries - deletedEntries; + + while (size <= remaining) { + size += Math.max(MIN_CAPACITY_INCREASE, size >> 1); + } + + Object[] newEntries = new Object[size << 1]; + int z = 0; + int newNextIndex = remaining; + for (int i = 0; i < totalEntries; ++i) { + Object key = getKey(i); + if (i == nextIndex) { + newNextIndex = z; + } + if (key != null) { + newEntries[z << 1] = key; + newEntries[(z << 1) + 1] = getValue(i); + z++; + } + } + + this.entries = newEntries; + totalEntries = z; + deletedEntries = 0; + if (z <= getHashThreshold()) { + this.hashArray = null; + } else { + createHash(); + } + return newNextIndex; + } + + private int getHashTableSize() { + if (entries.length < LARGE_HASH_THRESHOLD) { + return hashArray.length; + } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { + return hashArray.length >> 1; + } else { + return hashArray.length >> 2; + } + } + + private void createHash() { + int entryCount = size(); + + // Calculate smallest 2^n that is greater number of entries. + int size = getHashThreshold(); + while (size <= entryCount) { + size <<= 1; + } + + // Give extra size to avoid collisions. + size <<= 1; + + if (this.entries.length >= VERY_LARGE_HASH_THRESHOLD) { + // Every entry has 4 bytes. + size <<= 2; + } else if (this.entries.length >= LARGE_HASH_THRESHOLD) { + // Every entry has 2 bytes. + size <<= 1; + } else { + // Entries are very small => give extra size to further reduce collisions. + size <<= 1; + } + + hashArray = new byte[size]; + for (int i = 0; i < totalEntries; i++) { + Object entryKey = getKey(i); + if (entryKey != null) { + putHashEntry(entryKey, i, false); + } + } + } + + private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) { + int hashIndex = getHashIndex(key); + int oldIndex = getHashArray(hashIndex) - 1; + if (oldIndex != -1 && rehashOnCollision) { + this.createHash(); + return; + } + setHashArray(hashIndex, entryIndex + 1); + Object value = getRawValue(entryIndex); + if (oldIndex != -1) { + assert entryIndex != oldIndex : "this cannot happend and would create an endless collision link cycle"; + if (value instanceof CollisionLink) { + CollisionLink collisionLink = (CollisionLink) value; + setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex)); + } else { + setRawValue(entryIndex, new CollisionLink(getRawValue(entryIndex), oldIndex)); + } + } else { + if (value instanceof CollisionLink) { + CollisionLink collisionLink = (CollisionLink) value; + setRawValue(entryIndex, collisionLink.value); + } + } + } + + @Override + public int size() { + return totalEntries - deletedEntries; + } + + @Override + public boolean containsKey(K key) { + return find(key) != -1; + } + + @Override + public void clear() { + entries = null; + hashArray = null; + totalEntries = deletedEntries = 0; + } + + private boolean hasHashArray() { + return hashArray != null; + } + + @SuppressWarnings("unchecked") + @Override + public V removeKey(K key) { + if (key == null) { + throw new UnsupportedOperationException("null not supported as key!"); + } + int index; + if (hasHashArray()) { + index = this.findAndRemoveHash(key); + } else { + index = this.findLinear(key); + } + + if (index != -1) { + Object value = getValue(index); + remove(index); + return (V) value; + } + return null; + } + + /** + * Removes the element at the specific index and returns the index of the next element. This can + * be a different value if graph compression was triggered. + */ + private int remove(int indexToRemove) { + int index = indexToRemove; + int entriesAfterIndex = totalEntries - index - 1; + int result = index + 1; + + // Without hash array, compress immediately. + if (entriesAfterIndex <= COMPRESS_IMMEDIATE_CAPACITY && !hasHashArray()) { + while (index < totalEntries - 1) { + setKey(index, getKey(index + 1)); + setRawValue(index, getRawValue(index + 1)); + index++; + } + result--; + } + + setKey(index, null); + setRawValue(index, null); + if (index == totalEntries - 1) { + // Make sure last element is always non-null. + totalEntries--; + while (index > 0 && getKey(index - 1) == null) { + totalEntries--; + deletedEntries--; + index--; + } + } else { + deletedEntries++; + result = maybeCompress(result); + } + + return result; + } + + private abstract class SparseMapIterator implements Iterator { + + protected int current; + + @Override + public boolean hasNext() { + return current < totalEntries; + } + + @Override + public void remove() { + if (hasHashArray()) { + EconomicMapImpl.this.findAndRemoveHash(getKey(current - 1)); + } + current = EconomicMapImpl.this.remove(current - 1); + } + } + + @Override + public Iterable getValues() { + return new Iterable() { + @Override + public Iterator iterator() { + return new SparseMapIterator() { + @SuppressWarnings("unchecked") + @Override + public V next() { + Object result; + while (true) { + result = getValue(current); + if (result == null && getKey(current) == null) { + // values can be null, double-check if key is also null + current++; + } else { + current++; + break; + } + } + return (V) result; + } + }; + } + }; + } + + @Override + public Iterable getKeys() { + return this; + } + + @Override + public boolean isEmpty() { + return this.size() == 0; + } + + @Override + public MapCursor getEntries() { + return new MapCursor() { + int current = -1; + + @Override + public boolean advance() { + current++; + if (current >= totalEntries) { + return false; + } else { + while (EconomicMapImpl.this.getKey(current) == null) { + // Skip over null entries + current++; + } + return true; + } + } + + @SuppressWarnings("unchecked") + @Override + public K getKey() { + return (K) EconomicMapImpl.this.getKey(current); + } + + @SuppressWarnings("unchecked") + @Override + public V getValue() { + return (V) EconomicMapImpl.this.getValue(current); + } + + @Override + public void remove() { + if (hasHashArray()) { + EconomicMapImpl.this.findAndRemoveHash(EconomicMapImpl.this.getKey(current)); + } + current = EconomicMapImpl.this.remove(current) - 1; + } + }; + } + + @SuppressWarnings("unchecked") + @Override + public void replaceAll(BiFunction function) { + for (int i = 0; i < totalEntries; i++) { + Object entryKey = getKey(i); + if (entryKey != null) { + Object newValue = function.apply((K) entryKey, (V) getValue(i)); + setValue(i, newValue); + } + } + } + + private Object getKey(int index) { + return entries[index << 1]; + } + + private void setKey(int index, Object newValue) { + entries[index << 1] = newValue; + } + + private void setValue(int index, Object newValue) { + Object oldValue = getRawValue(index); + if (oldValue instanceof CollisionLink) { + CollisionLink collisionLink = (CollisionLink) oldValue; + setRawValue(index, new CollisionLink(newValue, collisionLink.next)); + } else { + setRawValue(index, newValue); + } + } + + private void setRawValue(int index, Object newValue) { + entries[(index << 1) + 1] = newValue; + } + + private Object getRawValue(int index) { + return entries[(index << 1) + 1]; + } + + private Object getValue(int index) { + Object object = getRawValue(index); + if (object instanceof CollisionLink) { + return ((CollisionLink) object).value; + } + return object; + } + + private final boolean isSet; + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(isSet ? "set(size=" : "map(size=").append(size()).append(", {"); + String sep = ""; + MapCursor cursor = getEntries(); + while (cursor.advance()) { + builder.append(sep); + if (isSet) { + builder.append(cursor.getKey()); + } else { + builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append(")"); + } + sep = ","; + } + builder.append("})"); + return builder.toString(); + } + + @Override + public Iterator iterator() { + return new SparseMapIterator() { + @SuppressWarnings("unchecked") + @Override + public K next() { + Object result; + while ((result = getKey(current++)) == null) { + // skip null entries + } + return (K) result; + } + }; + } + + @Override + public boolean contains(K element) { + return containsKey(element); + } + + @SuppressWarnings("unchecked") + @Override + public boolean add(K element) { + return put(element, (V) element) == null; + } + + @Override + public void remove(K element) { + removeKey(element); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +import java.util.Iterator; + +/** + * Memory efficient set data structure. + * + * @since 1.0 + */ +public interface EconomicSet extends UnmodifiableEconomicSet { + + /** + * Adds {@code element} to this set if it is not already present. + * + * @return {@code true} if this set did not already contain {@code element}. + * @since 1.0 + */ + boolean add(E element); + + /** + * Removes {@code element} from this set if it is present. This set will not contain + * {@code element} once the call returns. + * + * @since 1.0 + */ + void remove(E element); + + /** + * Removes all of the elements from this set. The set will be empty after this call returns. + * + * @since 1.0 + */ + void clear(); + + /** + * Adds all of the elements in {@code other} to this set if they're not already present. + * + * @since 1.0 + */ + default void addAll(EconomicSet other) { + addAll(other.iterator()); + } + + /** + * Adds all of the elements in {@code values} to this set if they're not already present. + * + * @since 1.0 + */ + default void addAll(Iterable values) { + addAll(values.iterator()); + } + + /** + * Adds all of the elements enumerated by {@code iterator} to this set if they're not already + * present. + * + * @since 1.0 + */ + default void addAll(Iterator iterator) { + while (iterator.hasNext()) { + add(iterator.next()); + } + } + + /** + * Removes from this set all of its elements that are contained in {@code other}. + * + * @since 1.0 + */ + default void removeAll(EconomicSet other) { + removeAll(other.iterator()); + } + + /** + * Removes from this set all of its elements that are contained in {@code values}. + * + * @since 1.0 + */ + default void removeAll(Iterable values) { + removeAll(values.iterator()); + } + + /** + * Removes from this set all of its elements that are enumerated by {@code iterator}. + * + * @since 1.0 + */ + default void removeAll(Iterator iterator) { + while (iterator.hasNext()) { + remove(iterator.next()); + } + } + + /** + * Removes from this set all of its elements that are not contained in {@code other}. + * + * @since 1.0 + */ + default void retainAll(EconomicSet other) { + Iterator iterator = iterator(); + while (iterator.hasNext()) { + E key = iterator.next(); + if (!other.contains(key)) { + iterator.remove(); + } + } + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements with the + * default {@link Equivalence#DEFAULT} comparison strategy. + * + * @since 1.0 + */ + static EconomicSet create() { + return EconomicSet.create(Equivalence.DEFAULT); + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements. + * + * @since 1.0 + */ + static EconomicSet create(Equivalence strategy) { + return EconomicMapImpl.create(strategy, true); + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements with the + * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the + * specified collection. + * + * @since 1.0 + */ + static EconomicSet create(int initialCapacity) { + return EconomicSet.create(Equivalence.DEFAULT, initialCapacity); + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements with the + * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the + * specified collection. + * + * @since 1.0 + */ + static EconomicSet create(UnmodifiableEconomicSet c) { + return EconomicSet.create(Equivalence.DEFAULT, c); + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements and + * initializes with the given capacity. + * + * @since 1.0 + */ + static EconomicSet create(Equivalence strategy, int initialCapacity) { + return EconomicMapImpl.create(strategy, initialCapacity, true); + } + + /** + * Creates a new set guaranteeing insertion order when iterating over its elements and inserts + * all elements of the specified collection. + * + * @since 1.0 + */ + static EconomicSet create(Equivalence strategy, UnmodifiableEconomicSet c) { + return EconomicMapImpl.create(strategy, c, true); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +/** + * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT}, + * {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}. + * + * @since 1.0 + */ +public abstract class Equivalence { + + /** + * Default equivalence calling {@link #equals(Object)} to check equality and {@link #hashCode()} + * for obtaining hash values. Do not change the logic of this class as it may be inlined in + * other places. + * + * @since 1.0 + */ + public static final Equivalence DEFAULT = new Equivalence() { + + @Override + public boolean equals(Object a, Object b) { + return a.equals(b); + } + + @Override + public int hashCode(Object o) { + return o.hashCode(); + } + }; + + /** + * Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining + * hash values. Do not change the logic of this class as it may be inlined in other places. + * + * @since 1.0 + */ + public static final Equivalence IDENTITY = new Equivalence() { + + @Override + public boolean equals(Object a, Object b) { + return a == b; + } + + @Override + public int hashCode(Object o) { + return o.hashCode(); + } + }; + + /** + * Identity equivalence using {@code ==} to check equality and + * {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of + * this class as it may be inlined in other places. + * + * @since 1.0 + */ + public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() { + + @Override + public boolean equals(Object a, Object b) { + return a == b; + } + + @Override + public int hashCode(Object o) { + return System.identityHashCode(o); + } + }; + + /** + * Subclass for creating custom equivalence definitions. + * + * @since 1.0 + */ + protected Equivalence() { + } + + /** + * Returns {@code true} if the non-{@code null} arguments are equal to each other and + * {@code false} otherwise. + * + * @since 1.0 + */ + public abstract boolean equals(Object a, Object b); + + /** + * Returns the hash code of a non-{@code null} argument {@code o}. + * + * @since 1.0 + */ + public abstract int hashCode(Object o); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +/** + * Cursor to iterate over a mutable map. + * + * @since 1.0 + */ +public interface MapCursor extends UnmodifiableMapCursor { + /** + * Remove the current entry from the map. May only be called once. After calling + * {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on + * the current entry. + * + * @since 1.0 + */ + void remove(); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +import java.util.Objects; + +/** + * Utility class representing a pair of values. + * + * @since 1.0 + */ +public final class Pair { + + private static final Pair EMPTY = new Pair<>(null, null); + + private final L left; + private final R right; + + /** + * Returns an empty pair. + * + * @since 1.0 + */ + @SuppressWarnings("unchecked") + public static Pair empty() { + return (Pair) EMPTY; + } + + /** + * Constructs a pair with its left value being {@code left}, or returns an empty pair if + * {@code left} is null. + * + * @return the constructed pair or an empty pair if {@code left} is null. + * @since 1.0 + */ + public static Pair createLeft(L left) { + if (left == null) { + return empty(); + } else { + return new Pair<>(left, null); + } + } + + /** + * Constructs a pair with its right value being {@code right}, or returns an empty pair if + * {@code right} is null. + * + * @return the constructed pair or an empty pair if {@code right} is null. + * @since 1.0 + */ + public static Pair createRight(R right) { + if (right == null) { + return empty(); + } else { + return new Pair<>(null, right); + } + } + + /** + * Constructs a pair with its left value being {@code left}, and its right value being + * {@code right}, or returns an empty pair if both inputs are null. + * + * @return the constructed pair or an empty pair if both inputs are null. + * @since 1.0 + */ + public static Pair create(L left, R right) { + if (right == null && left == null) { + return empty(); + } else { + return new Pair<>(left, right); + } + } + + private Pair(L left, R right) { + this.left = left; + this.right = right; + } + + /** + * Returns the left value of this pair. + * + * @since 1.0 + */ + public L getLeft() { + return left; + } + + /** + * Returns the right value of this pair. + * + * @since 1.0 + */ + public R getRight() { + return right; + } + + /** + * {@inheritDoc} + * + * @since 1.0 + */ + @Override + public int hashCode() { + return Objects.hashCode(left) + 31 * Objects.hashCode(right); + } + + /** + * {@inheritDoc} + * + * @since 1.0 + */ + @SuppressWarnings("unchecked") + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj instanceof Pair) { + Pair pair = (Pair) obj; + return Objects.equals(left, pair.left) && Objects.equals(right, pair.right); + } + + return false; + } + + /** + * {@inheritDoc} + * + * @since 1.0 + */ + @Override + public String toString() { + return String.format("(%s, %s)", left, right); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +/** + * Unmodifiable memory efficient map data structure. + * + * @since 1.0 + */ +public interface UnmodifiableEconomicMap { + + /** + * Returns the value to which {@code key} is mapped, or {@code null} if this map contains no + * mapping for {@code key}. + * + * @since 1.0 + */ + V get(K key); + + /** + * Returns the value to which {@code key} is mapped, or {@code defaultValue} if this map + * contains no mapping for {@code key}. + * + * @since 1.0 + */ + default V get(K key, V defaultValue) { + V v = get(key); + if (v == null) { + return defaultValue; + } + return v; + } + + /** + * Returns {@code true} if this map contains a mapping for {@code key}. + * + * @since 1.0 + */ + boolean containsKey(K key); + + /** + * Returns the number of key-value mappings in this map. + * + * @since 1.0 + */ + int size(); + + /** + * Returns {@code true} if this map contains no key-value mappings. + * + * @since 1.0 + */ + boolean isEmpty(); + + /** + * Returns a {@link Iterable} view of the values contained in this map. + * + * @since 1.0 + */ + Iterable getValues(); + + /** + * Returns a {@link Iterable} view of the keys contained in this map. + * + * @since 1.0 + */ + Iterable getKeys(); + + /** + * Returns a {@link UnmodifiableMapCursor} view of the mappings contained in this map. + * + * @since 1.0 + */ + UnmodifiableMapCursor getEntries(); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +/** + * Unmodifiable memory efficient set data structure. + * + * @since 1.0 + */ +public interface UnmodifiableEconomicSet extends Iterable { + + /** + * Returns {@code true} if this set contains a mapping for the {@code element}. + * + * @since 1.0 + */ + boolean contains(E element); + + /** + * Returns the number of elements in this set. + * + * @since 1.0 + */ + int size(); + + /** + * Returns {@code true} if this set contains no elements. + * + * @since 1.0 + */ + boolean isEmpty(); + + /** + * Stores all of the elements in this set into {@code target}. An + * {@link UnsupportedOperationException} will be thrown if the length of {@code target} does not + * match the size of this set. + * + * @return an array containing all the elements in this set. + * @throws UnsupportedOperationException if the length of {@code target} does not equal the size + * of this set. + * @since 1.0 + */ + default E[] toArray(E[] target) { + if (target.length != size()) { + throw new UnsupportedOperationException("Length of target array must equal the size of the set."); + } + + int index = 0; + for (E element : this) { + target[index++] = element; + } + + return target; + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, 2017, 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 org.graalvm.collections; + +/** + * Cursor to iterate over a map without changing its contents. + * + * @since 1.0 + */ +public interface UnmodifiableMapCursor { + /** + * Advances to the next entry. + * + * @return {@code true} if a next entry exists, {@code false} if there is no next entry. + * @since 1.0 + */ + boolean advance(); + + /** + * The key of the current entry. + * + * @since 1.0 + */ + K getKey(); + + /** + * The value of the current entry. + * + * @since 1.0 + */ + V getValue(); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017, 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. + */ +/** + * The Graal-SDK collections package contains memory efficient data structures. + * + * @see org.graalvm.collections.EconomicMap + * @see org.graalvm.collections.EconomicSet + * + * @since 1.0 + */ +package org.graalvm.collections; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -50,6 +50,21 @@ test("branchProbabilitySnippet", 5); } + public static int branchProbabilitySnippet2(int arg) { + if (!GraalDirectives.injectBranchProbability(0.125, arg <= 0)) { + GraalDirectives.controlFlowAnchor(); // prevent removal of the if + return 2; + } else { + GraalDirectives.controlFlowAnchor(); // prevent removal of the if + return 1; + } + } + + @Test + public void testBranchProbability2() { + test("branchProbabilitySnippet2", 5); + } + @Override protected boolean checkLowTierGraph(StructuredGraph graph) { NodeIterable ifNodes = graph.getNodes(IfNode.TYPE); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java Sat Feb 10 09:25:35 2018 +0100 @@ -50,6 +50,13 @@ } /** + * Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate + * the compiled code, record a speculation and reprofile the method. + */ + public static void deoptimizeAndInvalidateWithSpeculation() { + } + + /** * Returns a boolean value indicating whether the method is executed in Graal-compiled code. */ public static boolean inCompiledCode() { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,15 +26,52 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.Array; import jdk.vm.ci.meta.Signature; /** * Denotes a method whose body is used by a compiler as the substitute (or intrinsification) of - * another method. The exact method used to do the substitution is compiler dependent but every + * another method. The exact mechanism used to do the substitution is compiler dependent but every * compiler should require substitute methods to be annotated with {@link MethodSubstitution}. In * addition, a compiler is recommended to implement {@link MethodSubstitutionRegistry} to advertise * the mechanism by which it supports registration of method substitutes. + * + * A compiler may support partial intrinsification where only a part of a method is implemented by + * the compiler. The unsupported path is expressed by a call to either the original or substitute + * method from within the substitute method. Such as call is a partial intrinsic exit. + * + * For example, here's a HotSpot specific intrinsic for {@link Array#newInstance(Class, int)} that + * only handles the case where the VM representation of the array class to be instantiated already + * exists: + * + *
+ * @MethodSubstitution
+ * public static Object newInstance(Class componentType, int length) {
+ *     if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
+ *         // Array class not yet created - exit the intrinsic and call the original method
+ *         return newInstance(componentType, length);
+ *     }
+ *     return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
+ * }
+ * 
+ * + * Here's the same intrinsification where the exit is expressed as a call to the original method: + * + *
+ * @MethodSubstitution
+ * public static Object newInstance(Class componentType, int length) {
+ *     if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
+ *         // Array class not yet created - exit the intrinsic and call the original method
+ *         return java.lang.reflect.newInstance(componentType, length);
+ *     }
+ *     return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
+ * }
+ * 
+ * + * A condition for a partial intrinsic exit is that it is uses the unmodified parameters of the + * substitute as arguments to the partial intrinsic exit call. There must also be no side effecting + * instruction between the start of the substitute method and the partial intrinsic exit. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -90,4 +90,12 @@ * if this provider cannot provide a value of the requested type */ T getInjectedNodeIntrinsicParameter(Class type); + + /** + * Get the original Java class corresponding to a {@link ResolvedJavaType}. + * + * @param type the type for which the original Java class is requested + * @return the original Java class corresponding to the {@code type} parameter + */ + Class originalClass(ResolvedJavaType type); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,9 +22,19 @@ */ package org.graalvm.compiler.api.runtime; +import jdk.vm.ci.common.JVMCIError; + public interface GraalRuntime { String getName(); T getCapability(Class clazz); + + default T getRequiredCapability(Class clazz) { + T ret = getCapability(clazz); + if (ret == null) { + throw new JVMCIError("The VM does not expose the required Graal capability %s.", clazz.getName()); + } + return ret; + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Sat Feb 10 09:25:35 2018 +0100 @@ -208,7 +208,6 @@ } private static class VexOpcode { - private static final int VEX_OPCODE_NONE = 0x0; private static final int VEX_OPCODE_0F = 0x1; private static final int VEX_OPCODE_0F_38 = 0x2; private static final int VEX_OPCODE_0F_3A = 0x3; @@ -861,9 +860,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; boolean rexVexW = (size == QWORD) ? true : false; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; @@ -881,20 +897,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } int encode; if (noNds) { encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes); @@ -938,9 +940,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; boolean rexVexW = (size == QWORD) ? true : false; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; @@ -958,20 +977,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } if (noNds) { asm.simdPrefix(dst, Register.None, src, pre, opc, attributes); } else { @@ -1055,8 +1060,7 @@ opc = VexOpcode.VEX_OPCODE_0F_3A; break; default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; + throw GraalError.shouldNotReachHere("invalid VEX instruction prefix"); } int encode; encode = asm.simdPrefixAndEncode(dst, nds, src, pre, opc, attributes); @@ -1096,8 +1100,7 @@ opc = VexOpcode.VEX_OPCODE_0F_3A; break; default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; + throw GraalError.shouldNotReachHere("invalid VEX instruction prefix"); } asm.simdPrefix(dst, nds, src, pre, opc, attributes); asm.emitByte(op); @@ -1163,9 +1166,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; boolean rexVexW = (size == QWORD) ? true : false; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; @@ -1183,20 +1203,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } int encode; if (noNds) { encode = asm.simdPrefixAndEncode(src, Register.None, dst, pre, opc, attributes); @@ -1222,9 +1228,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; boolean rexVexW = (size == QWORD) ? true : false; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; @@ -1242,20 +1265,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } asm.simdPrefix(src, Register.None, dst, pre, opc, attributes); asm.emitByte(op); asm.emitOperandHelper(src, dst, 0); @@ -1390,9 +1399,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; switch (curPrefix) { @@ -1409,20 +1435,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } int encode; if (noNds) { encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes); @@ -1453,9 +1465,26 @@ break; } + int opc = 0; + if (isSimd) { + switch (prefix2) { + case P_0F: + opc = VexOpcode.VEX_OPCODE_0F; + break; + case P_0F38: + opc = VexOpcode.VEX_OPCODE_0F_38; + break; + case P_0F3A: + opc = VexOpcode.VEX_OPCODE_0F_3A; + break; + default: + isSimd = false; + break; + } + } + if (isSimd) { int pre; - int opc; AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target); int curPrefix = size.sizePrefix | prefix1; switch (curPrefix) { @@ -1472,21 +1501,6 @@ pre = VexSimdPrefix.VEX_SIMD_NONE; break; } - switch (prefix2) { - case P_0F: - opc = VexOpcode.VEX_OPCODE_0F; - break; - case P_0F38: - opc = VexOpcode.VEX_OPCODE_0F_38; - break; - case P_0F3A: - opc = VexOpcode.VEX_OPCODE_0F_3A; - break; - default: - opc = VexOpcode.VEX_OPCODE_NONE; - break; - } - if (noNds) { asm.simdPrefix(dst, Register.None, src, pre, opc, attributes); } else { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,9 +33,9 @@ import java.util.List; import java.util.Objects; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.graph.NodeSourcePosition; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.StackSlot; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java Sat Feb 10 09:25:35 2018 +0100 @@ -40,7 +40,7 @@ public interface Patches { - void registerPatch(VMConstant c); + void registerPatch(int position, VMConstant c); } public abstract static class Data { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,7 +27,6 @@ import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.PrimitiveStamp; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; @@ -107,7 +106,9 @@ ret.setBase(add.getX()); ret.setIndex(considerNegation(graph, add.getY(), isBaseNegated)); return true; - } else if (ret.getBase() == null && ret.getIndex() instanceof AddNode) { + } + + if (ret.getBase() == null && ret.getIndex() instanceof AddNode) { AddNode add = (AddNode) ret.getIndex(); ret.setBase(considerNegation(graph, add.getX(), isIndexNegated)); ret.setIndex(add.getY()); @@ -188,7 +189,7 @@ return improveConstDisp(address, node, c, null, shift, negateExtractedDisplacement); } else { if (node.stamp(NodeView.DEFAULT) instanceof IntegerStamp) { - assert PrimitiveStamp.getBits(node.stamp(NodeView.DEFAULT)) == ADDRESS_BITS; + assert IntegerStamp.getBits(node.stamp(NodeView.DEFAULT)) == ADDRESS_BITS; /* * we can't swallow zero-extends because of multiple reasons: diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64CompressAddressLowering.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64CompressAddressLowering.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017, 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.amd64; + +import jdk.vm.ci.code.Register; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.CounterKey; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.CompressionNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +public abstract class AMD64CompressAddressLowering extends AMD64AddressLowering { + private static final CounterKey counterFoldedUncompressDuringAddressLowering = DebugContext.counter("FoldedUncompressDuringAddressLowering"); + + @Override + protected final boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) { + if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) { + return true; + } + + if (!isBaseNegated && !isIndexNegated && addr.getScale() == AMD64Address.Scale.Times1) { + ValueNode base = addr.getBase(); + ValueNode index = addr.getIndex(); + + if (tryToImproveUncompression(addr, index, base) || tryToImproveUncompression(addr, base, index)) { + counterFoldedUncompressDuringAddressLowering.increment(debug); + return true; + } + } + + return false; + } + + private boolean tryToImproveUncompression(AMD64AddressNode addr, ValueNode value, ValueNode other) { + if (value instanceof CompressionNode) { + CompressionNode compression = (CompressionNode) value; + if (compression.getOp() == CompressionNode.CompressionOp.Uncompress && improveUncompression(addr, compression, other)) { + return true; + } + } + + return false; + } + + protected abstract boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other); + + @NodeInfo(cycles = CYCLES_0, size = SIZE_0) + public static class HeapBaseNode extends FloatingNode implements LIRLowerable { + + public static final NodeClass TYPE = NodeClass.create(HeapBaseNode.class); + + private final Register heapBaseRegister; + + public HeapBaseNode(Register heapBaseRegister) { + super(TYPE, StampFactory.pointer()); + this.heapBaseRegister = heapBaseRegister; + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); + generator.setResult(this, heapBaseRegister.asValue(kind)); + } + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,14 +26,14 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction; import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove; import org.graalvm.compiler.lir.framemap.FrameMapBuilder; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Architecture; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java Sat Feb 10 09:25:35 2018 +0100 @@ -44,6 +44,7 @@ import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.gen.NodeLIRBuilder; import org.graalvm.compiler.core.gen.NodeMatchRules; @@ -128,7 +129,7 @@ } protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, LIRLowerableAccess access) { - Condition cond = compare.condition(); + Condition cond = compare.condition().asCondition(); AMD64Kind kind = getMemoryKind(access); boolean matchedAsConstant = false; // For assertion checking @@ -303,7 +304,7 @@ @MatchRule("(If (FloatEquals=compare value ValueCompareAndSwap=cas))") @MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))") public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) { - assert compare.condition() == Condition.EQ; + assert compare.condition() == CanonicalCondition.EQ; if (value == cas.getExpectedValue() && cas.usages().count() == 1) { return builder -> { LIRKind kind = getLirKind(cas); @@ -326,7 +327,7 @@ @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))") public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) { JavaConstant constant = value.asJavaConstant(); - assert compare.condition() == Condition.EQ; + assert compare.condition() == CanonicalCondition.EQ; if (constant != null && cas.usages().count() == 1) { long constantValue = constant.asLong(); boolean successIsTrue; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java Sat Feb 10 09:25:35 2018 +0100 @@ -233,6 +233,9 @@ public static final OptionKey OptScheduleOutOfLoops = new OptionKey<>(true); @Option(help = "", type = OptionType.Debug) + public static final OptionKey GuardPriorities = new OptionKey<>(true); + + @Option(help = "", type = OptionType.Debug) public static final OptionKey OptEliminateGuards = new OptionKey<>(true); @Option(help = "", type = OptionType.Debug) @@ -271,4 +274,7 @@ @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug) public static final OptionKey TraceRA = new OptionKey<>(false); + @Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug) + public static final OptionKey TraceInlining = new OptionKey<>(TraceInliningMode.None); + } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018, 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.common; + +public enum TraceInliningMode { + None(false), + Linear(true), + Tree(true); + + private final boolean tracing; + + TraceInliningMode(boolean tracing) { + this.tracing = tracing; + } + + public boolean isTracing() { + return tracing; + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,9 +22,9 @@ */ package org.graalvm.compiler.core.common.alloc; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.GraalOptions; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.Register.RegisterCategory; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/CanonicalCondition.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/CanonicalCondition.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.common.calc; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.PrimitiveConstant; + +public enum CanonicalCondition { + EQ(Condition.EQ), + LT(Condition.LT), + BT(Condition.BT); + + private final Condition condition; + + CanonicalCondition(Condition condition) { + assert condition.isCanonical(); + this.condition = condition; + } + + public Condition asCondition() { + return condition; + } + + public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { + return asCondition().foldCondition(lt, rt, constantReflection, unorderedIsTrue); + } + + public boolean foldCondition(PrimitiveConstant lp, PrimitiveConstant rp, boolean unorderedIsTrue) { + return asCondition().foldCondition(lp, rp, unorderedIsTrue); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java Sat Feb 10 09:25:35 2018 +0100 @@ -115,6 +115,55 @@ throw new IllegalArgumentException(this.toString()); } + public static final class CanonicalizedCondition { + private final CanonicalCondition canonicalCondition; + private final boolean mirror; + private final boolean negate; + + private CanonicalizedCondition(CanonicalCondition canonicalCondition, boolean mirror, boolean negate) { + this.canonicalCondition = canonicalCondition; + this.mirror = mirror; + this.negate = negate; + } + + public CanonicalCondition getCanonicalCondition() { + return canonicalCondition; + } + + public boolean mustMirror() { + return mirror; + } + + public boolean mustNegate() { + return negate; + } + } + + public CanonicalizedCondition canonicalize() { + CanonicalCondition canonicalCondition; + switch (this) { + case EQ: + case NE: + canonicalCondition = CanonicalCondition.EQ; + break; + case LT: + case LE: + case GT: + case GE: + canonicalCondition = CanonicalCondition.LT; + break; + case BT: + case BE: + case AT: + case AE: + canonicalCondition = CanonicalCondition.BT; + break; + default: + throw new IllegalArgumentException(this.toString()); + } + return new CanonicalizedCondition(canonicalCondition, canonicalMirror(), canonicalNegate()); + } + /** * Given a condition and its negation, this method returns true for one of the two and false for * the other one. This can be used to keep comparisons in a canonical form. @@ -151,7 +200,7 @@ * Returns true if the condition needs to be mirrored to get to a canonical condition. The * result of the mirroring operation might still need to be negated to achieve a canonical form. */ - public boolean canonicalMirror() { + private boolean canonicalMirror() { switch (this) { case EQ: return false; @@ -181,7 +230,7 @@ * Returns true if the condition needs to be negated to get to a canonical condition. The result * of the negation might still need to be mirrored to achieve a canonical form. */ - public boolean canonicalNegate() { + private boolean canonicalNegate() { switch (this) { case EQ: return false; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, 2018, 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.common.spi; + +import jdk.vm.ci.meta.JavaKind; + +public interface ArrayOffsetProvider { + + int arrayBaseOffset(JavaKind elementKind); + + int arrayScalingFactor(JavaKind elementKind); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java Sat Feb 10 09:25:35 2018 +0100 @@ -40,4 +40,5 @@ ConstantReflectionProvider getConstantReflection(); + ArrayOffsetProvider getArrayOffsetProvider(); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,9 @@ import java.util.Objects; import java.util.function.Function; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; + import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; @@ -51,9 +54,6 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt; import org.graalvm.util.CollectionsUtil; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaKind; - /** * Information about arithmetic operations. */ diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,8 +25,8 @@ import java.util.ArrayList; import java.util.List; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; /** * Creates an array of T objects order by the occurrence frequency of each object. The most diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java Sat Feb 10 09:25:35 2018 +0100 @@ -58,6 +58,9 @@ import javax.tools.JavaFileObject; import javax.tools.StandardLocation; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.core.match.ComplexMatchResult; import org.graalvm.compiler.core.match.MatchRule; @@ -70,9 +73,6 @@ import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.serviceprovider.ServiceProvider; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; /** * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.sparc.test; - -import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; -import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; -import static org.junit.Assume.assumeTrue; - -import org.junit.Before; -import org.junit.Test; - -import org.graalvm.compiler.core.test.backend.AllocatorTest; - -import jdk.vm.ci.sparc.SPARC; - -public class SPARCAllocatorTest extends AllocatorTest { - - @Before - public void checkSPARC() { - assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); - assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null); - assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions())); - } - - @Test - public void test1() { - testAllocation("test1snippet", 2, 0, 0); - } - - public static long test1snippet(long x) { - return x + 41; - } - - @Test - public void test2() { - testAllocation("test2snippet", 2, 0, 0); - } - - public static long test2snippet(long x) { - return x * 41; - } - - @Test - public void test3() { - testAllocation("test3snippet", 4, 0, 0); - } - - public static long test3snippet(long x) { - return x / 41 + x % 41; - } - -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,7 @@ import static jdk.vm.ci.sparc.SPARCKind.XWORD; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.core.match.ComplexMatchResult; @@ -147,7 +148,7 @@ @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))") public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) { JavaConstant constant = value.asJavaConstant(); - assert compare.condition() == Condition.EQ; + assert compare.condition() == CanonicalCondition.EQ; if (constant != null && cas.usages().count() == 1) { long constantValue = constant.asLong(); boolean successIsTrue; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java Sat Feb 10 09:25:35 2018 +0100 @@ -123,19 +123,19 @@ public static int test6Snippet(int a) { if ((a & 8) != 0) { - GraalDirectives.deoptimizeAndInvalidate(); + GraalDirectives.deoptimize(); } if ((a & 15) != 15) { - GraalDirectives.deoptimizeAndInvalidate(); + GraalDirectives.deoptimize(); } return 0; } public static int reference6Snippet(int a) { if ((a & 8) != 0) { - GraalDirectives.deoptimizeAndInvalidate(); + GraalDirectives.deoptimize(); } - GraalDirectives.deoptimizeAndInvalidate(); + GraalDirectives.deoptimize(); return 0; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Sat Feb 10 09:25:35 2018 +0100 @@ -74,7 +74,6 @@ new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context); canonicalizer.apply(graph, context); canonicalizer.apply(graph, context); - new ConvertDeoptimizeToGuardPhase().apply(graph, context); } catch (Throwable t) { debug.handle(t); } @@ -86,7 +85,6 @@ } canonicalizer.apply(referenceGraph, context); canonicalizer.apply(referenceGraph, context); - new ConvertDeoptimizeToGuardPhase().apply(graph, context); } catch (Throwable t) { debug.handle(t); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,14 +25,12 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; -import org.graalvm.compiler.nodes.NodeView; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.loop.InductionVariable; import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.FloatingNode; @@ -42,6 +40,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.junit.Test; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -117,6 +116,21 @@ test("incrementSnippet", 0, 256, 3); } + @Test + public void increment4() { + test("incrementSnippet", -10, Integer.MAX_VALUE, 1); + } + + @Test + public void increment5() { + test("incrementSnippet", 256, 256, 1); + } + + @Test + public void increment6() { + test("incrementSnippet", 257, 256, 1); + } + public static Result incrementEqSnippet(int start, int limit, int step) { int i; int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive @@ -144,6 +158,21 @@ test("incrementEqSnippet", 0, 256, 3); } + @Test + public void incrementEq4() { + test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE); + } + + @Test + public void incrementEq5() { + test("incrementEqSnippet", 256, 256, 1); + } + + @Test + public void incrementEq6() { + test("incrementEqSnippet", 257, 256, 1); + } + public static Result decrementSnippet(int start, int limit, int step) { int i; int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive @@ -198,6 +227,11 @@ test("decrementEqSnippet", 256, 0, 3); } + @Test + public void decrementEq4() { + test("decrementEqSnippet", -10, 0, Integer.MAX_VALUE); + } + public static Result twoVariablesSnippet() { Result ret = new Result(); int j = 0; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,10 +27,10 @@ import java.nio.file.Files; import java.nio.file.Path; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Test; /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -561,7 +561,7 @@ * @return a scheduled textual dump of {@code graph} . */ protected static String getScheduledGraphString(StructuredGraph graph) { - SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); schedule.apply(graph); ScheduleResult scheduleResult = graph.getLastSchedule(); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,14 +22,14 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.DebugContext.Scope; import org.graalvm.compiler.debug.DebugOptions; -import org.graalvm.compiler.debug.DebugContext.Scope; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Assert; import org.junit.Test; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,20 +24,29 @@ import java.util.List; -import org.junit.Assert; - import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeMap; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.junit.Assert; + +import jdk.vm.ci.meta.SpeculationLog; public class GraphScheduleTest extends GraalCompilerTest { protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) { - SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST); + assertOrderedAfterSchedule(graph, SchedulePhase.SchedulingStrategy.LATEST, a, b); + } + + protected void assertOrderedAfterSchedule(StructuredGraph graph, SchedulePhase.SchedulingStrategy strategy, Node a, Node b) { + SchedulePhase ibp = new SchedulePhase(strategy); ibp.apply(graph); + assertOrderedAfterLastSchedule(graph, a, b); + } + + protected void assertOrderedAfterLastSchedule(StructuredGraph graph, Node a, Node b) { assertOrderedAfterSchedule(graph.getLastSchedule(), a, b); } @@ -48,7 +57,7 @@ if (bBlock == aBlock) { List instructions = ibp.nodesFor(bBlock); - Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a)); + Assert.assertTrue(a + " should be before " + b, instructions.indexOf(b) > instructions.indexOf(a)); } else { Block block = bBlock; while (block != null) { @@ -60,4 +69,9 @@ Assert.fail("block of A doesn't dominate the block of B"); } } + + @Override + protected SpeculationLog getSpeculationLog() { + return getCodeCache().createSpeculationLog(); + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017, 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 static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; +import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeThat; +import static org.junit.Assume.assumeTrue; + +import java.util.Iterator; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.graph.iterators.NodeIterable; +import org.graalvm.compiler.nodes.GuardNode; +import org.graalvm.compiler.nodes.ParameterNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.calc.IntegerLowerThanNode; +import org.graalvm.compiler.nodes.calc.IsNullNode; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.common.LoweringPhase; +import org.graalvm.compiler.phases.schedule.SchedulePhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Test; + +public class GuardPrioritiesTest extends GraphScheduleTest { + private int[] array; + private int size; + + public void growing(int e) { + if (size >= array.length) { + // grow + GraalDirectives.deoptimizeAndInvalidateWithSpeculation(); + } + array[size++] = e; + } + + @Test + public void growingTest() { + assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions())); + StructuredGraph graph = prepareGraph("growing"); + + NodeIterable guards = graph.getNodes(GuardNode.TYPE).filter(n -> n.inputs().filter(i -> i instanceof IntegerLowerThanNode).isNotEmpty()); + assertThat(guards, isNotEmpty()); + assumeThat(guards, hasCount(2)); + + Iterator iterator = guards.iterator(); + GuardNode g1 = iterator.next(); + GuardNode g2 = iterator.next(); + assertTrue("There should be one guard with speculation, the other one without", g1.getSpeculation().isNull() ^ g2.getSpeculation().isNull()); + GuardNode withSpeculation = g1.getSpeculation().isNull() ? g2 : g1; + GuardNode withoutSpeculation = g1.getSpeculation().isNull() ? g1 : g2; + + assertOrderedAfterSchedule(graph, SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, withSpeculation, withoutSpeculation); + } + + private StructuredGraph prepareGraph(String method) { + StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES); + HighTierContext highTierContext = getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new ConvertDeoptimizeToGuardPhase().apply(graph, highTierContext); + new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext); + new FloatingReadPhase().apply(graph); + return graph; + } + + public int unknownCondition(Integer c, Object o, int[] a, Integer i) { + if (o != null) { + GraalDirectives.deoptimizeAndInvalidate(); + } + if (i > 5560) { + GraalDirectives.deoptimizeAndInvalidate(); + } + if (c >= 10) { + GraalDirectives.deoptimizeAndInvalidateWithSpeculation(); + } + return array[8] + a[i]; + } + + @Test + public void unknownTest() { + assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions())); + StructuredGraph graph = prepareGraph("unknownCondition"); + + new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER).apply(graph); + for (GuardNode g1 : graph.getNodes(GuardNode.TYPE)) { + for (GuardNode g2 : graph.getNodes(GuardNode.TYPE)) { + if (g1.getSpeculation().isNull() ^ g2.getSpeculation().isNull()) { + GuardNode withSpeculation = g1.getSpeculation().isNull() ? g2 : g1; + GuardNode withoutSpeculation = g1.getSpeculation().isNull() ? g1 : g2; + + if (withoutSpeculation.isNegated() && withoutSpeculation.getCondition() instanceof IsNullNode) { + IsNullNode isNullNode = (IsNullNode) withoutSpeculation.getCondition(); + if (isNullNode.getValue() instanceof ParameterNode && ((ParameterNode) isNullNode.getValue()).index() == 1) { + // this is the null check before the speculative guard, it's the only + // one that should be above + assertOrderedAfterLastSchedule(graph, withoutSpeculation, withSpeculation); + continue; + } + } + + assertOrderedAfterLastSchedule(graph, withSpeculation, withoutSpeculation); + } + } + } + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -44,7 +44,7 @@ public static final int N = 10000; - private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST}; + private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER}; @Test public void testLongAddChain() { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,13 +31,13 @@ import java.util.Map; import java.util.Properties; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptor; import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; /** * An implementation of {@link OptionDescriptor} that uses reflection to create descriptors from a diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java Sat Feb 10 09:25:35 2018 +0100 @@ -70,7 +70,7 @@ returnNode.replaceAtPredecessor(beginNode); beginNode.setNext(returnNode); debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph"); - SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST); + SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); schedulePhase.apply(graph); ScheduleResult schedule = graph.getLastSchedule(); BlockMap> blockToNodesMap = schedule.getBlockToNodesMap(); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, 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.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.java.BytecodeParserOptions; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Tests that the defaults for {@link GraalOptions#TrivialInliningSize} and + * {@link BytecodeParserOptions#InlineDuringParsingMaxDepth} prevent explosive graph growth for code + * with small recursive methods. + */ +public class TrivialInliningExplosionTest extends GraalCompilerTest { + + public static void trivial() { + trivial(); + trivial(); + trivial(); + } + + public static void main() { + trivial(); + trivial(); + trivial(); + trivial(); + trivial(); + trivial(); + trivial(); + trivial(); + trivial(); + } + + private int afterParseSize; + + @Override + protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) { + final StructuredGraph graph = super.parseForCompile(method, compilationId, options); + this.afterParseSize = graph.getNodeCount(); + return graph; + } + + @Test + public void test() { + ResolvedJavaMethod methodm0 = getResolvedJavaMethod("trivial"); + Assert.assertTrue(methodm0.getCodeSize() <= GraalOptions.TrivialInliningSize.getValue(getInitialOptions())); + test("main"); + int afterCompileSize = lastCompiledGraph.getNodeCount(); + + // The values of afterParseSize and afterCompileSize when this + // test was written were 849 and 848 respectively. + Assert.assertTrue(afterParseSize < 2000); + Assert.assertTrue(afterCompileSize < 2000); + + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.TTY; @@ -43,7 +44,6 @@ import org.graalvm.compiler.phases.tiers.PhaseContext; import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; -import org.graalvm.util.EconomicSet; import org.junit.Test; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,7 @@ import java.util.Collection; import java.util.List; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; import org.graalvm.compiler.core.common.GraalOptions; @@ -64,7 +65,6 @@ import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.tiers.TargetProvider; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,8 @@ import java.util.Arrays; import java.util.Queue; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; @@ -42,8 +44,6 @@ import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.virtual.nodes.MaterializedObjectState; import org.graalvm.compiler.virtual.nodes.VirtualObjectState; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.VirtualObject; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,6 +33,8 @@ import java.util.Collection; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; @@ -100,8 +102,6 @@ import org.graalvm.compiler.nodes.spi.NodeValueMap; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.StackSlot; @@ -538,7 +538,8 @@ public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { PlatformKind kind = gen.getLIRKind(compare.getX().stamp(NodeView.DEFAULT)).getPlatformKind(); - gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability); + gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition().asCondition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, + trueSuccessorProbability); } public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) { @@ -566,7 +567,7 @@ } else if (node instanceof CompareNode) { CompareNode compare = (CompareNode) node; PlatformKind kind = gen.getLIRKind(compare.getX().stamp(NodeView.DEFAULT)).getPlatformKind(); - return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue); + return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition().asCondition(), compare.unorderedIsTrue(), trueValue, falseValue); } else if (node instanceof LogicConstantNode) { return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue); } else if (node instanceof IntegerTestNode) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,8 @@ import java.util.Arrays; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.gen.NodeLIRBuilder; import org.graalvm.compiler.core.match.MatchPattern.Result; import org.graalvm.compiler.debug.DebugContext; @@ -35,8 +37,6 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; /** * Container for state captured during a match. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,9 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.gen.NodeMatchRules; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; @@ -36,9 +39,6 @@ import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.serviceprovider.GraalServices; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; public class MatchRuleRegistry { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.core.phases; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph.NodeEvent; import org.graalvm.compiler.graph.Graph.NodeEventScope; @@ -32,8 +34,6 @@ import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; /** * A utility phase for detecting when a phase would change the graph and reporting extra information diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import java.util.ArrayList; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; @@ -44,7 +45,6 @@ import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.phases.tiers.TargetProvider; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.CodeCacheProvider; @@ -204,31 +204,48 @@ } try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext); DebugContext.Activation a = debug.activate()) { - for (CodeInstallationTask task : tasks) { - task.preProcess(compilationResult); + preCodeInstallationTasks(tasks, compilationResult); + + InstalledCode installedCode; + try { + CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); + installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); + } catch (Throwable t) { + failCodeInstallationTasks(tasks, t); + throw t; } - CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); - InstalledCode installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); + postCodeInstallationTasks(tasks, installedCode); - // Run post-code installation tasks. - try { - for (CodeInstallationTask task : tasks) { - task.postProcess(installedCode); - } - for (CodeInstallationTask task : tasks) { - task.releaseInstallation(installedCode); - } - } catch (Throwable t) { - installedCode.invalidate(); - throw t; - } return installedCode; } catch (Throwable e) { throw debug.handle(e); } } + private static void failCodeInstallationTasks(CodeInstallationTask[] tasks, Throwable t) { + for (CodeInstallationTask task : tasks) { + task.installFailed(t); + } + } + + private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult) { + for (CodeInstallationTask task : tasks) { + task.preProcess(compilationResult); + } + } + + private static void postCodeInstallationTasks(CodeInstallationTask[] tasks, InstalledCode installedCode) { + try { + for (CodeInstallationTask task : tasks) { + task.postProcess(installedCode); + } + } catch (Throwable t) { + installedCode.invalidate(); + throw t; + } + } + /** * Installs code based on a given compilation result. * @@ -301,11 +318,10 @@ } /** - * Task to run after all the post-code installation tasks are complete, used to release the - * installed code. + * Invoked after {@link #preProcess} when code installation fails. */ @SuppressWarnings("unused") - public void releaseInstallation(InstalledCode installedCode) { + public void installFailed(Throwable t) { } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,7 @@ import java.util.Formatter; import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.Assertions; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; @@ -46,7 +47,6 @@ import org.graalvm.compiler.debug.DebugVerifyHandler; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ import java.lang.management.ThreadMXBean; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugOptions; @@ -37,7 +38,6 @@ import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Assume; import org.junit.Before; import org.junit.Test; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.debug; -import org.graalvm.util.Pair; +import org.graalvm.collections.Pair; class CounterKeyImpl extends AbstractKey implements CounterKey { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Sat Feb 10 09:25:35 2018 +0100 @@ -56,12 +56,12 @@ import java.util.SortedMap; import java.util.TreeMap; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Pair; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.graphio.GraphOutput; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Pair; import jdk.vm.ci.meta.JavaMethod; @@ -1937,10 +1937,17 @@ if (description != null) { printMetrics(description); } - if (metricsEnabled && globalMetrics != null && metricValues != null) { + if (metricsEnabled && metricValues != null && globalMetrics != null) { globalMetrics.add(this); } metricValues = null; + if (sharedChannel != null) { + try { + sharedChannel.realClose(); + } catch (IOException ex) { + // ignore. + } + } } public void closeDumpHandlers(boolean ignoreErrors) { @@ -2022,7 +2029,6 @@ } } } - } /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,11 +27,11 @@ import java.nio.file.Path; import java.nio.file.Paths; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; /** * Options that configure a {@link DebugContext} and related functionality. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,10 +29,10 @@ import java.util.Collections; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.Pair; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; -import org.graalvm.util.Pair; /** * Metric values that can be {@linkplain #add(DebugContext) updated} by multiple threads. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,7 +25,7 @@ import java.util.ArrayList; import java.util.List; -import org.graalvm.util.EconomicMap; +import org.graalvm.collections.EconomicMap; /** * Registry for allocating a globally unique integer id to each {@link AbstractKey}. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE; -import org.graalvm.util.Pair; +import org.graalvm.collections.Pair; class MemUseTrackerKeyImpl extends AccumulatedKey implements MemUseTrackerKey { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import java.util.Comparator; -import org.graalvm.util.Pair; +import org.graalvm.collections.Pair; /** * A key for a metric. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit; -import org.graalvm.util.Pair; +import org.graalvm.collections.Pair; final class TimerKeyImpl extends AccumulatedKey implements TimerKey { static class FlatTimer extends AbstractKey implements TimerKey { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import java.util.function.Consumer; -import org.graalvm.util.UnmodifiableEconomicMap; +import org.graalvm.collections.UnmodifiableEconomicMap; /** * This class is a container of a graph that needs to be readonly and optionally a lazily created diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,9 @@ import java.util.Iterator; import java.util.function.Consumer; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; @@ -41,9 +44,6 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; /** * This class is a graph container, it contains the set of nodes that belong to this graph. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Sat Feb 10 09:25:35 2018 +0100 @@ -160,6 +160,12 @@ } } + public void invert() { + for (int i = 0; i < bits.length; i++) { + bits[i] = ~bits[i]; + } + } + public void grow() { nodeCount = Math.max(nodeCount, graph().nodeIdCount()); int newLength = sizeForNodeCount(nodeCount); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Sat Feb 10 09:25:35 2018 +0100 @@ -42,6 +42,8 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.FieldIntrospection; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.FieldsScanner; @@ -65,8 +67,6 @@ import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.NodeSize; import org.graalvm.compiler.nodeinfo.Verbosity; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; /** * Metadata for every {@link Node} type. The metadata includes: diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,8 @@ import java.util.Iterator; import java.util.function.BiFunction; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; public class NodeMap extends NodeIdAccessor implements EconomicMap { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java Sat Feb 10 09:25:35 2018 +0100 @@ -74,6 +74,10 @@ return tos == 0; } + public void clear() { + tos = 0; + } + @Override public String toString() { if (tos == 0) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.hotspot.aarch64; -import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; import static java.lang.reflect.Modifier.isStatic; import static jdk.vm.ci.aarch64.AArch64.lr; import static jdk.vm.ci.aarch64.AArch64.r10; @@ -30,7 +29,9 @@ import static jdk.vm.ci.aarch64.AArch64.zr; import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp; +import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; @@ -42,11 +43,11 @@ import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotDataBuilder; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotHostBackend; import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.stubs.Stub; @@ -64,7 +65,6 @@ import org.graalvm.compiler.lir.gen.LIRGeneratorTool; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java Sat Feb 10 09:25:35 2018 +0100 @@ -49,6 +49,7 @@ import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.util.Providers; @@ -136,7 +137,7 @@ replacements = createReplacements(graalRuntime.getOptions(), p, snippetReflection, bytecodeProvider); } try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { - plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); + plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); replacements.setGraphBuilderPlugins(plugins); } try (InitTimer rt = timer("create Suites provider")) { @@ -152,9 +153,10 @@ } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, - HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, - HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, + HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, + replacements); AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider()); return plugins; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ArrayAccessInLoopToAddressTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ArrayAccessInLoopToAddressTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018, 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.amd64.test; + +import jdk.vm.ci.hotspot.HotSpotSpeculationLog; +import jdk.vm.ci.meta.SpeculationLog; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; + +public class ArrayAccessInLoopToAddressTest extends GraalCompilerTest { + + public static int positiveInductionVariable(short[] array) { + int sum = 0; + for (int i = 0; i < array.length - 1; i++) { + sum += array[i + 1]; + } + return sum; + } + + @Test + public void testPositiveInductionVariable() { + test("positiveInductionVariable", new short[]{1, 3, 7, 9}); + } + + public static int negativeInductionVariable(short[] array) { + int sum = 0; + for (int i = -array.length; i < array.length - 4; i++) { + sum += array[i + 4]; + } + return sum; + } + + @Test + public void testNegativeInductionVariable() { + test("negativeInductionVariable", new short[]{1, 3, 7, 9}); + } + + @Override + protected SpeculationLog getSpeculationLog() { + return new HotSpotSpeculationLog(); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,64 +24,50 @@ package org.graalvm.compiler.hotspot.amd64; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; -import org.graalvm.compiler.core.amd64.AMD64AddressLowering; import org.graalvm.compiler.core.amd64.AMD64AddressNode; +import org.graalvm.compiler.core.amd64.AMD64CompressAddressLowering; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.debug.CounterKey; -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; -import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.loop.BasicInductionVariable; +import org.graalvm.compiler.loop.CountedLoopInfo; +import org.graalvm.compiler.loop.DerivedInductionVariable; +import org.graalvm.compiler.loop.InductionVariable; +import org.graalvm.compiler.loop.LoopEx; +import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.nodes.CompressionNode; -import org.graalvm.compiler.nodes.CompressionNode.CompressionOp; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.SignExtendNode; +import org.graalvm.compiler.nodes.calc.ZeroExtendNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; +import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.JavaKind; -public class AMD64HotSpotAddressLowering extends AMD64AddressLowering { +public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering { - private static final CounterKey counterFoldedUncompressDuringAddressLowering = DebugContext.counter("FoldedUncompressDuringAddressLowering"); + private static final int ADDRESS_BITS = 64; + private static final int INT_BITS = 32; private final long heapBase; private final Register heapBaseRegister; private final GraalHotSpotVMConfig config; private final boolean generatePIC; - @NodeInfo(cycles = CYCLES_0, size = SIZE_0) - public static class HeapBaseNode extends FloatingNode implements LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(HeapBaseNode.class); - - private final Register heapBaseRegister; - - public HeapBaseNode(Register heapBaseRegister) { - super(TYPE, StampFactory.pointer()); - this.heapBaseRegister = heapBaseRegister; - } - - @Override - public void generate(NodeLIRBuilderTool generator) { - LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT)); - generator.setResult(this, heapBaseRegister.asValue(kind)); - } - } - public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister, OptionValues options) { this.heapBase = config.getOopEncoding().getBase(); this.config = config; @@ -94,35 +80,7 @@ } @Override - protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) { - if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) { - return true; - } - - if (addr.getScale() == Scale.Times1) { - if (addr.getIndex() instanceof CompressionNode) { - if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase(), isBaseNegated, isIndexNegated)) { - counterFoldedUncompressDuringAddressLowering.increment(debug); - return true; - } - } - - if (addr.getBase() instanceof CompressionNode) { - if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex(), isBaseNegated, isIndexNegated)) { - counterFoldedUncompressDuringAddressLowering.increment(debug); - return true; - } - } - } - - return false; - } - - private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other, boolean isBaseNegated, boolean isIndexNegated) { - if (isBaseNegated || isIndexNegated || compression.getOp() != CompressionOp.Uncompress) { - return false; - } - + protected final boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other) { CompressEncoding encoding = compression.getEncoding(); Scale scale = Scale.fromShift(encoding.getShift()); if (scale == null) { @@ -147,7 +105,7 @@ return false; } } else { - if (updateDisplacement(addr, encoding.getBase(), isBaseNegated)) { + if (updateDisplacement(addr, encoding.getBase(), false)) { addr.setBase(other); } else { return false; @@ -161,4 +119,117 @@ addr.setIndex(compression.getValue()); return true; } + + @Override + public void preProcess(StructuredGraph graph) { + if (graph.hasLoops()) { + LoopsData loopsData = new LoopsData(graph); + loopsData.detectedCountedLoops(); + for (LoopEx loop : loopsData.countedLoops()) { + for (OffsetAddressNode offsetAdressNode : loop.whole().nodes().filter(OffsetAddressNode.class)) { + tryOptimize(offsetAdressNode, loop); + } + } + } + } + + @Override + public void postProcess(AddressNode lowered) { + // Allow implicit zero extend for always positive input. This + // assumes that the upper bits of the operand is zero out by + // the backend. + AMD64AddressNode address = (AMD64AddressNode) lowered; + address.setBase(tryImplicitZeroExtend(address.getBase())); + address.setIndex(tryImplicitZeroExtend(address.getIndex())); + } + + private static void tryOptimize(OffsetAddressNode offsetAddress, LoopEx loop) { + EconomicMap ivs = loop.getInductionVariables(); + InductionVariable currentIV = ivs.get(offsetAddress.getOffset()); + while (currentIV != null) { + if (!(currentIV instanceof DerivedInductionVariable)) { + break; + } + ValueNode currentValue = currentIV.valueNode(); + if (currentValue.isDeleted()) { + break; + } + + if (currentValue instanceof ZeroExtendNode) { + ZeroExtendNode zeroExtendNode = (ZeroExtendNode) currentValue; + if (applicableToImplicitZeroExtend(zeroExtendNode)) { + ValueNode input = zeroExtendNode.getValue(); + if (input instanceof AddNode) { + AddNode add = (AddNode) input; + if (add.getX().isConstant()) { + optimizeAdd(zeroExtendNode, (ConstantNode) add.getX(), add.getY(), loop); + } else if (add.getY().isConstant()) { + optimizeAdd(zeroExtendNode, (ConstantNode) add.getY(), add.getX(), loop); + } + } + } + } + + currentIV = ((DerivedInductionVariable) currentIV).getBase(); + } + } + + /** + * Given that Add(a, cst) is always positive, performs the following: ZeroExtend(Add(a, cst)) -> + * Add(SignExtend(a), SignExtend(cst)). + */ + private static void optimizeAdd(ZeroExtendNode zeroExtendNode, ConstantNode constant, ValueNode other, LoopEx loop) { + StructuredGraph graph = zeroExtendNode.graph(); + AddNode addNode = graph.unique(new AddNode(signExtend(other, loop), ConstantNode.forLong(constant.asJavaConstant().asInt(), graph))); + zeroExtendNode.replaceAtUsages(addNode); + } + + /** + * Create a sign extend for {@code input}, or zero extend if {@code input} can be proven + * positive. + */ + private static ValueNode signExtend(ValueNode input, LoopEx loop) { + StructuredGraph graph = input.graph(); + if (input instanceof PhiNode) { + EconomicMap ivs = loop.getInductionVariables(); + InductionVariable inductionVariable = ivs.get(input); + if (inductionVariable != null && inductionVariable instanceof BasicInductionVariable) { + CountedLoopInfo countedLoopInfo = loop.counted(); + IntegerStamp initStamp = (IntegerStamp) inductionVariable.initNode().stamp(NodeView.DEFAULT); + if (initStamp.isPositive()) { + if (inductionVariable.isConstantExtremum()) { + long init = inductionVariable.constantInit(); + long stride = inductionVariable.constantStride(); + long extremum = inductionVariable.constantExtremum(); + + if (init >= 0 && extremum >= 0) { + long shortestTrip = (extremum - init) / stride + 1; + if (shortestTrip == countedLoopInfo.constantMaxTripCount()) { + return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true)); + } + } + } + if (countedLoopInfo.getCounter() == inductionVariable && inductionVariable.direction() == InductionVariable.Direction.Up && countedLoopInfo.getOverFlowGuard() != null) { + return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true)); + } + } + } + } + return input.graph().maybeAddOrUnique(SignExtendNode.create(input, ADDRESS_BITS, NodeView.DEFAULT)); + } + + private static boolean applicableToImplicitZeroExtend(ZeroExtendNode zeroExtendNode) { + return zeroExtendNode.isInputAlwaysPositive() && zeroExtendNode.getInputBits() == INT_BITS && zeroExtendNode.getResultBits() == ADDRESS_BITS; + } + + private static ValueNode tryImplicitZeroExtend(ValueNode input) { + if (input instanceof ZeroExtendNode) { + ZeroExtendNode zeroExtendNode = (ZeroExtendNode) input; + if (applicableToImplicitZeroExtend(zeroExtendNode)) { + return zeroExtendNode.getValue(); + } + } + return input; + } + } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; @@ -66,7 +67,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64Kind; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java Sat Feb 10 09:25:35 2018 +0100 @@ -49,6 +49,7 @@ import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; +import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; @@ -137,7 +138,7 @@ replacements = createReplacements(options, p, snippetReflection, bytecodeProvider); } try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { - plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, + plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); replacements.setGraphBuilderPlugins(plugins); } @@ -154,9 +155,10 @@ } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, OptionValues options, TargetDescription target, - HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, + HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, + replacements); AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue(options)); return plugins; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Sat Feb 10 09:25:35 2018 +0100 @@ -572,7 +572,7 @@ if (inputKind.isReference(0)) { // oop Variable result = newVariable(lirKindTool.getNarrowOopKind()); - append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool())); + append(new AMD64Move.CompressPointerOp(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool())); return result; } else { // metaspace pointer @@ -589,7 +589,7 @@ base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase())); } } - append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool())); + append(new AMD64Move.CompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool())); return result; } } @@ -602,7 +602,7 @@ if (inputKind.isReference(0)) { // oop Variable result = newVariable(lirKindTool.getObjectKind()); - append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool)); + append(new AMD64Move.UncompressPointerOp(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool)); return result; } else { // metaspace pointer @@ -620,7 +620,7 @@ base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase())); } } - append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool)); + append(new AMD64Move.UncompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool)); return result; } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -67,7 +67,8 @@ public void initialize(OptionValues options, Iterable factories, HotSpotProviders providers, GraalHotSpotVMConfig config) { convertSnippets = new AMD64ConvertSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget()); profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue(options) - ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget()) : null; + ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget()) + : null; super.initialize(options, factories, providers, config); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -60,6 +60,7 @@ crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); // This must be emitted exactly like this to ensure it's patchable masm.movq(AMD64.rax, config.nonOopBits); - super.emitCode(crb, masm); + int offset = super.emitCall(crb, masm); + crb.recordInvokeVirtualOrInterfaceCallOp(offset, getPosition()); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -70,7 +70,8 @@ crb.recordMark(config.MARKID_INLINE_INVOKE); Register callReg = asRegister(targetAddress); assert !callReg.equals(METHOD); - AMD64Call.indirectCall(crb, masm, callReg, callTarget, state); + int pcOffset = AMD64Call.indirectCall(crb, masm, callReg, callTarget, state); + crb.recordInlineInvokeCallOp(pcOffset, getPosition()); } @Override diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, 2018, 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.sparc.test; + +import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; +import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; +import static org.junit.Assume.assumeTrue; + +import org.graalvm.compiler.core.test.backend.AllocatorTest; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.sparc.SPARC; + +public class SPARCAllocatorTest extends AllocatorTest { + + private final GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig(); + + @Before + public void checkSPARC() { + assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); + assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null); + assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions())); + } + + @Test + public void test1() { + testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); + } + + public static long test1snippet(long x) { + return x + 41; + } + + @Test + public void test2() { + testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); + } + + public static long test2snippet(long x) { + return x * 41; + } + + @Test + public void test3() { + testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0); + } + + public static long test3snippet(long x) { + return x / 41 + x % 41; + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java Sat Feb 10 09:25:35 2018 +0100 @@ -46,6 +46,9 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.sparc.SPARCAddress; @@ -92,9 +95,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.Register; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java Sat Feb 10 09:25:35 2018 +0100 @@ -101,7 +101,7 @@ HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(runtime.getOptions(), p, snippetReflection, bytecodeProvider, target); - Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes); + Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, lowerer, stampProvider, snippetReflection, replacements, wordTypes); replacements.setGraphBuilderPlugins(plugins); HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements); HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers, @@ -112,9 +112,10 @@ } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess, - HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider, + HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotStampProvider stampProvider, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements); + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, + replacements); SPARCGraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider()); return plugins; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayNewInstanceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayNewInstanceTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017, 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.test; + +import java.lang.reflect.Array; +import java.util.ArrayList; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(Parameterized.class) +public class ArrayNewInstanceTest extends GraalCompilerTest { + + @Parameters(name = "{index}: class {0} length {1}") + public static Iterable data() { + ArrayList parameters = new ArrayList<>(); + Class[] classesToTest = new Class[]{ + byte.class, + boolean.class, + short.class, + char.class, + int.class, + long.class, + Void.class, + ArrayNewInstanceTest.class + }; + for (Class clazz : classesToTest) { + // Negative sizes always deopt + parameters.add(new Object[]{clazz, -1, true}); + parameters.add(new Object[]{clazz, 0, false}); + parameters.add(new Object[]{clazz, 42, false}); + } + // The void type always throws an exception where graal deopts + parameters.add(new Object[]{void.class, -1, true}); + parameters.add(new Object[]{void.class, 0, true}); + parameters.add(new Object[]{void.class, 42, true}); + return parameters; + } + + private final Class type; + private final int length; + private final boolean shouldDeopt; + private final DeoptimizationBox box = new DeoptimizationBox(); + + public ArrayNewInstanceTest(Class type, int length, boolean shouldDeopt) { + super(); + this.type = type; + this.length = length; + this.shouldDeopt = shouldDeopt; + } + + public static Object newArray(Class klass, int length, DeoptimizationBox box) { + Object result = Array.newInstance(klass, length); + box.inCompiledCode = GraalDirectives.inCompiledCode(); + return result; + } + + @Test + public void testNewArray() { + test("newArray", type, length, box); + assertTrue(box.inCompiledCode != shouldDeopt); + } + + public static Object newArrayInLoop(Class klass, int length, int iterations, DeoptimizationBox box) { + Object o = null; + for (int i = 0; i < iterations; i++) { + o = Array.newInstance(klass, length); + } + box.inCompiledCode = GraalDirectives.inCompiledCode(); + return o; + } + + @Test + public void testNewArrayInLoop() { + test("newArrayInLoop", type, length, 2, box); + assertTrue(box.inCompiledCode != shouldDeopt); + } + + private static class DeoptimizationBox { + volatile boolean inCompiledCode = false; + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Sat Feb 10 09:25:35 2018 +0100 @@ -32,6 +32,8 @@ import java.util.TreeSet; import java.util.stream.Collectors; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; @@ -43,8 +45,6 @@ import org.graalvm.compiler.runtime.RuntimeProvider; import org.graalvm.compiler.serviceprovider.JDK9Method; import org.graalvm.compiler.test.GraalTest; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; import org.junit.Test; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; @@ -416,6 +416,12 @@ "java/lang/StringUTF16.toBytes([CII)[B"); } + if (isJDK10OrHigher()) { + add(TO_BE_INVESTIGATED, + "java/lang/Math.multiplyHigh(JJ)J", + "jdk/internal/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I"); + } + if (!getHostArchitectureName().equals("amd64")) { // Can we implement these on non-AMD64 platforms? C2 seems to. add(TO_BE_INVESTIGATED, @@ -539,6 +545,10 @@ return JDK9Method.JAVA_SPECIFICATION_VERSION >= 9; } + private static boolean isJDK10OrHigher() { + return JDK9Method.JAVA_SPECIFICATION_VERSION >= 10; + } + private static String getHostArchitectureName() { String arch = System.getProperty("os.arch"); if (arch.equals("x86_64")) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java Sat Feb 10 09:25:35 2018 +0100 @@ -68,6 +68,8 @@ import java.util.jar.JarFile; import java.util.stream.Collectors; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.bytecode.Bytecodes; import org.graalvm.compiler.core.CompilerThreadFactory; @@ -85,8 +87,6 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.serviceprovider.JDK9Method; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.UnmodifiableEconomicMap; import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotCompilationRequest; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,12 +25,12 @@ import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationBailoutAction; import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureAction; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Test; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -32,6 +32,7 @@ import java.util.HashSet; import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.phases.HighTier; import org.graalvm.compiler.debug.DebugContext; @@ -40,13 +41,12 @@ import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; import org.junit.Assert; +import org.junit.Assume; +import org.junit.BeforeClass; import org.junit.Test; import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.junit.Assume; -import org.junit.BeforeClass; /** * Test on-stack-replacement with locks. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,8 +31,8 @@ import java.lang.management.ManagementFactory; import java.lang.reflect.Field; +import java.util.Arrays; -import java.util.Arrays; import javax.management.Attribute; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; @@ -41,11 +41,11 @@ import javax.management.ObjectInstance; import javax.management.ObjectName; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugOptions; import org.graalvm.compiler.hotspot.HotSpotGraalMBean; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.test.GraalTest; -import org.graalvm.util.EconomicMap; import org.junit.Assume; import org.junit.Test; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,8 +23,10 @@ package org.graalvm.compiler.hotspot.test; import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; + import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; @@ -36,10 +38,9 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Binding; +import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; import org.graalvm.compiler.runtime.RuntimeProvider; -import org.graalvm.util.EconomicMap; import org.junit.Test; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Scope; @@ -58,7 +59,6 @@ import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.MidTierContext; -import org.graalvm.util.EconomicMap; import org.graalvm.word.LocationIdentity; import org.junit.Assert; import org.junit.Test; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,7 @@ import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.CompilationPrinter; @@ -45,7 +46,6 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.CodeCacheProvider; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,7 @@ import java.util.List; import java.util.stream.Collectors; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionKey; @@ -36,7 +37,6 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.serviceprovider.GraalServices; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.common.InitTimer; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Sat Feb 10 09:25:35 2018 +0100 @@ -64,10 +64,10 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.word.Word; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.word.Pointer; import jdk.vm.ci.code.CompilationRequest; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -98,8 +98,8 @@ ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder()); Builder patchBuilder = Stream.builder(); - data.buildDataSection(buffer, vmConstant -> { - patchBuilder.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant))); + data.buildDataSection(buffer, (position, vmConstant) -> { + patchBuilder.accept(new DataPatch(position, new ConstantReference(vmConstant))); }); int dataSectionAlignment = data.getSectionAlignment(); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,11 +22,13 @@ */ package org.graalvm.compiler.hotspot; +import static jdk.vm.ci.code.ValueUtil.isRegister; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static jdk.vm.ci.code.ValueUtil.isRegister; import java.util.Arrays; + +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.GraalError; @@ -34,7 +36,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -56,41 +56,30 @@ @Override public Data createDataItem(Constant constant) { - int size; - if (constant instanceof VMConstant) { + if (JavaConstant.isNull(constant)) { + boolean compressed = COMPRESSED_NULL.equals(constant); + int size = compressed ? 4 : target.wordSize; + return ZeroData.create(size, size); + } else if (constant instanceof VMConstant) { VMConstant vmConstant = (VMConstant) constant; - boolean compressed; - if (constant instanceof HotSpotConstant) { - HotSpotConstant c = (HotSpotConstant) vmConstant; - compressed = c.isCompressed(); - } else { + if (!(constant instanceof HotSpotConstant)) { throw new GraalError(String.valueOf(constant)); } - size = compressed ? 4 : target.wordSize; - if (size == 4) { - return new Data(size, size) { - - @Override - protected void emit(ByteBuffer buffer, Patches patches) { - patches.registerPatch(vmConstant); + HotSpotConstant c = (HotSpotConstant) vmConstant; + int size = c.isCompressed() ? 4 : target.wordSize; + return new Data(size, size) { + @Override + protected void emit(ByteBuffer buffer, Patches patches) { + int position = buffer.position(); + if (getSize() == Integer.BYTES) { buffer.putInt(0xDEADDEAD); - } - }; - } else { - return new Data(size, size) { - - @Override - protected void emit(ByteBuffer buffer, Patches patches) { - patches.registerPatch(vmConstant); + } else { buffer.putLong(0xDEADDEADDEADDEADL); } - }; - } - } else if (JavaConstant.isNull(constant)) { - boolean compressed = COMPRESSED_NULL.equals(constant); - size = compressed ? 4 : target.wordSize; - return ZeroData.create(size, size); + patches.registerPatch(position, vmConstant); + } + }; } else if (constant instanceof SerializableConstant) { SerializableConstant s = (SerializableConstant) constant; return new SerializableData(s); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,15 +22,15 @@ */ package org.graalvm.compiler.hotspot; +import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS; -import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.util.EconomicSet; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.CallingConvention; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java Sat Feb 10 09:25:35 2018 +0100 @@ -44,10 +44,10 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.options.OptionsParser; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; public final class HotSpotGraalMBean implements javax.management.DynamicMBean { private static Object mBeanServerField; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Properties; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionDescriptors; import org.graalvm.compiler.options.OptionKey; @@ -37,7 +38,6 @@ import org.graalvm.compiler.options.OptionValuesAccess; import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.serviceprovider.ServiceProvider; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.common.InitTimer; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,8 @@ import java.util.List; import java.util.Map; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalRuntime; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; @@ -57,8 +59,6 @@ import org.graalvm.compiler.replacements.SnippetCounter; import org.graalvm.compiler.replacements.SnippetCounter.Group; import org.graalvm.compiler.runtime.RuntimeProvider; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.stack.StackIntrospection; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.hotspot; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.hotspot.stubs.Stub; import org.graalvm.compiler.lir.LIR; @@ -29,8 +31,6 @@ import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; import org.graalvm.compiler.lir.framemap.FrameMapBuilder; import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.code.StackSlot; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; @@ -42,7 +43,6 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.util.EconomicMap; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.CallingConvention; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,6 +31,7 @@ import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MutableCallSite; import java.lang.invoke.VolatileCallSite; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.math.BigInteger; @@ -39,17 +40,20 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; +import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode; import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; +import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions; import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions; -import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions; import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode; import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode; +import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions; import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions; import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode; import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode; @@ -68,7 +72,6 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.IntegerConvertNode; @@ -83,8 +86,10 @@ import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory; import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; +import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; +import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.StampProvider; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; @@ -123,12 +128,12 @@ * @param stampProvider */ public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, - ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, - ReplacementsImpl replacements) { + ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, LoweringProvider lowerer, + StampProvider stampProvider, ReplacementsImpl replacements) { InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration); Plugins plugins = new Plugins(invocationPlugins); - NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes); + NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, lowerer, wordTypes); HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes); HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin); @@ -171,6 +176,7 @@ registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider); registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider); StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true); + registerArrayPlugins(invocationPlugins, replacementBytecodeProvider); for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) { factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider); @@ -401,19 +407,23 @@ }); } + private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { + Registration r = new Registration(plugins, Array.class, bytecodeProvider); + r.setAllowOverwrite(true); + r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class); + } + private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) { Registration r = new Registration(plugins, Thread.class, bytecodeProvider); r.register0("currentThread", new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind())); - boolean compressible = false; ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset)); AddressNode address = b.add(new OffsetAddressNode(thread, offset)); - ValueNode javaThread = WordOperationPlugin.readOp(b, JavaKind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible); - boolean exactType = false; - boolean nonNull = true; - b.addPush(JavaKind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull)); + // JavaThread::_threadObj is never compressed + ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class))); + b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE)); return true; } }); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -101,6 +101,7 @@ import java.util.EnumMap; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.debug.GraalError; @@ -123,7 +124,6 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordTypes; -import org.graalvm.util.EconomicMap; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.CodeCacheProvider; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,7 @@ import java.lang.reflect.Type; import java.util.Set; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -42,7 +43,6 @@ import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.replacements.nodes.MacroNode; import org.graalvm.compiler.serviceprovider.JDK9Method; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; import jdk.vm.ci.meta.JavaKind; @@ -122,7 +122,7 @@ * of its module dependencies are trusted. */ @Override - protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) { + public boolean canBeIntrinsified(ResolvedJavaType declaringClass) { if (declaringClass instanceof HotSpotResolvedJavaType) { Class javaClass = ((HotSpotResolvedJavaType) declaringClass).mirror(); if (Java8OrEarlier) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.hotspot.meta; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; @@ -104,4 +105,9 @@ } return null; } + + @Override + public Class originalClass(ResolvedJavaType type) { + return ((HotSpotResolvedJavaType) type).mirror(); + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,34 +23,37 @@ package org.graalvm.compiler.hotspot.nodes; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; @NodeInfo public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable { public static final NodeClass TYPE = NodeClass.create(ArrayRangeWriteBarrier.class); - @Input ValueNode object; - @Input ValueNode startIndex; + @Input(InputType.Association) AddressNode address; @Input ValueNode length; - protected ArrayRangeWriteBarrier(NodeClass c, ValueNode object, ValueNode startIndex, ValueNode length) { + private final int elementStride; + + protected ArrayRangeWriteBarrier(NodeClass c, AddressNode address, ValueNode length, int elementStride) { super(c); - this.object = object; - this.startIndex = startIndex; + this.address = address; this.length = length; + this.elementStride = elementStride; } - public ValueNode getObject() { - return object; - } - - public ValueNode getStartIndex() { - return startIndex; + public AddressNode getAddress() { + return address; } public ValueNode getLength() { return length; } + + public int getElementStride() { + return elementStride; + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,13 +28,14 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; @NodeInfo(cycles = CYCLES_64, size = SIZE_64) public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier { public static final NodeClass TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class); - public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { - super(TYPE, object, startIndex, length); + public G1ArrayRangePostWriteBarrier(AddressNode address, ValueNode length, int elementStride) { + super(TYPE, address, length, elementStride); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,13 +28,14 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; @NodeInfo(cycles = CYCLES_64, size = SIZE_64) public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier { public static final NodeClass TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class); - public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { - super(TYPE, object, startIndex, length); + public G1ArrayRangePreWriteBarrier(AddressNode address, ValueNode length, int elementStride) { + super(TYPE, address, length, elementStride); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,14 +28,14 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; @NodeInfo(cycles = CYCLES_8, size = SIZE_8) public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier { - public static final NodeClass TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class); - public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) { - super(TYPE, object, startIndex, length); + public SerialArrayRangeWriteBarrier(AddressNode address, ValueNode length, int elementStride) { + super(TYPE, address, length, elementStride); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,7 +34,7 @@ import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +import org.graalvm.compiler.nodes.extended.ArrayRangeWrite; import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode; import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode; import org.graalvm.compiler.nodes.memory.FixedAccessNode; @@ -65,9 +65,9 @@ addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph); } else if (n instanceof AbstractCompareAndSwapNode) { addCASBarriers((AbstractCompareAndSwapNode) n, graph); - } else if (n instanceof ArrayRangeWriteNode) { - ArrayRangeWriteNode node = (ArrayRangeWriteNode) n; - if (node.isObjectArray()) { + } else if (n instanceof ArrayRangeWrite) { + ArrayRangeWrite node = (ArrayRangeWrite) n; + if (node.writesObjectArray()) { addArrayRangeBarriers(node, graph); } } @@ -171,17 +171,17 @@ } } - private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) { + private void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) { if (config.useG1GC) { - if (!node.isInitialization()) { - G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); - graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier); + if (!write.isInitialization()) { + G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride())); + graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier); } - G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); - graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier); + G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride())); + graph.addAfterFixed(write.asNode(), g1ArrayRangePostWriteBarrier); } else { - SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength())); - graph.addAfterFixed(node, serialArrayRangeWriteBarrier); + SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride())); + graph.addAfterFixed(write.asNode(), serialArrayRangeWriteBarrier); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -39,7 +39,7 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode; +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.memory.FixedAccessNode; @@ -122,7 +122,7 @@ private boolean hasAttachedBarrier(FixedWithNextNode node) { final Node next = node.next(); final Node previous = node.predecessor(); - boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization()); + boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization()); if (node instanceof WriteNode) { WriteNode writeNode = (WriteNode) node; if (writeNode.getLocationIdentity().isInit()) { @@ -143,7 +143,7 @@ } private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) { - return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject(); + return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWrite) node).getAddress() == ((ArrayRangeWriteBarrier) next).getAddress(); } private static boolean isObjectWrite(Node node) { @@ -152,7 +152,7 @@ } private static boolean isObjectArrayRangeWrite(Node node) { - return node instanceof ArrayRangeWriteNode && ((ArrayRangeWriteNode) node).isObjectArray(); + return node instanceof ArrayRangeWrite && ((ArrayRangeWrite) node).writesObjectArray(); } private static void expandFrontier(NodeFlood frontier, Node node) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,11 @@ import java.util.Iterator; import java.util.List; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; @@ -40,11 +45,6 @@ import org.graalvm.compiler.phases.graph.MergeableState; import org.graalvm.compiler.phases.graph.PostOrderNodeIterator; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicSet; - -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ResolvedJavaType; public class EliminateRedundantInitializationPhase extends BasePhase { /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,7 @@ import java.util.HashSet; import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -64,7 +65,6 @@ import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,10 +25,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; @@ -56,7 +53,9 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; /** @@ -169,8 +168,8 @@ } @Override - public boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) { - assert op == Condition.EQ || op == Condition.NE; + public boolean preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection) { + assert op == CanonicalCondition.EQ; ResolvedJavaType exactType = constantReflection.asJavaType(value); return !exactType.isPrimitive(); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, 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.replacements; + +import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject; + +import java.lang.reflect.Array; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; + +// JaCoCo Exclude + +/** + * Substitutions for {@link Array} methods. + */ +@ClassSubstitution(Array.class) +public class HotSpotArraySubstitutions { + + @MethodSubstitution + public static Object newInstance(Class componentType, int length) { + if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) { + // Exit the intrinsic here for the case where the array class does not exist + return newInstance(componentType, length); + } + return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -303,7 +303,11 @@ return result; } - public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj"); + /* + * As far as Java code is concerned this can be considered immutable: it is set just after the + * JavaThread is created, before it is published. After that, it is never changed. + */ + public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj"); @Fold public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) { @@ -565,9 +569,20 @@ return WordFactory.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int))); } + /** + * Idiom for making {@link GraalHotSpotVMConfig} a constant. + */ @Fold - public static int objectAlignment(@InjectedParameter GraalHotSpotVMConfig config) { - return config.objectAlignment; + public static GraalHotSpotVMConfig getConfig(@InjectedParameter GraalHotSpotVMConfig config) { + return config; + } + + /** + * Calls {@link #arrayAllocationSize(int, int, int, GraalHotSpotVMConfig)} using an injected VM + * configuration object. + */ + public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize) { + return arrayAllocationSize(length, headerSize, log2ElementSize, getConfig(INJECTED_VMCONFIG)); } /** @@ -578,10 +593,12 @@ * @param length the number of elements in the array * @param headerSize the size of the array header * @param log2ElementSize log2 of the size of an element in the array + * @param config the VM configuration providing the + * {@linkplain GraalHotSpotVMConfig#objectAlignment object alignment requirement} * @return the size of the memory chunk */ - public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize) { - int alignment = objectAlignment(INJECTED_VMCONFIG); + public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize, GraalHotSpotVMConfig config) { + int alignment = config.objectAlignment; int size = (length << log2ElementSize) + headerSize + (alignment - 1); int mask = ~(alignment - 1); return size & mask; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java Sat Feb 10 09:25:35 2018 +0100 @@ -62,6 +62,7 @@ import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; import static org.graalvm.compiler.replacements.ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED; +import static org.graalvm.compiler.replacements.ReplacementsUtil.runtimeAssert; import static org.graalvm.compiler.replacements.ReplacementsUtil.staticAssert; import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring; @@ -378,7 +379,13 @@ if (length < 0) { DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint); } - int layoutHelper = knownElementKind != JavaKind.Illegal ? knownLayoutHelper : readLayoutHelper(nonNullKlass); + int layoutHelper; + if (knownElementKind == JavaKind.Illegal) { + layoutHelper = readLayoutHelper(nonNullKlass); + } else { + runtimeAssert(knownLayoutHelper == readLayoutHelper(nonNullKlass), "layout mismatch"); + layoutHelper = knownLayoutHelper; + } //@formatter:off // from src/share/vm/oops/klass.hpp: // diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,6 @@ import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue; @@ -59,7 +58,6 @@ import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier; import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier; import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier; -import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode; import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode; import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode; import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier; @@ -152,18 +150,14 @@ } @Snippet - public static void serialArrayRangeWriteBarrier(Object object, int startIndex, int length) { + public static void serialArrayRangeWriteBarrier(Address address, int length, @ConstantParameter int elementStride) { if (length == 0) { return; } - Object dest = FixedValueAnchorNode.getObject(object); int cardShift = cardTableShift(INJECTED_VMCONFIG); final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress(); - final int scale = arrayIndexScale(JavaKind.Object); - int header = arrayBaseOffset(JavaKind.Object); - long dstAddr = GetObjectAddressNode.get(dest); - long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift; - long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift; + long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift; + long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift; long count = end - start + 1; while (count-- > 0) { DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean); @@ -305,24 +299,22 @@ } @Snippet - public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { + public static void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) { Word thread = registerAsWord(threadRegister); byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG)); // If the concurrent marker is not enabled or the vector length is zero, return. if (markingValue == (byte) 0 || length == 0) { return; } - Object dest = FixedValueAnchorNode.getObject(object); Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG)); Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG)); - long dstAddr = GetObjectAddressNode.get(dest); long indexValue = indexAddress.readWord(0).rawValue(); final int scale = arrayIndexScale(JavaKind.Object); - int header = arrayBaseOffset(JavaKind.Object); + long start = getPointerToFirstArrayElement(address, length, elementStride); - for (int i = startIndex; i < length; i++) { - Word address = WordFactory.pointer(dstAddr + header + (i * scale)); - Pointer oop = Word.objectToTrackedPointer(address.readObject(0, BarrierType.NONE)); + for (int i = 0; i < length; i++) { + Word arrElemPtr = WordFactory.pointer(start + i * scale); + Pointer oop = Word.objectToTrackedPointer(arrElemPtr.readObject(0, BarrierType.NONE)); verifyOop(oop.toObject()); if (oop.notEqual(0)) { if (indexValue != 0) { @@ -339,11 +331,10 @@ } @Snippet - public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) { + public static void g1ArrayRangePostWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) { if (length == 0) { return; } - Object dest = FixedValueAnchorNode.getObject(object); Word thread = registerAsWord(threadRegister); Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG)); Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG)); @@ -351,11 +342,8 @@ int cardShift = cardTableShift(INJECTED_VMCONFIG); final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress(); - final int scale = arrayIndexScale(JavaKind.Object); - int header = arrayBaseOffset(JavaKind.Object); - long dstAddr = GetObjectAddressNode.get(dest); - long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift; - long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift; + long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift; + long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift; long count = end - start + 1; while (count-- > 0) { @@ -384,6 +372,26 @@ } } + private static long getPointerToFirstArrayElement(Address address, int length, int elementStride) { + long result = Word.fromAddress(address).rawValue(); + if (elementStride < 0) { + // the address points to the place after the last array element + result = result + elementStride * length; + } + return result; + } + + private static long getPointerToLastArrayElement(Address address, int length, int elementStride) { + long result = Word.fromAddress(address).rawValue(); + if (elementStride < 0) { + // the address points to the place after the last array element + result = result + elementStride; + } else { + result = result + (length - 1) * elementStride; + } + return result; + } + public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class); @NodeIntrinsic(ForeignCallNode.class) @@ -431,9 +439,9 @@ public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) { Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); - args.add("object", arrayRangeWriteBarrier.getObject()); - args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("address", arrayRangeWriteBarrier.getAddress()); args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } @@ -519,18 +527,18 @@ public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); - args.add("object", arrayRangeWriteBarrier.getObject()); - args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("address", arrayRangeWriteBarrier.getAddress()); args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("threadRegister", registers.getThreadRegister()); template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) { Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage()); - args.add("object", arrayRangeWriteBarrier.getObject()); - args.add("startIndex", arrayRangeWriteBarrier.getStartIndex()); + args.add("address", arrayRangeWriteBarrier.getAddress()); args.add("length", arrayRangeWriteBarrier.getLength()); + args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("threadRegister", registers.getThreadRegister()); template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Sat Feb 10 09:25:35 2018 +0100 @@ -40,6 +40,7 @@ import java.lang.reflect.Method; import java.util.EnumMap; +import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Snippet; @@ -76,7 +77,6 @@ import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.word.Word; -import org.graalvm.util.UnmodifiableEconomicMap; import org.graalvm.word.LocationIdentity; import org.graalvm.word.WordFactory; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,21 @@ import java.util.ListIterator; import java.util.concurrent.atomic.AtomicInteger; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.DefaultProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.TriState; + +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.target.Backend; @@ -54,21 +69,6 @@ import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; -import org.graalvm.util.EconomicSet; - -import jdk.vm.ci.code.CodeCacheProvider; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.site.Call; -import jdk.vm.ci.code.site.ConstantReference; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.code.site.Infopoint; -import jdk.vm.ci.hotspot.HotSpotCompiledCode; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.DefaultProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.TriState; //JaCoCo Exclude diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Sat Feb 10 09:25:35 2018 +0100 @@ -86,6 +86,8 @@ import java.util.List; import java.util.TreeSet; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeLookupSwitch; import org.graalvm.compiler.bytecode.BytecodeStream; @@ -95,8 +97,6 @@ import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.ExceptionHandler; @@ -415,9 +415,6 @@ } public static class ExceptionDispatchBlock extends BciBlock { - - private EconomicMap exceptionDispatch = EconomicMap.create(Equivalence.DEFAULT); - public ExceptionHandler handler; public int deoptBci; } @@ -748,15 +745,6 @@ } } - private EconomicMap initialExceptionDispatch; - - private EconomicMap getInitialExceptionDispatch() { - if (initialExceptionDispatch == null) { - initialExceptionDispatch = EconomicMap.create(Equivalence.DEFAULT); - } - return initialExceptionDispatch; - } - private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) { ExceptionDispatchBlock lastHandler = null; @@ -769,20 +757,17 @@ lastHandler = null; } - EconomicMap exceptionDispatch = lastHandler != null ? lastHandler.exceptionDispatch : getInitialExceptionDispatch(); - ExceptionDispatchBlock curHandler = exceptionDispatch.get(h); - if (curHandler == null) { - curHandler = new ExceptionDispatchBlock(); - blocksNotYetAssignedId++; - curHandler.startBci = -1; - curHandler.endBci = -1; - curHandler.deoptBci = bci; - curHandler.handler = h; - curHandler.addSuccessor(blockMap[h.getHandlerBCI()]); - if (lastHandler != null) { - curHandler.addSuccessor(lastHandler); - } - exceptionDispatch.put(h, curHandler); + // We do not reuse exception dispatch blocks, because nested exception handlers + // might have problems reasoning about the correct frame state. + ExceptionDispatchBlock curHandler = new ExceptionDispatchBlock(); + blocksNotYetAssignedId++; + curHandler.startBci = -1; + curHandler.endBci = -1; + curHandler.deoptBci = bci; + curHandler.handler = h; + curHandler.addSuccessor(blockMap[h.getHandlerBCI()]); + if (lastHandler != null) { + curHandler.addSuccessor(lastHandler); } lastHandler = curHandler; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Sat Feb 10 09:25:35 2018 +0100 @@ -265,6 +265,8 @@ import java.util.Formatter; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; @@ -278,9 +280,12 @@ import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; import org.graalvm.compiler.core.common.PermanentBailoutException; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -343,8 +348,8 @@ import org.graalvm.compiler.nodes.calc.AndNode; import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.FloatConvertNode; import org.graalvm.compiler.nodes.calc.FloatDivNode; -import org.graalvm.compiler.nodes.calc.FloatConvertNode; import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; @@ -408,8 +413,6 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.util.ValueMergeUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.code.BailoutException; @@ -436,7 +439,6 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.core.common.type.IntegerStamp; /** * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph. @@ -577,10 +579,11 @@ // value on the stack on entry to an exception handler, // namely the exception object. assert frameState.rethrowException(); - ExceptionObjectNode exceptionObject = (ExceptionObjectNode) frameState.stackAt(0); + ValueNode exceptionValue = frameState.stackAt(0); + ExceptionObjectNode exceptionObject = (ExceptionObjectNode) GraphUtil.unproxify(exceptionValue); FrameStateBuilder dispatchState = parser.frameState.copy(); dispatchState.clearStack(); - dispatchState.push(JavaKind.Object, exceptionObject); + dispatchState.push(JavaKind.Object, exceptionValue); dispatchState.setRethrowException(true); FrameState newFrameState = dispatchState.create(parser.bci(), exceptionObject); frameState.replaceAndDelete(newFrameState); @@ -700,6 +703,12 @@ assert code.getCode() != null : "method must contain bytecodes: " + method; + if (TraceBytecodeParserLevel.getValue(options) != 0) { + if (!Assertions.assertionsEnabled()) { + throw new IllegalArgumentException("A non-zero " + TraceBytecodeParserLevel.getName() + " value requires assertions to be enabled"); + } + } + if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) { lnt = code.getLineNumberTable(); previousLineNumber = -1; @@ -1893,7 +1902,7 @@ LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver)); LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub)); ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess())); - LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, Condition.EQ, actual, expected, NodeView.DEFAULT)); + LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT)); JavaTypeProfile profile = null; if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) { @@ -2267,8 +2276,10 @@ } protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) { + FixedWithNextNode calleeBeforeUnwindNode = null; + ValueNode calleeUnwindValue = null; + try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) { - BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext); FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph); if (!targetMethod.isStatic()) { @@ -2315,13 +2326,25 @@ } } - FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); + calleeBeforeUnwindNode = parser.getBeforeUnwindNode(); if (calleeBeforeUnwindNode != null) { - ValueNode calleeUnwindValue = parser.getUnwindValue(); + calleeUnwindValue = parser.getUnwindValue(); assert calleeUnwindValue != null; - calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false)); } } + + /* + * Method handleException will call createTarget, which wires this exception edge to the + * corresponding exception dispatch block in the caller. In the case where it wires to the + * caller's unwind block, any FrameState created meanwhile, e.g., FrameState for + * LoopExitNode, would be instantiated with AFTER_EXCEPTION_BCI. Such frame states should + * not be fixed by IntrinsicScope.close, as they denote the states of the caller. Thus, the + * following code should be placed outside the IntrinsicScope, so that correctly created + * FrameStates are not replaced. + */ + if (calleeBeforeUnwindNode != null) { + calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false)); + } } public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) { @@ -2773,6 +2796,10 @@ setCurrentFrameState(frameState); currentBlock = block; + if (block != blockMap.getUnwindBlock() && !(block instanceof ExceptionDispatchBlock)) { + frameState.setRethrowException(false); + } + if (firstInstruction instanceof AbstractMergeNode) { setMergeStateAfter(block, firstInstruction); } @@ -2782,7 +2809,6 @@ } else if (block instanceof ExceptionDispatchBlock) { createExceptionDispatch((ExceptionDispatchBlock) block); } else { - frameState.setRethrowException(false); iterateBytecodesForBlock(block); } } @@ -3055,7 +3081,7 @@ } private boolean traceState() { - if (debug.isLogEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE) { + if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE) { frameState.traceState(); } return true; @@ -3075,56 +3101,107 @@ ValueNode a = x; ValueNode b = y; + BciBlock trueSuccessor = trueBlock; + BciBlock falseSuccessor = falseBlock; + + CanonicalizedCondition canonicalizedCondition = cond.canonicalize(); // Check whether the condition needs to mirror the operands. - if (cond.canonicalMirror()) { + if (canonicalizedCondition.mustMirror()) { a = y; b = x; } + if (canonicalizedCondition.mustNegate()) { + trueSuccessor = falseBlock; + falseSuccessor = trueBlock; + } // Create the logic node for the condition. - LogicNode condition = createLogicNode(cond, a, b); - - // Check whether the condition needs to negate the result. - boolean negate = cond.canonicalNegate(); - genIf(condition, negate, trueBlock, falseBlock); - } - - protected void genIf(LogicNode conditionInput, boolean negateCondition, BciBlock trueBlockInput, BciBlock falseBlockInput) { + LogicNode condition = createLogicNode(canonicalizedCondition.getCanonicalCondition(), a, b); + + double probability = -1; + if (condition instanceof IntegerEqualsNode) { + probability = extractInjectedProbability((IntegerEqualsNode) condition); + // the probability coming from here is about the actual condition + } + + if (probability == -1) { + probability = getProfileProbability(canonicalizedCondition.mustNegate()); + } + + probability = clampProbability(probability); + genIf(condition, trueSuccessor, falseSuccessor, probability); + } + + private double getProfileProbability(boolean negate) { + double probability; + if (profilingInfo == null) { + probability = 0.5; + } else { + assert assertAtIfBytecode(); + probability = profilingInfo.getBranchTakenProbability(bci()); + if (probability < 0) { + assert probability == -1 : "invalid probability"; + debug.log("missing probability in %s at bci %d", code, bci()); + probability = 0.5; + } else { + if (negate) { + // the probability coming from profile is about the original condition + probability = 1 - probability; + } + } + } + return probability; + } + + private static double extractInjectedProbability(IntegerEqualsNode condition) { + // Propagate injected branch probability if any. + IntegerEqualsNode equalsNode = condition; + BranchProbabilityNode probabilityNode = null; + ValueNode other = null; + if (equalsNode.getX() instanceof BranchProbabilityNode) { + probabilityNode = (BranchProbabilityNode) equalsNode.getX(); + other = equalsNode.getY(); + } else if (equalsNode.getY() instanceof BranchProbabilityNode) { + probabilityNode = (BranchProbabilityNode) equalsNode.getY(); + other = equalsNode.getX(); + } + + if (probabilityNode != null && probabilityNode.getProbability().isConstant() && other != null && other.isConstant()) { + double probabilityValue = probabilityNode.getProbability().asJavaConstant().asDouble(); + return other.asJavaConstant().asInt() == 0 ? 1.0 - probabilityValue : probabilityValue; + } + return -1; + } + + protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock falseBlockInput, double probabilityInput) { BciBlock trueBlock = trueBlockInput; BciBlock falseBlock = falseBlockInput; LogicNode condition = conditionInput; + double probability = probabilityInput; FrameState stateBefore = null; ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin(); if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); } - // Remove a logic negation node and fold it into the negate boolean. - boolean negate = negateCondition; + // Remove a logic negation node. if (condition instanceof LogicNegationNode) { LogicNegationNode logicNegationNode = (LogicNegationNode) condition; - negate = !negate; + BciBlock tmpBlock = trueBlock; + trueBlock = falseBlock; + falseBlock = tmpBlock; + probability = 1 - probability; condition = logicNegationNode.getValue(); } if (condition instanceof LogicConstantNode) { - genConstantTargetIf(trueBlock, falseBlock, negate, condition); + genConstantTargetIf(trueBlock, falseBlock, condition); } else { if (condition.graph() == null) { condition = genUnique(condition); } - // Need to get probability based on current bci. - double probability = branchProbability(condition); - - if (negate) { - BciBlock tmpBlock = trueBlock; - trueBlock = falseBlock; - falseBlock = tmpBlock; - probability = 1 - probability; - } - if (isNeverExecutedCode(probability)) { append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true)); if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) { @@ -3200,28 +3277,26 @@ } } - private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) { - LogicNode condition; + private LogicNode createLogicNode(CanonicalCondition cond, ValueNode a, ValueNode b) { assert !a.getStackKind().isNumericFloat(); - if (cond == Condition.EQ || cond == Condition.NE) { - if (a.getStackKind() == JavaKind.Object) { - condition = genObjectEquals(a, b); - } else { - condition = genIntegerEquals(a, b); - } - } else { - assert a.getStackKind() != JavaKind.Object && !cond.isUnsigned(); - condition = genIntegerLessThan(a, b); + switch (cond) { + case EQ: + if (a.getStackKind() == JavaKind.Object) { + return genObjectEquals(a, b); + } else { + return genIntegerEquals(a, b); + } + case LT: + assert a.getStackKind() != JavaKind.Object; + return genIntegerLessThan(a, b); + default: + throw GraalError.shouldNotReachHere("Unexpected condition: " + cond); } - return condition; - } - - private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) { + } + + private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition) { LogicConstantNode constantLogicNode = (LogicConstantNode) condition; boolean value = constantLogicNode.getValue(); - if (negate) { - value = !value; - } BciBlock nextBlock = falseBlock; if (value) { nextBlock = trueBlock; @@ -3775,7 +3850,13 @@ BciBlock firstSucc = currentBlock.getSuccessor(0); BciBlock secondSucc = currentBlock.getSuccessor(1); if (firstSucc != secondSucc) { - genIf(instanceOfNode, value != Bytecodes.IFNE, firstSucc, secondSucc); + boolean negate = value != Bytecodes.IFNE; + if (negate) { + BciBlock tmp = firstSucc; + firstSucc = secondSucc; + secondSucc = tmp; + } + genIf(instanceOfNode, firstSucc, secondSucc, getProfileProbability(negate)); } else { appendGoto(firstSucc); } @@ -4263,47 +4344,12 @@ return probability == 0 && optimisticOpts.removeNeverExecutedCode(getOptions()); } - private double rawBranchProbability(LogicNode conditionInput) { - if (conditionInput instanceof IntegerEqualsNode) { - // Propagate injected branch probability if any. - IntegerEqualsNode condition = (IntegerEqualsNode) conditionInput; - BranchProbabilityNode injectedProbability = null; - ValueNode other = null; - if (condition.getX() instanceof BranchProbabilityNode) { - injectedProbability = (BranchProbabilityNode) condition.getX(); - other = condition.getY(); - } else if (condition.getY() instanceof BranchProbabilityNode) { - injectedProbability = (BranchProbabilityNode) condition.getY(); - other = condition.getX(); - } - - if (injectedProbability != null && injectedProbability.getProbability().isConstant() && other != null && other.isConstant()) { - double probabilityValue = injectedProbability.getProbability().asJavaConstant().asDouble(); - return other.asJavaConstant().asInt() == 0 ? 1.0 - probabilityValue : probabilityValue; - } - } - - if (profilingInfo == null) { - return 0.5; - } - assert assertAtIfBytecode(); - - return profilingInfo.getBranchTakenProbability(bci()); - } - - protected double branchProbability(LogicNode conditionInput) { - double probability = rawBranchProbability(conditionInput); - if (probability < 0) { - assert probability == -1 : "invalid probability"; - debug.log("missing probability in %s at bci %d", code, bci()); - probability = 0.5; - } - + private double clampProbability(double probability) { if (!optimisticOpts.removeNeverExecutedCode(getOptions())) { if (probability == 0) { - probability = 0.0000001; + return 0.0000001; } else if (probability == 1) { - probability = 0.999999; + return 0.999999; } } return probability; @@ -4568,7 +4614,7 @@ } protected boolean traceInstruction(int bci, int opcode, boolean blockStart) { - if (debug.isLogEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS) { + if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS) { traceInstructionHelper(bci, opcode, blockStart); } return true; @@ -4589,7 +4635,7 @@ if (!currentBlock.getJsrScope().isEmpty()) { sb.append(' ').append(currentBlock.getJsrScope()); } - debug.log("%s", sb); + TTY.println("%s", sb); } @Override diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,7 +34,9 @@ */ public class BytecodeParserOptions { // @formatter:off - @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug) + @Option(help = "The trace level for the bytecode parser. A value of 1 enables instruction tracing " + + "and any greater value emits a frame state trace just prior to an instruction trace. " + + "This option requires assertions to be enabled.", type = OptionType.Debug) public static final OptionKey TraceBytecodeParserLevel = new OptionKey<>(0); @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert) @@ -56,7 +58,7 @@ public static final OptionKey TraceParserPlugins = new OptionKey<>(false); @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) - public static final OptionKey InlineDuringParsingMaxDepth = new OptionKey<>(10); + public static final OptionKey InlineDuringParsingMaxDepth = new OptionKey<>(3); @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) public static final OptionKey HideSubstitutionStates = new OptionKey<>(false); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,11 @@ */ package org.graalvm.compiler.java; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; + import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.ControlSplitNode; @@ -34,9 +37,6 @@ import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; -import org.graalvm.util.EconomicMap; - -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -47,6 +47,7 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.java.BciBlockMapping.BciBlock; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -999,15 +1000,14 @@ } public void traceState() { - DebugContext debug = graph.getDebug(); - debug.log("| state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod()); + TTY.println("| state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod()); for (int i = 0; i < localsSize(); ++i) { ValueNode value = locals[i]; - debug.log("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); + TTY.println("| local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); } for (int i = 0; i < stackSize(); ++i) { ValueNode value = stack[i]; - debug.log("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); + TTY.println("| stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value); } } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,9 +26,6 @@ import static jdk.vm.ci.code.ValueUtil.asRegister; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import java.lang.reflect.Array; -import java.lang.reflect.Field; - import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; @@ -43,7 +40,6 @@ import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; -import sun.misc.Unsafe; /** * Emits code which compares two arrays of the same length. If the CPU supports any vector @@ -72,9 +68,8 @@ assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; - Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); - this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass); - this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass); + this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); this.resultValue = result; this.array1Value = array1; @@ -218,20 +213,4 @@ masm.bind(end); masm.mov(64, rscratch1, zr); } - - private static final Unsafe UNSAFE = initUnsafe(); - - private static Unsafe initUnsafe() { - try { - return Unsafe.getUnsafe(); - } catch (SecurityException se) { - try { - Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - return (Unsafe) theUnsafe.get(Unsafe.class); - } catch (Exception e) { - throw new RuntimeException("exception while trying to get Unsafe", e); - } - } - } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,12 +22,9 @@ */ package org.graalvm.compiler.lir.amd64; +import static jdk.vm.ci.code.ValueUtil.asRegister; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; @@ -50,7 +47,6 @@ import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; -import sun.misc.Unsafe; /** * Emits code which compares two arrays of the same length. If the CPU supports any vector @@ -83,9 +79,8 @@ super(TYPE); this.kind = kind; - Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); - this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass); - this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass); + this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); this.resultValue = result; this.array1Value = array1; @@ -531,20 +526,4 @@ // Floats within the range are equal, revert change to the register index masm.subq(index, range); } - - private static final Unsafe UNSAFE = initUnsafe(); - - private static Unsafe initUnsafe() { - try { - return Unsafe.getUnsafe(); - } catch (SecurityException se) { - try { - Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - return (Unsafe) theUnsafe.get(Unsafe.class); - } catch (Exception e) { - throw new RuntimeException("exception while trying to get Unsafe", e); - } - } - } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java Sat Feb 10 09:25:35 2018 +0100 @@ -101,6 +101,10 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { directCall(crb, masm, callTarget, null, true, state); } + + public int emitCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + return directCall(crb, masm, callTarget, null, true, state); + } } @Opcode("CALL_INDIRECT") @@ -183,23 +187,27 @@ } } - public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { + public static int directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) { if (align) { emitAlignmentForDirectCall(crb, masm); } int before = masm.position(); + int callPCOffset; if (scratch != null) { // offset might not fit a 32-bit immediate, generate an // indirect call with a 64-bit immediate masm.movq(scratch, 0L); + callPCOffset = masm.position(); masm.call(scratch); } else { + callPCOffset = masm.position(); masm.call(); } int after = masm.position(); crb.recordDirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); masm.ensureUniquePC(); + return callPCOffset; } protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) { @@ -228,12 +236,13 @@ masm.ensureUniquePC(); } - public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { + public static int indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { int before = masm.position(); masm.call(dst); int after = masm.position(); crb.recordIndirectCall(before, after, callTarget, info); crb.recordExceptionHandlers(after, info); masm.ensureUniquePC(); + return before; } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; @@ -755,17 +756,18 @@ } } - public abstract static class Pointer extends AMD64LIRInstruction { + public abstract static class PointerCompressionOp extends AMD64LIRInstruction { protected final LIRKindTool lirKindTool; protected final CompressEncoding encoding; protected final boolean nonNull; @Def({REG, HINT}) private AllocatableValue result; - @Use({REG}) private AllocatableValue input; + @Use({REG, CONST}) private Value input; @Alive({REG, ILLEGAL}) private AllocatableValue baseRegister; - protected Pointer(LIRInstructionClass type, AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, - LIRKindTool lirKindTool) { + protected PointerCompressionOp(LIRInstructionClass type, AllocatableValue result, Value input, + AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { + super(type); this.result = result; this.input = input; @@ -779,8 +781,12 @@ return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase(); } - protected final Register getResultRegister() { - return asRegister(result); + public final Value getInput() { + return input; + } + + public final AllocatableValue getResult() { + return result; } protected final Register getBaseRegister() { @@ -796,18 +802,24 @@ } } - public static final class CompressPointer extends Pointer { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); + public static class CompressPointerOp extends PointerCompressionOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointerOp.class); - public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { - super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool); + public CompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { + this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool); + } + + protected CompressPointerOp(LIRInstructionClass type, AllocatableValue result, Value input, + AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { + + super(type, result, input, baseRegister, encoding, nonNull, lirKindTool); } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { move(lirKindTool.getObjectKind(), crb, masm); - Register resReg = getResultRegister(); + Register resReg = asRegister(getResult()); if (hasBase(crb)) { Register baseReg = getBaseRegister(); if (!nonNull) { @@ -824,18 +836,24 @@ } } - public static final class UncompressPointer extends Pointer { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); + public static class UncompressPointerOp extends PointerCompressionOp { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointerOp.class); - public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { - super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool); + public UncompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { + this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool); + } + + protected UncompressPointerOp(LIRInstructionClass type, AllocatableValue result, Value input, + AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { + + super(type, result, input, baseRegister, encoding, nonNull, lirKindTool); } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { move(lirKindTool.getNarrowOopKind(), crb, masm); - Register resReg = getResultRegister(); + Register resReg = asRegister(getResult()); int shift = getShift(); if (shift != 0) { masm.shlq(resReg, shift); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,11 +22,13 @@ */ package org.graalvm.compiler.lir.amd64; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import static jdk.vm.ci.code.ValueUtil.asStackSlot; import static jdk.vm.ci.code.ValueUtil.isStackSlot; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import java.util.Arrays; + +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.LIRValueUtil; @@ -34,7 +36,6 @@ import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,13 +24,13 @@ import static org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp.prune; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterSaveLayout; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -36,9 +36,6 @@ import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import java.lang.reflect.Array; -import java.lang.reflect.Field; - import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.sparc.SPARCAddress; import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; @@ -52,7 +49,6 @@ import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.sparc.SPARCKind; -import sun.misc.Unsafe; /** * Emits code which compares two arrays of the same length. @@ -82,9 +78,8 @@ assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; - Class arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass(); - this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass); - this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass); + this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); this.resultValue = result; this.array1Value = array1; @@ -247,20 +242,4 @@ } } } - - private static final Unsafe UNSAFE = initUnsafe(); - - private static Unsafe initUnsafe() { - try { - return Unsafe.getUnsafe(); - } catch (SecurityException se) { - try { - Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - return (Unsafe) theUnsafe.get(Unsafe.class); - } catch (Exception e) { - throw new RuntimeException("exception while trying to get Unsafe", e); - } - } - } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java Sat Feb 10 09:25:35 2018 +0100 @@ -78,6 +78,8 @@ import java.util.EnumSet; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Assembler.LabelHint; import org.graalvm.compiler.asm.Label; @@ -98,8 +100,6 @@ import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; import org.graalvm.compiler.lir.Variable; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,12 +22,14 @@ */ package org.graalvm.compiler.lir.sparc; +import static jdk.vm.ci.code.ValueUtil.asStackSlot; +import static jdk.vm.ci.code.ValueUtil.isStackSlot; import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; import static org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer.DUMMY; -import static jdk.vm.ci.code.ValueUtil.asStackSlot; -import static jdk.vm.ci.code.ValueUtil.isStackSlot; import java.util.Arrays; + +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.sparc.SPARCAddress; import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; import org.graalvm.compiler.lir.LIRInstructionClass; @@ -36,7 +38,6 @@ import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterSaveLayout; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,15 +27,14 @@ import java.util.HashSet; +import org.graalvm.collections.Pair; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue; +import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue; -import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase; -import org.graalvm.util.Pair; - import jdk.vm.ci.code.Register; import jdk.vm.ci.code.Register.RegisterCategory; import jdk.vm.ci.code.RegisterValue; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,14 +33,14 @@ import java.util.Arrays; import java.util.EnumSet; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.common.FieldIntrospection; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.FieldsScanner; import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; import org.graalvm.compiler.lir.LIRInstruction.OperandMode; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.StackSlot; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,7 +30,8 @@ import java.util.Collections; import java.util.EnumSet; -import jdk.vm.ci.code.RegisterConfig; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.CounterKey; @@ -43,11 +44,10 @@ import org.graalvm.compiler.lir.framemap.FrameMap; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; +import jdk.vm.ci.code.RegisterConfig; import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,12 +31,12 @@ import java.util.ArrayList; import java.util.EnumSet; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterSaveLayout; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Sat Feb 10 09:25:35 2018 +0100 @@ -35,6 +35,7 @@ import java.util.BitSet; import java.util.EnumSet; +import org.graalvm.collections.Pair; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; @@ -60,7 +61,6 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.Pair; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -35,6 +35,8 @@ import java.util.BitSet; import java.util.EnumSet; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; @@ -56,8 +58,6 @@ import org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.RegisterArray; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,10 +22,10 @@ */ package org.graalvm.compiler.lir.alloc.lsra; +import org.graalvm.collections.Pair; import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; -import org.graalvm.util.Pair; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,8 @@ import java.util.ArrayList; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; @@ -37,8 +39,6 @@ import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.LIRValueUtil; import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Constant; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -32,13 +32,15 @@ import java.util.List; import java.util.function.Consumer; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.asm.AbstractAddress; import org.graalvm.compiler.asm.Assembler; -import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.DataSection.Data; import org.graalvm.compiler.code.DataSection.RawData; +import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.type.DataPointerConstant; @@ -55,8 +57,6 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.DebugInfo; @@ -324,12 +324,32 @@ } /** - * Notifies this object of a branch instruction at offset {@code pos} in the code. + * Notifies this object of a branch instruction at offset {@code pcOffset} in the code. * * @param isNegated negation status of the branch's condition. */ @SuppressWarnings("unused") - public void recordBranch(int pos, boolean isNegated) { + public void recordBranch(int pcOffset, boolean isNegated) { + } + + /** + * Notifies this object of a call instruction belonging to an INVOKEVIRTUAL or INVOKEINTERFACE + * at offset {@code pcOffset} in the code. + * + * @param nodeSourcePosition source position of the corresponding invoke. + */ + @SuppressWarnings("unused") + public void recordInvokeVirtualOrInterfaceCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) { + } + + /** + * Notifies this object of a call instruction belonging to an INLINE_INVOKE at offset + * {@code pcOffset} in the code. + * + * @param nodeSourcePosition source position of the corresponding invoke. + */ + @SuppressWarnings("unused") + public void recordInlineInvokeCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) { } /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,8 @@ */ package org.graalvm.compiler.lir.gen; -import jdk.vm.ci.code.RegisterConfig; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity; import org.graalvm.compiler.debug.DebugContext; @@ -30,10 +31,9 @@ import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.framemap.FrameMap; import org.graalvm.compiler.lir.framemap.FrameMapBuilder; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.CallingConvention; +import jdk.vm.ci.code.RegisterConfig; public class LIRGenerationResult { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,20 +22,20 @@ */ package org.graalvm.compiler.lir.gen; -import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import static jdk.vm.ci.code.ValueUtil.isIllegal; import static jdk.vm.ci.code.ValueUtil.isLegal; import static jdk.vm.ci.meta.Value.ILLEGAL; +import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.lir.LIRInsertionBuffer; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.Value; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ public PreAllocationOptimizationStage(OptionValues options) { if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue(options)) { appendPhase(new ConstantLoadOptimization()); - appendPhase(new SaveCalleeSaveRegisters()); } + appendPhase(new SaveCalleeSaveRegisters()); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,6 +31,8 @@ import java.util.Deque; import java.util.EnumSet; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.debug.CounterKey; @@ -43,8 +45,6 @@ import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; import org.graalvm.compiler.lir.LIRInstruction.OperandMode; import org.graalvm.compiler.lir.VirtualStackSlot; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.Value; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java Sat Feb 10 09:25:35 2018 +0100 @@ -35,6 +35,7 @@ import java.util.EnumSet; import java.util.PriorityQueue; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; @@ -54,7 +55,6 @@ import org.graalvm.compiler.options.NestedBooleanOptionKey; import org.graalvm.compiler.options.Option; import org.graalvm.compiler.options.OptionType; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,8 @@ */ package org.graalvm.compiler.lir.util; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import jdk.vm.ci.meta.Value; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,7 +31,7 @@ import java.util.List; import org.graalvm.compiler.core.common.RetryableBailoutException; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.Mark; @@ -451,7 +451,7 @@ if (!(condition instanceof CompareNode)) { return false; } - if (((CompareNode) condition).condition() == Condition.EQ || ((CompareNode) condition).condition() == Condition.NE) { + if (((CompareNode) condition).condition() == CanonicalCondition.EQ) { condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s condition unsupported %s ", loopBegin, ((CompareNode) condition).condition()); return false; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -73,12 +73,18 @@ Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT); ValueNode range = sub(graph, end, iv.initNode()); + ValueNode max; + ValueNode min; ValueNode oneDirection; if (iv.direction() == Direction.Up) { oneDirection = ConstantNode.forIntegerStamp(stamp, 1, graph); + max = end; + min = iv.initNode(); } else { assert iv.direction() == Direction.Down; oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph); + max = iv.initNode(); + min = end; } if (oneOff) { range = add(graph, range, oneDirection); @@ -95,7 +101,7 @@ return div; } ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph); - return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero)); + return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(max, min)), zero, div)); } /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,13 @@ */ package org.graalvm.compiler.loop; -import jdk.vm.ci.code.BytecodeFrame; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Queue; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.IntegerStamp; @@ -67,13 +73,8 @@ import org.graalvm.compiler.nodes.debug.ControlFlowAnchored; import org.graalvm.compiler.nodes.extended.ValueAnchorNode; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import java.util.Collection; -import java.util.LinkedList; -import java.util.Queue; +import jdk.vm.ci.code.BytecodeFrame; public class LoopEx { private final Loop loop; @@ -236,13 +237,13 @@ if (isOutsideLoop(lessThan.getX())) { iv = getInductionVariables().get(lessThan.getY()); if (iv != null) { - condition = lessThan.condition().mirror(); + condition = lessThan.condition().asCondition().mirror(); limit = lessThan.getX(); } } else if (isOutsideLoop(lessThan.getY())) { iv = getInductionVariables().get(lessThan.getX()); if (iv != null) { - condition = lessThan.condition(); + condition = lessThan.condition().asCondition(); limit = lessThan.getY(); } } @@ -393,8 +394,8 @@ } else { boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode; if (!isValidConvert && op instanceof ZeroExtendNode) { - IntegerStamp inputStamp = (IntegerStamp) ((ZeroExtendNode) op).getValue().stamp(NodeView.DEFAULT); - isValidConvert = inputStamp.isPositive(); + ZeroExtendNode zeroExtendNode = (ZeroExtendNode) op; + isValidConvert = zeroExtendNode.isInputAlwaysPositive() || ((IntegerStamp) zeroExtendNode.stamp(NodeView.DEFAULT)).isPositive(); } if (isValidConvert) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,12 @@ */ package org.graalvm.compiler.loop; -import jdk.vm.ci.meta.TriState; +import java.util.ArrayDeque; +import java.util.Collections; +import java.util.Deque; +import java.util.Iterator; + +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; @@ -52,12 +57,8 @@ import org.graalvm.compiler.nodes.spi.NodeWithState; import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.util.EconomicMap; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; +import jdk.vm.ci.meta.TriState; public abstract class LoopFragment { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,8 @@ import java.util.LinkedList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.DuplicationReplacement; @@ -62,8 +64,6 @@ import org.graalvm.compiler.nodes.calc.SubNode; import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; public class LoopFragmentInside extends LoopFragment { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.loop; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph; @@ -35,7 +36,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.cfg.Block; -import org.graalvm.util.EconomicSet; public class LoopFragmentWhole extends LoopFragment { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,9 @@ import java.util.LinkedList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.LoopBeginNode; @@ -34,9 +37,6 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; public class LoopsData { private final EconomicMap loopBeginToEx = EconomicMap.create(Equivalence.IDENTITY); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,9 @@ import java.util.Arrays; +import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Warmup; import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec; @@ -32,7 +34,8 @@ import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; -@Warmup(iterations = 15) +@Warmup(iterations = 20) +@Measurement(iterations = 10) public class SchedulePhaseBenchmark extends GraalBenchmark { @MethodSpec(declaringClass = String.class, name = "equals") @@ -117,5 +120,67 @@ public void intersection_EARLIEST_OPTIMAL(IntersectionState_EARLIEST_OPTIMAL s) { s.schedule.apply(s.graph); } + + @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet") + public static class IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL extends ScheduleState { + public IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() { + super(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); + } + } + + @Benchmark + public void intersection_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) { + s.schedule.apply(s.graph); + } + // Checkstyle: resume method name check + + // Checkstyle: stop method name check + @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") + public static class ScheduleEarliestIterative_LATEST_OPTIMAL extends ScheduleState { + public ScheduleEarliestIterative_LATEST_OPTIMAL() { + super(SchedulingStrategy.LATEST); + } + } + + @Benchmark + public void scheduleEarliestIterative_LATEST_OPTIMAL(ScheduleEarliestIterative_LATEST_OPTIMAL s) { + s.schedule.apply(s.graph); + } + + @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") + public static class ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL extends ScheduleState { + public ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL() { + super(SchedulingStrategy.LATEST_OUT_OF_LOOPS); + } + } + + @Benchmark + public void scheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL(ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL s) { + s.schedule.apply(s.graph); + } + + @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") + public static class ScheduleEarliestIterative_EARLIEST_OPTIMAL extends ScheduleState { + public ScheduleEarliestIterative_EARLIEST_OPTIMAL() { + super(SchedulingStrategy.EARLIEST); + } + } + + @Benchmark + public void scheduleEarliestIterative_EARLIEST_OPTIMAL(ScheduleEarliestIterative_EARLIEST_OPTIMAL s) { + s.schedule.apply(s.graph); + } + + @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative") + public static class ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL extends ScheduleState { + public ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() { + super(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); + } + } + + @Benchmark + public void scheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) { + s.schedule.apply(s.graph); + } // Checkstyle: resume method name check } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,12 @@ */ package org.graalvm.compiler.microbenchmarks.graal.util; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; +import org.graalvm.compiler.phases.tiers.HighTierContext; public class ScheduleState extends GraphState { @@ -36,7 +40,7 @@ } public ScheduleState() { - this(SchedulingStrategy.EARLIEST); + this(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); } @Override @@ -44,4 +48,13 @@ schedule = new SchedulePhase(selectedStrategy); super.beforeInvocation(); } + + @Override + protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) { + StructuredGraph g = super.preprocessOriginal(structuredGraph); + GraalState graal = new GraalState(); + PhaseSuite highTier = graal.backend.getSuites().getDefaultSuites(graal.options).getHighTier(); + highTier.apply(g, new HighTierContext(graal.providers, graal.backend.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL)); + return g; + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -156,11 +156,11 @@ PhaseContext context = new PhaseContext(getProviders()); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + new ConvertDeoptimizeToGuardPhase().apply(graph, context); graph.clearAllStateAfter(); graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA); canonicalizer.apply(graph, context); - new ConvertDeoptimizeToGuardPhase().apply(graph, context); // new DominatorConditionalEliminationPhase(true).apply(graph, context); new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context); canonicalizer.apply(graph, context); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -129,10 +129,13 @@ if (ret == null) { throw new NoSuchElementException(); } - if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) { + if (current instanceof FixedWithNextNode) { + current = ((FixedWithNextNode) current).next(); + if (current instanceof AbstractBeginNode) { + current = null; + } + } else { current = null; - } else { - current = ((FixedWithNextNode) current).next(); } return ret; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -49,7 +49,7 @@ /** * Primary successor of the control split. Data dependencies on the node have to be scheduled in - * the primary successor. + * the primary successor. Returns null if data dependencies are not expected. * * @return the primary successor */ diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -39,7 +39,7 @@ import jdk.vm.ci.meta.Value; @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}") -public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable { +public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable, StaticDeoptimizingNode { public static final int DEFAULT_DEBUG_ID = 0; public static final NodeClass TYPE = NodeClass.create(DeoptimizeNode.class); @@ -67,11 +67,13 @@ this.speculation = speculation; } - public DeoptimizationAction action() { + @Override + public DeoptimizationAction getAction() { return action; } - public DeoptimizationReason reason() { + @Override + public DeoptimizationReason getReason() { return reason; } @@ -115,6 +117,7 @@ return ConstantNode.forConstant(speculation, metaAccess, graph()); } + @Override public JavaConstant getSpeculation() { return speculation; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,25 +24,15 @@ import org.graalvm.compiler.nodes.extended.GuardingNode; -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; - /** * Shared interface to capture core methods of {@link AbstractFixedGuardNode} and {@link GuardNode}. * */ -public interface DeoptimizingGuard extends ValueNodeInterface, GuardingNode { +public interface DeoptimizingGuard extends GuardingNode, StaticDeoptimizingNode { LogicNode getCondition(); void setCondition(LogicNode x, boolean negated); - DeoptimizationReason getReason(); - - DeoptimizationAction getAction(); - - JavaConstant getSpeculation(); - boolean isNegated(); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -83,15 +83,7 @@ @Override public void lower(LoweringTool tool) { if (graph().getGuardsStage().allowsFloatingGuards()) { - /* - * Don't allow guards with action None and reason RuntimeConstraint to float. In cases - * where 2 guards are testing equivalent conditions they might be lowered at the same - * location. If the guard with the None action is lowered before the other guard then - * the code will be stuck repeatedly deoptimizing without invalidating the code. - * Conditional elimination will eliminate the guard if it's truly redundant in this - * case. - */ - if (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint) { + if (getAction() != DeoptimizationAction.None) { ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode(); this.replaceAtUsages(guard); graph().removeFixed(this); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Sat Feb 10 09:25:35 2018 +0100 @@ -37,6 +37,9 @@ import java.util.SortedMap; import java.util.TreeMap; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.util.TypeReader; @@ -62,9 +65,6 @@ import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.DeoptimizationAction; @@ -489,7 +489,8 @@ */ LoopScope outerScope = loopScope.outer; int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1; - successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes, + successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, + outerScope.initialCreatedNodes == null ? null : Arrays.copyOf(outerScope.initialCreatedNodes, outerScope.initialCreatedNodes.length), Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates); checkLoopExplosionIteration(methodScope, successorAddScope); @@ -736,7 +737,8 @@ assert methodScope.loopExplosion != LoopExplosionKind.NONE; if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) { int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1; - LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes, + LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates); checkLoopExplosionIteration(methodScope, nextIterationScope); loopScope.nextIterations.addLast(nextIterationScope); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,8 @@ import java.util.Iterator; import java.util.Objects; +import org.graalvm.collections.Pair; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.util.FrequencyEncoder; import org.graalvm.compiler.core.common.util.TypeConversion; @@ -42,8 +44,6 @@ import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.java.ExceptionObjectNode; -import org.graalvm.util.Pair; -import org.graalvm.util.UnmodifiableMapCursor; import jdk.vm.ci.code.Architecture; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,8 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -59,8 +61,6 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.JavaConstant; @@ -557,7 +557,7 @@ } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) { DeoptimizeNode deopt1 = (DeoptimizeNode) next1; DeoptimizeNode deopt2 = (DeoptimizeNode) next2; - if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) { + if (deopt1.getReason() == deopt2.getReason() && deopt1.getAction() == deopt2.getAction()) { // Same deoptimization reason and action. return true; } @@ -600,7 +600,7 @@ } } else if (a instanceof CompareNode) { CompareNode compareA = (CompareNode) a; - Condition conditionA = compareA.condition(); + Condition conditionA = compareA.condition().asCondition(); if (compareA.unorderedIsTrue()) { return false; } @@ -614,7 +614,7 @@ return false; } Condition comparableCondition = null; - Condition conditionB = compareB.condition(); + Condition conditionB = compareB.condition().asCondition(); if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) { comparableCondition = conditionB; } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) { @@ -1384,7 +1384,7 @@ @Override public AbstractBeginNode getPrimarySuccessor() { - return this.trueSuccessor(); + return null; } public AbstractBeginNode getSuccessor(boolean result) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2018, 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; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class contains all inlining decisions performed on a graph during the compilation. + * + * Each inlining decision consists of: + * + *
    + *
  • a value indicating whether the decision was positive or negative
  • + *
  • the call target method
  • + *
  • the reason for the inlining decision
  • + *
  • the name of the phase in which the inlining decision took place
  • + *
  • the special {@link BytecodePositionWithId} value that describes the position in the bytecode + * together with the callsite-specific unique identifier
  • + *
  • the inlining log of the inlined graph, or {@code null} if the decision was negative
  • + *
+ * + * A phase that does inlining should use the instance of this class contained in the + * {@link StructuredGraph} by calling {@link #addDecision} whenever it decides to inline a method. + * If there are invokes in the graph at the end of the respective phase, then that phase must call + * {@link #addDecision} to log negative decisions. + * + * At the end of the compilation, the contents of the inlining log can be converted into a list of + * decisions by calling {@link #formatAsList} or into an inlining tree, by calling + * {@link #formatAsTree}. + */ +public class InliningLog { + /** + * A bytecode position with a unique identifier attached. + * + * The purpose of this class is to disambiguate callsites that are duplicated by a + * transformation (such as loop peeling or path duplication). + */ + public static final class BytecodePositionWithId extends BytecodePosition implements Comparable { + private final int id; + + public BytecodePositionWithId(BytecodePositionWithId caller, ResolvedJavaMethod method, int bci, int id) { + super(caller, method, bci); + this.id = id; + } + + public BytecodePositionWithId addCallerWithId(BytecodePositionWithId caller) { + if (getCaller() == null) { + return new BytecodePositionWithId(caller, getMethod(), getBCI(), id); + } else { + return new BytecodePositionWithId(getCaller().addCallerWithId(caller), getMethod(), getBCI(), id); + } + } + + public static BytecodePositionWithId create(FrameState state) { + return create(state, true); + } + + @SuppressWarnings("deprecation") + private static BytecodePositionWithId create(FrameState state, boolean topLevel) { + if (state == null) { + return null; + } + ResolvedJavaMethod method = state.getMethod(); + int bci = topLevel ? state.bci - 3 : state.bci; + int id = state.getId(); + return new BytecodePositionWithId(create(state.outerFrameState(), false), method, bci, id); + } + + @Override + public BytecodePositionWithId getCaller() { + return (BytecodePositionWithId) super.getCaller(); + } + + public BytecodePositionWithId withoutCaller() { + return new BytecodePositionWithId(null, getMethod(), getBCI(), id); + } + + public long getId() { + return id; + } + + @Override + public boolean equals(Object that) { + return super.equals(that) && this.id == ((BytecodePositionWithId) that).id; + } + + @Override + public int hashCode() { + return super.hashCode() ^ (id << 16); + } + + @Override + public int compareTo(BytecodePositionWithId that) { + int diff = this.getBCI() - that.getBCI(); + if (diff != 0) { + return diff; + } + diff = (int) (this.getId() - that.getId()); + return diff; + } + } + + public static final class Decision { + private final boolean positive; + private final String reason; + private final String phase; + private final ResolvedJavaMethod target; + private final BytecodePositionWithId position; + private final InliningLog childLog; + + private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, InliningLog childLog) { + assert position != null; + this.positive = positive; + this.reason = reason; + this.phase = phase; + this.target = target; + this.position = position; + this.childLog = childLog; + } + + public boolean isPositive() { + return positive; + } + + public String getReason() { + return reason; + } + + public String getPhase() { + return phase; + } + + public BytecodePositionWithId getPosition() { + return position; + } + + public InliningLog getChildLog() { + return childLog; + } + + public ResolvedJavaMethod getTarget() { + return target; + } + } + + private static class Callsite { + public final List decisions; + public final Map children; + public final BytecodePositionWithId position; + + Callsite(BytecodePositionWithId position) { + this.children = new HashMap<>(); + this.position = position; + this.decisions = new ArrayList<>(); + } + + public Callsite getOrCreateChild(BytecodePositionWithId fromRootPosition) { + Callsite child = children.get(fromRootPosition.withoutCaller()); + if (child == null) { + child = new Callsite(fromRootPosition); + children.put(fromRootPosition.withoutCaller(), child); + } + return child; + } + + public Callsite createCallsite(BytecodePositionWithId fromRootPosition, String decision) { + Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller()); + Callsite callsite = parent.getOrCreateChild(fromRootPosition); + callsite.decisions.add(decision); + return null; + } + + private Callsite getOrCreateCallsite(BytecodePositionWithId fromRootPosition) { + if (fromRootPosition == null) { + return this; + } else { + Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller()); + Callsite callsite = parent.getOrCreateChild(fromRootPosition); + return callsite; + } + } + } + + private final List decisions; + + public InliningLog() { + this.decisions = new ArrayList<>(); + } + + public List getDecisions() { + return decisions; + } + + public void addDecision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, + InliningLog calleeLog) { + Decision decision = new Decision(positive, reason, phase, target, position, calleeLog); + decisions.add(decision); + } + + public String formatAsList() { + StringBuilder builder = new StringBuilder(); + formatAsList("", null, decisions, builder); + return builder.toString(); + } + + private void formatAsList(String phasePrefix, BytecodePositionWithId caller, List subDecisions, StringBuilder builder) { + for (Decision decision : subDecisions) { + String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase(); + String target = decision.getTarget().format("%H.%n(%p)"); + String positive = decision.isPositive() ? "inline" : "do not inline"; + BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller); + String position = " " + decision.getPosition().toString().replaceAll("\n", "\n "); + String line = String.format("<%s> %s %s: %s\n%s", phaseStack, positive, target, decision.getReason(), position); + builder.append(line).append(System.lineSeparator()); + if (decision.getChildLog() != null) { + formatAsList(phaseStack, absolutePosition, decision.getChildLog().getDecisions(), builder); + } + } + } + + public String formatAsTree() { + Callsite root = new Callsite(null); + createTree("", null, root, decisions); + StringBuilder builder = new StringBuilder(); + formatAsTree(root, "", builder); + return builder.toString(); + } + + private void createTree(String phasePrefix, BytecodePositionWithId caller, Callsite root, List subDecisions) { + for (Decision decision : subDecisions) { + String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase(); + String target = decision.getTarget().format("%H.%n(%p)"); + BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller); + String line = String.format("<%s> %s: %s", phaseStack, target, decision.getReason()); + root.createCallsite(absolutePosition, line); + if (decision.getChildLog() != null) { + createTree(phaseStack, absolutePosition, root, decision.getChildLog().getDecisions()); + } + } + } + + private void formatAsTree(Callsite site, String indent, StringBuilder builder) { + String position = site.position != null ? site.position.withoutCaller().toString() : ""; + String decision = String.join("; ", site.decisions); + String line = String.format("%s%s; %s", indent, position, decision); + builder.append(line).append(System.lineSeparator()); + String childIndent = indent + " "; + site.children.entrySet().stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).forEach(e -> { + formatAsTree(e.getValue(), childIndent, builder); + }); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,9 +24,9 @@ import java.util.EnumMap; -import org.graalvm.util.Equivalence; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.word.LocationIdentity; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaKind.FormatWithToString; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017, 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; + +import org.graalvm.compiler.debug.GraalError; + +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaConstant; + +public interface StaticDeoptimizingNode extends ValueNodeInterface { + + DeoptimizationReason getReason(); + + DeoptimizationAction getAction(); + + JavaConstant getSpeculation(); + + /** + * Describes how much information is gathered when deoptimization triggers. + * + * This enum is {@link Comparable} and orders its element from highest priority to lowest + * priority. + */ + enum GuardPriority { + Speculation, + Profile, + None; + + public boolean isHigherPriorityThan(GuardPriority other) { + return this.compareTo(other) < 0; + } + + public boolean isLowerPriorityThan(GuardPriority other) { + return this.compareTo(other) > 0; + } + + public static GuardPriority highest() { + return Speculation; + } + } + + default GuardPriority computePriority() { + if (getSpeculation() != null && getSpeculation().isNonNull()) { + return GuardNode.GuardPriority.Speculation; + } + switch (getAction()) { + case InvalidateReprofile: + case InvalidateRecompile: + return GuardNode.GuardPriority.Profile; + case RecompileIfTooManyDeopts: + case InvalidateStopCompiling: + case None: + return GuardNode.GuardPriority.None; + } + throw GraalError.shouldNotReachHere(); + } +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,10 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.core.common.CancellationBailoutException; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.GraalOptions; @@ -38,6 +42,7 @@ import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeMap; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; @@ -45,10 +50,6 @@ import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.Assumptions.Assumption; @@ -169,6 +170,7 @@ private final OptionValues options; private Cancellable cancellable = null; private final DebugContext debug; + private NodeSourcePosition callerContext; /** * Creates a builder for a graph. @@ -255,8 +257,13 @@ return this; } + public Builder callerContext(NodeSourcePosition context) { + this.callerContext = context; + return this; + } + public StructuredGraph build() { - return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable); + return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable, callerContext); } } @@ -284,6 +291,13 @@ private ScheduleResult lastSchedule; + private final InliningLog inliningLog; + + /** + * Call stack (context) leading to construction of this graph. + */ + private final NodeSourcePosition callerContext; + /** * Records the methods that were used while constructing this graph, one entry for each time a * specific method is used. @@ -317,7 +331,8 @@ CompilationIdentifier compilationId, OptionValues options, DebugContext debug, - Cancellable cancellable) { + Cancellable cancellable, + NodeSourcePosition context) { super(name, options, debug); this.setStart(add(new StartNode())); this.rootMethod = method; @@ -328,6 +343,8 @@ this.speculationLog = speculationLog; this.useProfilingInfo = useProfilingInfo; this.cancellable = cancellable; + this.inliningLog = new InliningLog(); + this.callerContext = context; } public void setLastSchedule(ScheduleResult result) { @@ -436,6 +453,10 @@ this.start = start; } + public InliningLog getInliningLog() { + return inliningLog; + } + /** * Creates a copy of this graph. * @@ -459,7 +480,7 @@ speculationLog, useProfilingInfo, newCompilationId, - getOptions(), debugForCopy, null); + getOptions(), debugForCopy, null, callerContext); if (allowAssumptions == AllowAssumptions.YES && assumptions != null) { copy.assumptions.record(assumptions); } @@ -931,4 +952,8 @@ protected void afterRegister(Node node) { assert hasValueProxies() || !(node instanceof ValueProxyNode); } + + public NodeSourcePosition getCallerContext() { + return callerContext; + } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,7 +25,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; -import jdk.vm.ci.meta.MetaAccessProvider; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; @@ -42,17 +42,18 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; -import org.graalvm.compiler.options.OptionValues; @NodeInfo(cycles = CYCLES_1) public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary { public static final NodeClass TYPE = NodeClass.create(CompareNode.class); - protected final Condition condition; + protected final CanonicalCondition condition; protected final boolean unorderedIsTrue; /** @@ -61,7 +62,7 @@ * @param x the instruction producing the first input to the instruction * @param y the instruction that produces the second input to this instruction */ - protected CompareNode(NodeClass c, Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) { + protected CompareNode(NodeClass c, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) { super(c, x, y); this.condition = condition; this.unorderedIsTrue = unorderedIsTrue; @@ -72,7 +73,7 @@ * * @return the condition */ - public final Condition condition() { + public final CanonicalCondition condition() { return condition; } @@ -85,7 +86,7 @@ return this.unorderedIsTrue; } - public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { + public static LogicNode tryConstantFold(CanonicalCondition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { if (forX.isConstant() && forY.isConstant() && (constantReflection != null || forX.asConstant() instanceof PrimitiveConstant)) { return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue)); } @@ -93,7 +94,7 @@ } @SuppressWarnings("unused") - public static LogicNode tryConstantFoldPrimitive(Condition condition, ValueNode forX, ValueNode forY, boolean unorderedIsTrue, NodeView view) { + public static LogicNode tryConstantFoldPrimitive(CanonicalCondition condition, ValueNode forX, ValueNode forY, boolean unorderedIsTrue, NodeView view) { if (forX.asConstant() instanceof PrimitiveConstant && forY.asConstant() instanceof PrimitiveConstant) { return LogicConstantNode.forBoolean(condition.foldCondition((PrimitiveConstant) forX.asConstant(), (PrimitiveConstant) forY.asConstant(), unorderedIsTrue)); } @@ -107,11 +108,11 @@ * @return true for identity comparisons */ public boolean isIdentityComparison() { - return condition == Condition.EQ; + return condition == CanonicalCondition.EQ; } public abstract static class CompareOp { - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { LogicNode constantCondition = tryConstantFold(condition, forX, forY, constantReflection, unorderedIsTrue); if (constantCondition != null) { @@ -151,9 +152,13 @@ } protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, - Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { + CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { if (nonConstant instanceof ConditionalNode) { - return optimizeConditional(constant, (ConditionalNode) nonConstant, constantReflection, mirrored ? condition.mirror() : condition, unorderedIsTrue); + Condition realCondition = condition.asCondition(); + if (mirrored) { + realCondition = realCondition.mirror(); + } + return optimizeConditional(constant, (ConditionalNode) nonConstant, constantReflection, realCondition, unorderedIsTrue); } else if (nonConstant instanceof NormalizeCompareNode) { return optimizeNormalizeCompare(constantReflection, metaAccess, options, smallestCompareWidth, constant, (NormalizeCompareNode) nonConstant, mirrored, view); } else if (nonConstant instanceof ConvertNode) { @@ -186,7 +191,7 @@ return null; } - private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Condition condition, + private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, CanonicalCondition condition, ConvertNode convert, Constant constant, NodeView view) { if (convert.preservesOrder(condition, constant, constantReflection)) { Constant reverseConverted = convert.reverse(constant, constantReflection); @@ -235,18 +240,17 @@ protected abstract LogicNode duplicateModified(ValueNode newW, ValueNode newY, boolean unorderedIsTrue, NodeView view); } - public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) { + public static LogicNode createCompareNode(StructuredGraph graph, CanonicalCondition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) { LogicNode result = createCompareNode(condition, x, y, constantReflection, view); return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result); } - public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) { + public static LogicNode createCompareNode(CanonicalCondition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) { assert x.getStackKind() == y.getStackKind(); - assert condition.isCanonical(); assert !x.getStackKind().isNumericFloat(); LogicNode comparison; - if (condition == Condition.EQ) { + if (condition == CanonicalCondition.EQ) { if (x.stamp(view) instanceof AbstractObjectStamp) { comparison = ObjectEqualsNode.create(x, y, constantReflection, view); } else if (x.stamp(view) instanceof AbstractPointerStamp) { @@ -255,11 +259,11 @@ assert x.getStackKind().isNumericInteger(); comparison = IntegerEqualsNode.create(x, y, view); } - } else if (condition == Condition.LT) { + } else if (condition == CanonicalCondition.LT) { assert x.getStackKind().isNumericInteger(); comparison = IntegerLessThanNode.create(x, y, view); } else { - assert condition == Condition.BT; + assert condition == CanonicalCondition.BT; assert x.getStackKind().isNumericInteger(); comparison = IntegerBelowNode.create(x, y, view); } @@ -268,19 +272,18 @@ } public static LogicNode createCompareNode(StructuredGraph graph, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, - Condition condition, ValueNode x, ValueNode y, NodeView view) { + CanonicalCondition condition, ValueNode x, ValueNode y, NodeView view) { LogicNode result = createCompareNode(constantReflection, metaAccess, options, smallestCompareWidth, condition, x, y, view); return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result); } public static LogicNode createCompareNode(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, - Condition condition, ValueNode x, ValueNode y, NodeView view) { + CanonicalCondition condition, ValueNode x, ValueNode y, NodeView view) { assert x.getStackKind() == y.getStackKind(); - assert condition.isCanonical(); assert !x.getStackKind().isNumericFloat(); LogicNode comparison; - if (condition == Condition.EQ) { + if (condition == CanonicalCondition.EQ) { if (x.stamp(view) instanceof AbstractObjectStamp) { assert smallestCompareWidth == null; comparison = ObjectEqualsNode.create(constantReflection, metaAccess, options, x, y, view); @@ -290,11 +293,11 @@ assert x.getStackKind().isNumericInteger(); comparison = IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view); } - } else if (condition == Condition.LT) { + } else if (condition == CanonicalCondition.LT) { assert x.getStackKind().isNumericInteger(); comparison = IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view); } else { - assert condition == Condition.BT; + assert condition == CanonicalCondition.BT; assert x.getStackKind().isNumericInteger(); comparison = IntegerBelowNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,7 +26,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -268,7 +268,7 @@ generator.emitConditional(this); } - public ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) { + public ConditionalNode(StructuredGraph graph, CanonicalCondition condition, ValueNode x, ValueNode y) { this(createCompareNode(graph, condition, x, y, null, NodeView.DEFAULT)); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.nodes.calc; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValueNodeInterface; @@ -61,7 +61,7 @@ * @param op a comparison operator * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2 */ - default boolean preservesOrder(Condition op) { + default boolean preservesOrder(CanonicalCondition op) { return isLossless(); } @@ -73,7 +73,7 @@ * @param constantReflection * @return true iff (c1 op value) == (convert(c1) op convert(value)) for value and all c1 */ - default boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) { + default boolean preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection) { return preservesOrder(op); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,10 +22,9 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.core.common.calc.Condition; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; + +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -42,7 +41,9 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.TriState; @NodeInfo(shortName = "==", cycles = CYCLES_2) public final class FloatEqualsNode extends CompareNode implements BinaryCommutative { @@ -50,13 +51,13 @@ private static final FloatEqualsOp OP = new FloatEqualsOp(); public FloatEqualsNode(ValueNode x, ValueNode y) { - super(TYPE, Condition.EQ, false, x, y); + super(TYPE, CanonicalCondition.EQ, false, x, y); assert x.stamp(NodeView.DEFAULT) instanceof FloatStamp && y.stamp(NodeView.DEFAULT) instanceof FloatStamp : x.stamp(NodeView.DEFAULT) + " " + y.stamp(NodeView.DEFAULT); assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT)); } public static LogicNode create(ValueNode x, ValueNode y, NodeView view) { - LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false, view); + LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.EQ, x, y, false, view); if (result != null) { return result; } else { @@ -66,7 +67,7 @@ public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y, NodeView view) { - LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y, view); + LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.EQ, false, x, y, view); if (value != null) { return value; } @@ -89,7 +90,7 @@ @Override public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { NodeView view = NodeView.from(tool); - ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, unorderedIsTrue, forX, forY, view); + ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, unorderedIsTrue, forX, forY, view); if (value != null) { return value; } @@ -99,7 +100,7 @@ public static class FloatEqualsOp extends CompareOp { @Override - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view); if (result != null) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,10 +22,9 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.core.common.calc.Condition; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; + +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -41,7 +40,9 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.TriState; @NodeInfo(shortName = "<", cycles = CYCLES_2) public final class FloatLessThanNode extends CompareNode { @@ -49,13 +50,13 @@ private static final FloatLessThanOp OP = new FloatLessThanOp(); public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) { - super(TYPE, Condition.LT, unorderedIsTrue, x, y); + super(TYPE, CanonicalCondition.LT, unorderedIsTrue, x, y); assert x.stamp(NodeView.DEFAULT) instanceof FloatStamp && y.stamp(NodeView.DEFAULT) instanceof FloatStamp; assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT)); } public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue, NodeView view) { - LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.LT, x, y, unorderedIsTrue, view); + LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.LT, x, y, unorderedIsTrue, view); if (result != null) { return result; } @@ -64,7 +65,7 @@ public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y, boolean unorderedIsTrue, NodeView view) { - LogicNode result = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.LT, unorderedIsTrue, x, y, view); + LogicNode result = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.LT, unorderedIsTrue, x, y, view); if (result != null) { return result; } @@ -74,7 +75,7 @@ @Override public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { NodeView view = NodeView.from(tool); - ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.LT, unorderedIsTrue, forX, forY, view); + ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.LT, unorderedIsTrue, forX, forY, view); if (value != null) { return value; } @@ -84,7 +85,7 @@ public static class FloatLessThanOp extends CompareOp { @Override - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view); if (result != null) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,10 +22,8 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; import org.graalvm.compiler.core.common.NumUtil; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; @@ -35,9 +33,11 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.CodeUtil; -import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; @NodeInfo(shortName = "|<|") public final class IntegerBelowNode extends IntegerLowerThanNode { @@ -126,8 +126,8 @@ } @Override - protected Condition getCondition() { - return Condition.BT; + protected CanonicalCondition getCondition() { + return CanonicalCondition.BT; } @Override diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,9 +22,7 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; @@ -42,12 +40,14 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.options.OptionValues; @NodeInfo(shortName = "==") public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative { @@ -55,13 +55,13 @@ private static final IntegerEqualsOp OP = new IntegerEqualsOp(); public IntegerEqualsNode(ValueNode x, ValueNode y) { - super(TYPE, Condition.EQ, false, x, y); + super(TYPE, CanonicalCondition.EQ, false, x, y); assert !x.getStackKind().isNumericFloat() && x.getStackKind() != JavaKind.Object; assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object; } public static LogicNode create(ValueNode x, ValueNode y, NodeView view) { - LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false, view); + LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.EQ, x, y, false, view); if (result != null) { return result; } @@ -87,7 +87,7 @@ public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y, NodeView view) { - LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y, view); + LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.EQ, false, x, y, view); if (value != null) { return value; } @@ -97,7 +97,7 @@ @Override public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { NodeView view = NodeView.from(tool); - ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view); + ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view); if (value != null) { return value; } @@ -149,7 +149,7 @@ } @Override - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return LogicConstantNode.tautology(); @@ -186,7 +186,7 @@ @Override protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, - Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { + CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { if (constant instanceof PrimitiveConstant) { PrimitiveConstant primitiveConstant = (PrimitiveConstant) constant; IntegerStamp nonConstantStamp = ((IntegerStamp) nonConstant.stamp(view)); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,12 +22,10 @@ */ package org.graalvm.compiler.nodes.calc; -import static org.graalvm.compiler.core.common.calc.Condition.LT; +import static org.graalvm.compiler.core.common.calc.CanonicalCondition.LT; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; import org.graalvm.compiler.core.common.NumUtil; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.FloatStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -42,13 +40,15 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; -import org.graalvm.compiler.options.OptionValues; @NodeInfo(shortName = "<") public final class IntegerLessThanNode extends IntegerLowerThanNode { @@ -258,7 +258,7 @@ } @Override - protected Condition getCondition() { + protected CanonicalCondition getCondition() { return LT; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,9 +22,7 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; @@ -36,9 +34,11 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.options.OptionValues; /** * Common super-class for "a < b" comparisons both {@linkplain IntegerLowerThanNode signed} and @@ -117,7 +117,7 @@ public abstract static class LowerOp extends CompareOp { @Override - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view); if (result != null) { @@ -156,7 +156,7 @@ protected abstract IntegerStamp forInteger(int bits, long min, long max); - protected abstract Condition getCondition(); + protected abstract CanonicalCondition getCondition(); protected abstract IntegerLowerThanNode createNode(ValueNode x, ValueNode y); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -112,9 +112,9 @@ // ==> sxxx -(sign-extend)-> sssssxxx return SignExtendNode.create(other.getValue(), other.getInputBits(), getResultBits(), view); } else if (other instanceof ZeroExtendNode) { - // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx + // xxxx -(zero-extend)-> 00000000 0000xxxx -(narrow)-> 0000xxxx // ==> xxxx -(zero-extend)-> 0000xxxx - return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits()); + return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits(), ((ZeroExtendNode) other).isInputAlwaysPositive()); } } } else if (forValue instanceof AndNode) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.IterableNodeType; @@ -67,10 +67,10 @@ } protected static ValueNode tryConstantFold(ValueNode x, ValueNode y, boolean isUnorderedLess, JavaKind kind, ConstantReflectionProvider constantReflection) { - LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, null, false); + LogicNode result = CompareNode.tryConstantFold(CanonicalCondition.EQ, x, y, null, false); if (result instanceof LogicConstantNode) { LogicConstantNode logicConstantNode = (LogicConstantNode) result; - LogicNode resultLT = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, isUnorderedLess); + LogicNode resultLT = CompareNode.tryConstantFold(CanonicalCondition.LT, x, y, constantReflection, isUnorderedLess); if (resultLT instanceof LogicConstantNode) { LogicConstantNode logicConstantNodeLT = (LogicConstantNode) resultLT; if (logicConstantNodeLT.getValue()) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,7 @@ */ package org.graalvm.compiler.nodes.calc; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; @@ -42,6 +42,7 @@ import org.graalvm.compiler.nodes.spi.VirtualizerTool; import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -49,7 +50,6 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; -import org.graalvm.compiler.options.OptionValues; @NodeInfo(shortName = "==") public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable { @@ -64,7 +64,7 @@ } public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) { - LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + LogicNode result = CompareNode.tryConstantFold(CanonicalCondition.EQ, x, y, constantReflection, false); if (result != null) { return result; } else { @@ -77,7 +77,7 @@ } public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, ValueNode x, ValueNode y, NodeView view) { - LogicNode result = OP.canonical(constantReflection, metaAccess, options, null, Condition.EQ, false, x, y, view); + LogicNode result = OP.canonical(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, false, x, y, view); if (result != null) { return result; } @@ -87,7 +87,7 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { NodeView view = NodeView.from(tool); - ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view); + ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view); if (value != null) { return value; } @@ -98,7 +98,7 @@ @Override protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, - Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { + CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) { ResolvedJavaType type = constantReflection.asJavaType(constant); if (type != null && nonConstant instanceof GetClassNode) { GetClassNode getClassNode = (GetClassNode) nonConstant; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,9 +22,7 @@ */ package org.graalvm.compiler.nodes.calc; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -41,11 +39,13 @@ import org.graalvm.compiler.nodes.extended.LoadMethodNode; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.TriState; -import org.graalvm.compiler.options.OptionValues; @NodeInfo(shortName = "==") public class PointerEqualsNode extends CompareNode implements BinaryCommutative { @@ -66,7 +66,7 @@ } protected PointerEqualsNode(NodeClass c, ValueNode x, ValueNode y) { - super(c, Condition.EQ, false, x, y); + super(c, CanonicalCondition.EQ, false, x, y); assert x.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp; assert y.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp; } @@ -74,7 +74,7 @@ @Override public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { NodeView view = NodeView.from(tool); - ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view); + ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view); if (value != null) { return value; } @@ -88,9 +88,9 @@ * could select a certain method and if so, returns {@code true} if the answer is guaranteed * to be false. Otherwise, returns {@code false}. */ - private static boolean isAlwaysFailingVirtualDispatchTest(Condition condition, ValueNode forX, ValueNode forY) { + private static boolean isAlwaysFailingVirtualDispatchTest(CanonicalCondition condition, ValueNode forX, ValueNode forY) { if (forY.isConstant()) { - if (forX instanceof LoadMethodNode && condition == Condition.EQ) { + if (forX instanceof LoadMethodNode && condition == CanonicalCondition.EQ) { LoadMethodNode lm = ((LoadMethodNode) forX); if (lm.getMethod().getEncoding().equals(forY.asConstant())) { if (lm.getHub() instanceof LoadHubNode) { @@ -112,7 +112,7 @@ } @Override - public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition, + public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { LogicNode result = findSynonym(forX, forY, view); if (result != null) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -95,7 +95,7 @@ if (other.getResultBits() > other.getInputBits()) { // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx // ==> sxxx -(zero-extend)-> 00000000 0000sxxx - return ZeroExtendNode.create(other.getValue(), other.getInputBits(), resultBits, view); + return ZeroExtendNode.create(other.getValue(), other.getInputBits(), resultBits, view, other.isInputAlwaysPositive()); } } @@ -104,7 +104,7 @@ if ((inputStamp.upMask() & (1L << (inputBits - 1))) == 0L) { // 0xxx -(sign-extend)-> 0000 0xxx // ==> 0xxx -(zero-extend)-> 0000 0xxx - return ZeroExtendNode.create(forValue, inputBits, resultBits, view); + return ZeroExtendNode.create(forValue, inputBits, resultBits, view, true); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow; @@ -50,26 +50,33 @@ public static final NodeClass TYPE = NodeClass.create(ZeroExtendNode.class); + private final boolean inputAlwaysPositive; + public ZeroExtendNode(ValueNode input, int resultBits) { - this(input, PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)), resultBits); + this(input, PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)), resultBits, false); assert 0 < PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)) && PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)) <= resultBits; } - public ZeroExtendNode(ValueNode input, int inputBits, int resultBits) { + public ZeroExtendNode(ValueNode input, int inputBits, int resultBits, boolean inputAlwaysPositive) { super(TYPE, ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input); + this.inputAlwaysPositive = inputAlwaysPositive; } public static ValueNode create(ValueNode input, int resultBits, NodeView view) { - return create(input, PrimitiveStamp.getBits(input.stamp(view)), resultBits, view); + return create(input, PrimitiveStamp.getBits(input.stamp(view)), resultBits, view, false); } public static ValueNode create(ValueNode input, int inputBits, int resultBits, NodeView view) { + return create(input, inputBits, resultBits, view, false); + } + + public static ValueNode create(ValueNode input, int inputBits, int resultBits, NodeView view, boolean alwaysPositive) { IntegerConvertOp signExtend = ArithmeticOpTable.forStamp(input.stamp(view)).getZeroExtend(); ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp(view))); if (synonym != null) { return synonym; } - return canonical(null, input, inputBits, resultBits, view); + return canonical(null, input, inputBits, resultBits, view, alwaysPositive); } @Override @@ -77,12 +84,13 @@ return true; } + public boolean isInputAlwaysPositive() { + return inputAlwaysPositive; + } + @Override - public boolean preservesOrder(Condition cond) { + public boolean preservesOrder(CanonicalCondition cond) { switch (cond) { - case GE: - case GT: - case LE: case LT: return false; default: @@ -98,16 +106,16 @@ return ret; } - return canonical(this, forValue, getInputBits(), getResultBits(), view); + return canonical(this, forValue, getInputBits(), getResultBits(), view, inputAlwaysPositive); } - private static ValueNode canonical(ZeroExtendNode zeroExtendNode, ValueNode forValue, int inputBits, int resultBits, NodeView view) { + private static ValueNode canonical(ZeroExtendNode zeroExtendNode, ValueNode forValue, int inputBits, int resultBits, NodeView view, boolean alwaysPositive) { ZeroExtendNode self = zeroExtendNode; if (forValue instanceof ZeroExtendNode) { // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx // ==> xxxx -(zero-extend)-> 00000000 0000xxxx ZeroExtendNode other = (ZeroExtendNode) forValue; - return new ZeroExtendNode(other.getValue(), other.getInputBits(), resultBits); + return new ZeroExtendNode(other.getValue(), other.getInputBits(), resultBits, other.isInputAlwaysPositive()); } if (forValue instanceof NarrowNode) { NarrowNode narrow = (NarrowNode) forValue; @@ -135,7 +143,7 @@ } if (self == null) { - self = new ZeroExtendNode(forValue, inputBits, resultBits); + self = new ZeroExtendNode(forValue, inputBits, resultBits, alwaysPositive); } return self; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java Sat Feb 10 09:25:35 2018 +0100 @@ -42,7 +42,6 @@ import org.graalvm.word.LocationIdentity; public final class Block extends AbstractBlockBase { - public static final Block[] EMPTY_ARRAY = new Block[0]; protected final AbstractBeginNode beginNode; @@ -53,7 +52,6 @@ private Loop loop; protected Block postdominator; - protected Block distancedDominatorCache; private LocationSet killLocations; private LocationSet killLocationsBetweenThisAndDominator; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.nodes.extended; + +import org.graalvm.compiler.graph.NodeInterface; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.memory.address.AddressNode; + +public interface ArrayRangeWrite extends NodeInterface { + AddressNode getAddress(); + + /** + * The length of the modified range. + */ + ValueNode getLength(); + + /** + * Return true if the written array is an object array, false if it is a primitive array. + */ + boolean writesObjectArray(); + + /** + * Returns whether this write is the initialization of the written location. If it is true, the + * old value of the memory location is either uninitialized or zero. If it is false, the memory + * location is guaranteed to contain a valid value or zero. + */ + boolean isInitialization(); + + int getElementStride(); + + @Override + FixedWithNextNode asNode(); +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package org.graalvm.compiler.nodes.extended; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; - -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; - -/** - * Base class for nodes that modify a range of an array. - */ -@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) -public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint { - - public static final NodeClass TYPE = NodeClass.create(ArrayRangeWriteNode.class); - - protected ArrayRangeWriteNode(NodeClass c, Stamp stamp) { - super(c, stamp); - } - - /** - * The array that is written to. - */ - public abstract ValueNode getArray(); - - /** - * The first modified index. - */ - public abstract ValueNode getIndex(); - - /** - * The length of the modified range. - */ - public abstract ValueNode getLength(); - - /** - * Return true if the written array is an object array, false if it is a primitive array. - */ - public abstract boolean isObjectArray(); - - /** - * Returns whether this write is the initialization of the written location. If it is true, the - * old value of the memory location is either uninitialized or zero. If it is false, the memory - * location is guaranteed to contain a valid value or zero. - */ - public abstract boolean isInitialization(); -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,7 +25,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.iterators.NodePredicates; @@ -101,7 +101,7 @@ } boolean usageFound = false; for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) { - assert node.condition() == Condition.EQ; + assert node.condition() == CanonicalCondition.EQ; ValueNode other = node.getX(); if (node.getX() == this) { other = node.getY(); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -97,7 +97,7 @@ ValueNode offsetValue = tool.getAlias(offset()); if (offsetValue.isConstant()) { long off = offsetValue.asJavaConstant().asLong(); - int entryIndex = virtual.entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind()); if (entryIndex != -1) { ValueNode entry = tool.getEntry(virtual, entryIndex); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -119,7 +119,7 @@ ValueNode indexValue = tool.getAlias(offset()); if (indexValue.isConstant()) { long off = indexValue.asJavaConstant().asLong(); - int entryIndex = virtual.entryIndexForOffset(off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind()); if (entryIndex != -1 && tool.setVirtualEntry(virtual, entryIndex, value(), accessKind(), off)) { tool.delete(); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -228,7 +228,7 @@ @Override public AbstractBeginNode getPrimarySuccessor() { - return this.defaultSuccessor(); + return null; } /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java Sat Feb 10 09:25:35 2018 +0100 @@ -82,6 +82,10 @@ return methodToInline; } + public boolean allowsInlining() { + return methodToInline != null; + } + /** * Gets the provider of bytecode to be parsed for {@link #getMethodToInline()} if is is an * intrinsic for the original method (i.e., the {@code method} passed to diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Sat Feb 10 09:25:35 2018 +0100 @@ -35,6 +35,12 @@ import java.util.List; import java.util.Map; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.Pair; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry; import org.graalvm.compiler.bytecode.BytecodeProvider; @@ -44,12 +50,6 @@ import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; -import org.graalvm.util.Pair; -import org.graalvm.util.UnmodifiableEconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -112,6 +112,26 @@ } /** + * A symbol for an already resolved method. + */ + public static class ResolvedJavaSymbol implements Type { + private final ResolvedJavaType resolved; + + public ResolvedJavaSymbol(ResolvedJavaType type) { + this.resolved = type; + } + + public ResolvedJavaType getResolved() { + return resolved; + } + + @Override + public String toString() { + return resolved.toJavaName(); + } + } + + /** * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}. */ static class OptionalLazySymbol implements Type { @@ -696,7 +716,7 @@ * * @param declaringClass the class to test */ - protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) { + public boolean canBeIntrinsified(ResolvedJavaType declaringClass) { return true; } @@ -1150,6 +1170,9 @@ } static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) { + if (declaringType instanceof ResolvedJavaSymbol) { + return checkResolvable(isOptional, ((ResolvedJavaSymbol) declaringType).getResolved(), binding); + } Class declaringClass = InvocationPlugins.resolveType(declaringType, isOptional); if (declaringClass == null) { return true; @@ -1165,6 +1188,13 @@ } return true; } + + private static boolean checkResolvable(boolean isOptional, ResolvedJavaType declaringType, Binding binding) { + if (resolveJavaMethod(declaringType, binding) == null && !isOptional) { + throw new AssertionError(String.format("Method not found: %s.%s%s", declaringType.toJavaName(), binding.name, binding.argumentsDescriptor)); + } + return true; + } } /** @@ -1235,7 +1265,7 @@ * {@link NoSuchMethodError} is thrown. * * @param declaringClass the class to search for a method matching {@code binding} - * @return the method (if any) in {@code declaringClass} matching binding + * @return the method (if any) in {@code declaringClass} matching {@code binding} */ public static Method resolveMethod(Class declaringClass, Binding binding) { if (binding.name.equals("")) { @@ -1243,32 +1273,70 @@ } Method[] methods = declaringClass.getDeclaredMethods(); List parameterTypeNames = parseParameters(binding.argumentsDescriptor); + Method match = null; for (int i = 0; i < methods.length; ++i) { Method m = methods[i]; - if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && m.getName().equals(binding.name)) { - if (parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) { - for (int j = i + 1; j < methods.length; ++j) { - Method other = methods[j]; - if (binding.isStatic == Modifier.isStatic(other.getModifiers()) && other.getName().equals(binding.name)) { - if (parameterTypeNames.equals(toInternalTypeNames(other.getParameterTypes()))) { - if (m.getReturnType().isAssignableFrom(other.getReturnType())) { - // `other` has a more specific return type - choose it - // (m is most likely a bridge method) - m = other; - } else { - if (!other.getReturnType().isAssignableFrom(m.getReturnType())) { - throw new NoSuchMethodError(String.format( - "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", m, other)); - } - } - } - } + if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && + m.getName().equals(binding.name) && + parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) { + if (match == null) { + match = m; + } else if (match.getReturnType().isAssignableFrom(m.getReturnType())) { + // `m` has a more specific return type - choose it + // (`match` is most likely a bridge method) + match = m; + } else { + if (!m.getReturnType().isAssignableFrom(match.getReturnType())) { + throw new NoSuchMethodError(String.format( + "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m)); } + } + } + } + return match; + } + + /** + * Same as {@link #resolveMethod(Class, Binding)} and + * {@link #resolveConstructor(Class, Binding)} except in terms of {@link ResolvedJavaType} and + * {@link ResolvedJavaMethod}. + */ + public static ResolvedJavaMethod resolveJavaMethod(ResolvedJavaType declaringClass, Binding binding) { + ResolvedJavaMethod[] methods = declaringClass.getDeclaredMethods(); + if (binding.name.equals("")) { + for (ResolvedJavaMethod m : methods) { + if (m.getName().equals("") && m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) { return m; } } + return null; } - return null; + + ResolvedJavaMethod match = null; + for (int i = 0; i < methods.length; ++i) { + ResolvedJavaMethod m = methods[i]; + if (binding.isStatic == m.isStatic() && + m.getName().equals(binding.name) && + m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) { + if (match == null) { + match = m; + } else { + final ResolvedJavaType matchReturnType = (ResolvedJavaType) match.getSignature().getReturnType(declaringClass); + final ResolvedJavaType mReturnType = (ResolvedJavaType) m.getSignature().getReturnType(declaringClass); + if (matchReturnType.isAssignableFrom(mReturnType)) { + // `m` has a more specific return type - choose it + // (`match` is most likely a bridge method) + match = m; + } else { + if (!mReturnType.isAssignableFrom(matchReturnType)) { + throw new NoSuchMethodError(String.format( + "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m)); + } + } + } + } + } + return match; } /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -39,10 +39,10 @@ import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.Value; -import sun.misc.Unsafe; /** - * Represents an atomic read-and-add operation like {@link Unsafe#getAndAddInt(Object, long, int)}. + * Represents an atomic read-and-add operation like + * {@link sun.misc.Unsafe#getAndAddInt(Object, long, int)}. */ @NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_2) public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -36,11 +36,10 @@ import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; -import sun.misc.Unsafe; /** - * Represents an atomic read-and-write operation like {@link Unsafe#getAndSetInt(Object, long, int)} - * . + * Represents an atomic read-and-write operation like + * {@link sun.misc.Unsafe#getAndSetInt(Object, long, int)}. */ @NodeInfo(cycles = CYCLES_8, size = SIZE_2) public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -125,6 +125,13 @@ } @NodeIntrinsic + private static native Object newArray(Class componentType, int length, @ConstantNodeParameter boolean fillContents); + + public static Object newArray(Class componentType, int length) { + return newArray(componentType, length, true); + } + + @NodeIntrinsic private static native Object newArray(Class componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter JavaKind knownElementKind); public static Object newArray(Class componentType, int length, JavaKind knownElementKind) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -42,11 +42,10 @@ import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.Value; -import sun.misc.Unsafe; /** * Represents the lowered version of an atomic read-and-write operation like - * {@link Unsafe#getAndSetInt(Object, long, int)} . + * {@link sun.misc.Unsafe#getAndSetInt(Object, long, int)}. */ @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_8, size = SIZE_2) public final class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerableAccess, MemoryCheckpoint.Single { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import java.util.Collections; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -132,7 +132,7 @@ // Should be areFrameStatesAtSideEffects but currently SVM will complain about // RuntimeConstraint if (graph().getGuardsStage().allowsFloatingGuards()) { - LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), Condition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view); + LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), CanonicalCondition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view); // we do not have a non-deopting path for that at the moment so action=None. FixedGuardNode guard = graph().add(new FixedGuardNode(lengthNegativeCondition, DeoptimizationReason.RuntimeConstraint, DeoptimizationAction.None, true)); graph().replaceFixedWithFixed(this, guard); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -32,6 +32,9 @@ import java.util.Collection; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeInputList; @@ -41,9 +44,6 @@ import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; import org.graalvm.word.LocationIdentity; @NodeInfo(allowedUsageTypes = {Extension, Memory}, cycles = CYCLES_0, size = SIZE_0) diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.nodes.spi; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; @@ -31,7 +32,7 @@ /** * Provides a capability for replacing a higher node with one or more lower level nodes. */ -public interface LoweringProvider { +public interface LoweringProvider extends ArrayOffsetProvider { void lower(Node n, LoweringTool tool); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import java.util.List; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -56,6 +57,8 @@ */ ConstantReflectionProvider getConstantReflectionProvider(); + ArrayOffsetProvider getArrayOffsetProvider(); + /** * This method should be used to query the maximum size of virtualized objects before attempting * virtualization. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,10 @@ import java.util.List; import java.util.function.BiFunction; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.code.SourceStackTraceBailoutException; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; @@ -76,10 +80,6 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodePosition; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import java.nio.ByteOrder; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -35,7 +36,6 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaType; -import sun.misc.Unsafe; @NodeInfo(nameTemplate = "VirtualArray({p#objectId}) {p#componentType/s}[{p#length}]") public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider { @@ -88,53 +88,14 @@ } @Override - public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) { - return entryIndexForOffset(constantOffset, expectedEntryKind, componentType, length); + public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) { + return entryIndexForOffset(arrayOffsetProvider, constantOffset, expectedEntryKind, componentType, length); } - public static int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) { - int baseOffset; - int indexScale; - switch (componentType.getJavaKind()) { - case Boolean: - baseOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; - indexScale = Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; - break; - case Byte: - baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET; - indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE; - break; - case Short: - baseOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET; - indexScale = Unsafe.ARRAY_SHORT_INDEX_SCALE; - break; - case Char: - baseOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET; - indexScale = Unsafe.ARRAY_CHAR_INDEX_SCALE; - break; - case Int: - baseOffset = Unsafe.ARRAY_INT_BASE_OFFSET; - indexScale = Unsafe.ARRAY_INT_INDEX_SCALE; - break; - case Long: - baseOffset = Unsafe.ARRAY_LONG_BASE_OFFSET; - indexScale = Unsafe.ARRAY_LONG_INDEX_SCALE; - break; - case Float: - baseOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET; - indexScale = Unsafe.ARRAY_FLOAT_INDEX_SCALE; - break; - case Double: - baseOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET; - indexScale = Unsafe.ARRAY_DOUBLE_INDEX_SCALE; - break; - case Object: - baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET; - indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE; - break; - default: - return -1; - } + public static int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) { + int baseOffset = arrayOffsetProvider.arrayBaseOffset(componentType.getJavaKind()); + int indexScale = arrayOffsetProvider.arrayScalingFactor(componentType.getJavaKind()); + long offset; if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) { // On big endian, we expect the value to be correctly aligned in memory diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.nodes.virtual; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -100,7 +101,7 @@ } @Override - public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) { + public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) { return fieldIndex(type.findInstanceFieldWithOffset(constantOffset, expectedEntryKind)); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.graph.IterableNodeType; @@ -95,7 +96,7 @@ * @param expectedEntryKind Specifies which type is expected at this offset (Is important when * doing implicit casts, especially on big endian systems. */ - public abstract int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind); + public abstract int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind); /** * Returns the {@link JavaKind} of the entry at the given index. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import java.util.EnumSet; -import org.graalvm.util.EconomicMap; +import org.graalvm.collections.EconomicMap; public class EnumOptionKey> extends OptionKey { final Class enumClass; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,10 +24,10 @@ import java.util.concurrent.atomic.AtomicReference; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; /** * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,7 @@ import java.util.Formatter; -import org.graalvm.util.EconomicMap; +import org.graalvm.collections.EconomicMap; /** * A key for an option. The value for an option is obtained from an {@link OptionValues} object. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,10 +30,10 @@ import java.util.SortedMap; import java.util.TreeMap; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; /** * A context for obtaining values for {@link OptionKey}s. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,9 +28,9 @@ import java.util.List; import java.util.ServiceLoader; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.util.CollectionsUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; /** * This class contains methods for parsing Graal options and matching them against a set of diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,6 +33,15 @@ public class AddressLoweringPhase extends Phase { public abstract static class AddressLowering { + + @SuppressWarnings("unused") + public void preProcess(StructuredGraph graph) { + } + + @SuppressWarnings("unused") + public void postProcess(AddressNode lowered) { + } + public abstract AddressNode lower(ValueNode base, ValueNode offset); } @@ -45,11 +54,13 @@ @Override protected void run(StructuredGraph graph) { + lowering.preProcess(graph); for (Node node : graph.getNodes()) { AddressNode lowered; if (node instanceof OffsetAddressNode) { OffsetAddressNode address = (OffsetAddressNode) node; lowered = lowering.lower(address.getBase(), address.getOffset()); + lowering.postProcess(lowered); } else { continue; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,10 @@ import java.util.Deque; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.Pair; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; @@ -87,10 +91,6 @@ import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; -import org.graalvm.util.Pair; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.TriState; @@ -124,7 +124,11 @@ if (moveGuards) { cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies()); } - SchedulePhase.run(graph, SchedulingStrategy.EARLIEST, cfg); + try (DebugContext.Scope scheduleScope = graph.getDebug().scope(SchedulePhase.class)) { + SchedulePhase.run(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg); + } catch (Throwable t) { + throw graph.getDebug().handle(t); + } ScheduleResult r = graph.getLastSchedule(); blockToNodes = r.getBlockToNodesMap(); nodeToBlock = r.getNodeToBlockMap(); @@ -662,7 +666,7 @@ */ InputFilter v = new InputFilter(original); thisGuard.getCondition().applyInputs(v); - if (v.ok && foldGuard(thisGuard, pendingGuard, newStamp, rewireGuardFunction)) { + if (v.ok && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) { return true; } } @@ -670,19 +674,34 @@ return false; } - protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) { + protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, boolean outcome, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) { if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) { LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs(); + /* + * We have ...; guard(C1); guard(C2);... + * + * Where the first guard is `otherGuard` and the second one `thisGuard`. + * + * Depending on `outcome`, we have C2 => C1 or C2 => !C1. + * + * - If C2 => C1, `mustDeopt` below is false and we transform to ...; guard(C2); ... + * + * - If C2 => !C1, `mustDeopt` is true and we transform to ..; guard(C1); deopt; + */ GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> { - if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) { - otherGuard.setCondition(condition, thisGuard.isNegated()); + // `result` is `outcome`, `guard` is `otherGuard` + boolean mustDeopt = result == otherGuard.isNegated(); + if (rewireGuardFunction.rewire(guard, mustDeopt == thisGuard.isNegated(), innerGuardedValueStamp, newInput)) { + if (!mustDeopt) { + otherGuard.setCondition(condition, thisGuard.isNegated()); + } return true; } condition.safeDelete(); return false; }; // Move the later test up - return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer); + return rewireGuards(otherGuard, outcome, null, guardedValueStamp, rewirer); } return false; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,8 @@ import java.util.List; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.debug.DebugCloseable; -import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.spi.SimplifierTool; import org.graalvm.compiler.nodeinfo.InputType; @@ -46,6 +46,8 @@ import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.ProxyNode; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StaticDeoptimizingNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValuePhiNode; @@ -57,8 +59,6 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; /** * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their @@ -77,18 +77,16 @@ @SuppressWarnings("try") protected void run(final StructuredGraph graph, PhaseContext context) { assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies"; + assert !graph.getGuardsStage().areFrameStatesAtDeopts() : graph.getGuardsStage(); for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) { assert d.isAlive(); - // Can only aggressively move deoptimization point if their action implies that - // the deoptimization will not be triggered again. Example for such action is - // reprofiling or recompiling with less aggressive options. - if (d.action() != DeoptimizationAction.None) { - try (DebugCloseable closable = d.withNodeSourcePosition()) { - visitDeoptBegin(AbstractBeginNode.prevBegin(d), d.action(), d.reason(), d.getSpeculation(), graph, context != null ? context.getLowerer() : null); - } + if (d.getAction() == DeoptimizationAction.None) { + continue; } - + try (DebugCloseable closable = d.withNodeSourcePosition()) { + propagateFixed(d, d, context != null ? context.getLowerer() : null); + } } if (context != null) { @@ -154,71 +152,73 @@ ys = yPhi.valueAt(mergePredecessor).asConstant(); } if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) { - visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph(), context.getLowerer()); + propagateFixed(mergePredecessor, fixedGuard, context.getLowerer()); } } } - private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph, - LoweringProvider loweringProvider) { - if (deoptBegin.predecessor() instanceof AbstractBeginNode) { - /* - * Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization. - */ - visitDeoptBegin((AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph, loweringProvider); - return; - } + private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) { + Node current = from; + while (current != null) { + if (GraalOptions.GuardPriorities.getValue(from.getOptions()) && current instanceof FixedGuardNode) { + FixedGuardNode otherGuard = (FixedGuardNode) current; + if (otherGuard.computePriority().isHigherPriorityThan(deopt.computePriority())) { + moveAsDeoptAfter(otherGuard, deopt); + return; + } + } else if (current instanceof AbstractBeginNode) { + if (current instanceof AbstractMergeNode) { + AbstractMergeNode mergeNode = (AbstractMergeNode) current; + FixedNode next = mergeNode.next(); + while (mergeNode.isAlive()) { + AbstractEndNode end = mergeNode.forwardEnds().first(); + propagateFixed(end, deopt, loweringProvider); + } + assert next.isAlive(); + propagateFixed(next, deopt, loweringProvider); + return; + } else if (current.predecessor() instanceof IfNode) { + IfNode ifNode = (IfNode) current.predecessor(); + StructuredGraph graph = ifNode.graph(); + LogicNode conditionNode = ifNode.condition(); + boolean negateGuardCondition = current == ifNode.trueSuccessor(); + FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition)); + FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); + AbstractBeginNode survivingSuccessor; + if (negateGuardCondition) { + survivingSuccessor = ifNode.falseSuccessor(); + } else { + survivingSuccessor = ifNode.trueSuccessor(); + } + graph.removeSplitPropagate(ifNode, survivingSuccessor); - DebugContext debug = deoptBegin.getDebug(); - if (deoptBegin instanceof AbstractMergeNode) { - AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin; - debug.log("Visiting %s", mergeNode); - FixedNode next = mergeNode.next(); - while (mergeNode.isAlive()) { - AbstractEndNode end = mergeNode.forwardEnds().first(); - AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(end); - visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider); + Node newGuard = guard; + if (survivingSuccessor instanceof LoopExitNode) { + newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); + } + survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); + + graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor); + FixedNode next = pred.next(); + pred.setNext(guard); + guard.setNext(next); + SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider); + survivingSuccessor.simplify(simplifierTool); + return; + } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) { + assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start()); + moveAsDeoptAfter((AbstractBeginNode) current, deopt); + return; + } } - assert next.isAlive(); - AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(next); - visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider); - return; - } else if (deoptBegin.predecessor() instanceof IfNode) { - IfNode ifNode = (IfNode) deoptBegin.predecessor(); - LogicNode conditionNode = ifNode.condition(); - FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor())); - FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor(); - AbstractBeginNode survivingSuccessor; - if (deoptBegin == ifNode.trueSuccessor()) { - survivingSuccessor = ifNode.falseSuccessor(); - } else { - survivingSuccessor = ifNode.trueSuccessor(); - } - graph.removeSplitPropagate(ifNode, survivingSuccessor); + current = current.predecessor(); + } + } - Node newGuard = guard; - if (survivingSuccessor instanceof LoopExitNode) { - newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph); - } - survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard); - - debug.log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, survivingSuccessor); - FixedNode next = pred.next(); - pred.setNext(guard); - guard.setNext(next); - SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider); - survivingSuccessor.simplify(simplifierTool); - return; - } - - // We could not convert the control split - at least cut off control flow after the split. - FixedWithNextNode deoptPred = deoptBegin; - FixedNode next = deoptPred.next(); - - if (!(next instanceof DeoptimizeNode)) { - DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation)); - deoptPred.setNext(newDeoptNode); - assert deoptPred == newDeoptNode.predecessor(); + private static void moveAsDeoptAfter(FixedWithNextNode node, StaticDeoptimizingNode deopt) { + FixedNode next = node.next(); + if (next != deopt.asNode()) { + node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation()))); GraphUtil.killCFG(next); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,8 @@ */ package org.graalvm.compiler.phases.common; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.type.FloatStamp; @@ -70,8 +72,6 @@ import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; import org.graalvm.compiler.phases.tiers.LowTierContext; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.MetaAccessProvider; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,10 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.graph.Graph.NodeEventScope; @@ -67,10 +71,6 @@ import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.UnmodifiableMapCursor; import org.graalvm.word.LocationIdentity; public class FloatingReadPhase extends Phase { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import java.util.List; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -40,7 +41,6 @@ import org.graalvm.compiler.phases.Phase; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.BytecodeFrame; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -120,7 +120,7 @@ @Override protected void run(StructuredGraph graph, MidTierContext context) { if (graph.getGuardsStage().allowsFloatingGuards()) { - SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST); + SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); schedulePhase.apply(graph); ScheduleResult schedule = graph.getLastSchedule(); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,9 @@ */ package org.graalvm.compiler.phases.common; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.graph.NodeStack; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractDeoptimizeNode; @@ -32,9 +35,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.MapCursor; /** * This phase will make sure that the branch leading towards this deopt has 0.0 probability. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -50,6 +50,9 @@ import org.graalvm.compiler.nodes.memory.FixedAccessNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.tiers.LowTierContext; @@ -64,16 +67,24 @@ private static final CounterKey counterTrappingNullCheckUnreached = DebugContext.counter("TrappingNullCheckUnreached"); private static final CounterKey counterTrappingNullCheckDynamicDeoptimize = DebugContext.counter("TrappingNullCheckDynamicDeoptimize"); + public static class Options { + + // @formatter:off + @Option(help = "Use traps for null checks instead of explicit null-checks", type = OptionType.Expert) + public static final OptionKey UseTrappingNullChecks = new OptionKey<>(true); + // @formatter:on + } + @Override protected void run(StructuredGraph graph, LowTierContext context) { - if (context.getTarget().implicitNullCheckLimit <= 0) { + if (!Options.UseTrappingNullChecks.getValue(graph.getOptions()) || context.getTarget().implicitNullCheckLimit <= 0) { return; } assert graph.getGuardsStage().areFrameStatesAtDeopts(); long implicitNullCheckLimit = context.getTarget().implicitNullCheckLimit; for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.TYPE)) { - tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation(), implicitNullCheckLimit); + tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.getReason(), deopt.getSpeculation(), implicitNullCheckLimit); } for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.TYPE)) { tryUseTrappingNullCheck(context.getMetaAccess(), deopt, implicitNullCheckLimit); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,6 +33,11 @@ import java.util.Objects; import java.util.function.Consumer; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.Stamp; @@ -92,11 +97,6 @@ import org.graalvm.compiler.phases.common.inlining.info.InlineInfo; import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; import org.graalvm.compiler.phases.util.ValueMergeUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.meta.Assumptions; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.StructuredGraph; @@ -31,7 +32,6 @@ import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; import org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph; import org.graalvm.compiler.phases.tiers.HighTierContext; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,12 +22,12 @@ */ package org.graalvm.compiler.phases.common.inlining.info; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.Assumptions.AssumptionResult; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,11 +22,11 @@ */ package org.graalvm.compiler.phases.common.inlining.info; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.phases.common.inlining.info; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.StructuredGraph; @@ -30,7 +31,6 @@ import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,8 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -54,8 +56,6 @@ import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationAction; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,7 +22,8 @@ */ package org.graalvm.compiler.phases.common.inlining.info; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.collections.EconomicSet; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.ConstantNode; @@ -37,7 +38,6 @@ import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.DeoptimizationAction; import jdk.vm.ci.meta.DeoptimizationReason; @@ -114,7 +114,7 @@ LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver)); ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(NodeView.DEFAULT), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph); - LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT); + LogicNode typeCheck = CompareNode.createCompareNode(graph, CanonicalCondition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT); FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); assert invoke.predecessor() != null; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,8 @@ import java.util.LinkedList; import java.util.function.ToDoubleFunction; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.ParameterNode; @@ -33,8 +35,6 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.phases.common.inlining.policy.AbstractInliningPolicy; import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicSet; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,8 @@ import java.util.ArrayList; import java.util.function.ToDoubleFunction; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeWorkList; @@ -43,8 +45,6 @@ import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.common.inlining.InliningUtil; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; public class ComputeInliningRelevance { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,8 @@ import java.util.LinkedList; import java.util.List; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; @@ -64,8 +66,6 @@ import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.Assumptions.AssumptionResult; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,12 +26,12 @@ import java.util.HashSet; import java.util.Set; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.graph.Graph.NodeEvent; import org.graalvm.compiler.graph.Graph.NodeEventListener; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Node.IndirectCanonicalization; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicSet; /** * A simple {@link NodeEventListener} implementation that accumulates event nodes in a diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,12 @@ */ package org.graalvm.compiler.phases.graph; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; + import java.util.function.ToDoubleFunction; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; @@ -36,10 +40,6 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StartNode; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; - -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; /** * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,8 @@ import java.util.Deque; import java.util.Set; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -41,8 +43,6 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; /** * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,8 @@ import java.util.List; import java.util.function.Predicate; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.RetryableBailoutException; import org.graalvm.compiler.core.common.cfg.Loop; @@ -38,8 +40,6 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.cfg.Block; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; public final class ReentrantBlockIterator { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,9 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; @@ -38,9 +41,6 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.LoopExitNode; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.MapCursor; public final class ReentrantNodeIterator { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,6 +27,8 @@ import java.util.Deque; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeBitMap; import org.graalvm.compiler.nodes.AbstractBeginNode; @@ -42,8 +44,6 @@ import org.graalvm.compiler.nodes.LoopEndNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; /** * A SinglePassNodeIterator iterates the fixed nodes of the graph in post order starting from its diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,8 @@ import java.util.List; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.DebugContext; @@ -40,8 +42,6 @@ import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; public final class MemoryScheduleVerification extends BlockIteratorClosure> { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,14 +22,23 @@ */ package org.graalvm.compiler.phases.schedule; +import static org.graalvm.collections.Equivalence.IDENTITY; +import static org.graalvm.compiler.core.common.GraalOptions.GuardPriorities; import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumMap; import java.util.Formatter; +import java.util.Iterator; import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.function.Function; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.SuppressFBWarnings; import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph; import org.graalvm.compiler.core.common.cfg.BlockMap; @@ -48,7 +57,6 @@ import org.graalvm.compiler.nodes.ControlSplitNode; import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.GuardNode; import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.KillingBeginNode; @@ -57,6 +65,8 @@ import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StaticDeoptimizingNode; +import org.graalvm.compiler.nodes.StaticDeoptimizingNode.GuardPriority; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; @@ -78,10 +88,19 @@ public final class SchedulePhase extends Phase { public enum SchedulingStrategy { + EARLIEST_WITH_GUARD_ORDER, EARLIEST, LATEST, LATEST_OUT_OF_LOOPS, - FINAL_SCHEDULE + FINAL_SCHEDULE; + + public boolean isEarliest() { + return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER; + } + + public boolean isLatest() { + return !isEarliest(); + } } private final SchedulingStrategy selectedStrategy; @@ -164,13 +183,13 @@ this.nodeToBlockMap = currentNodeMap; this.blockToNodesMap = earliestBlockToNodesMap; - scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph); + scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph, selectedStrategy == SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER); - if (selectedStrategy != SchedulingStrategy.EARLIEST) { + if (!selectedStrategy.isEarliest()) { // For non-earliest schedules, we need to do a second pass. BlockMap> latestBlockToNodesMap = new BlockMap<>(cfg); for (Block b : cfg.getBlocks()) { - latestBlockToNodesMap.put(b, new ArrayList()); + latestBlockToNodesMap.put(b, new ArrayList<>()); } BlockMap> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph); @@ -181,8 +200,8 @@ this.blockToNodesMap = latestBlockToNodesMap; - cfg.setNodeToBlock(currentNodeMap); } + cfg.setNodeToBlock(currentNodeMap); graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap)); } @@ -524,7 +543,6 @@ assert latestBlock != null : currentNode; if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) { - assert latestBlock != null; Block currentBlock = latestBlock; while (currentBlock.getLoopDepth() > earliestBlock.getLoopDepth() && currentBlock != earliestBlock.getDominator()) { Block previousCurrentBlock = currentBlock; @@ -645,7 +663,7 @@ */ public void add(Node node) { assert !(node instanceof FixedNode) : node; - NodeEntry newTail = new NodeEntry(node, null); + NodeEntry newTail = new NodeEntry(node); if (tail == null) { tail = head = newTail; } else { @@ -659,9 +677,18 @@ * Number of nodes in this micro block. */ public int getNodeCount() { + assert getActualNodeCount() == nodeCount : getActualNodeCount() + " != " + nodeCount; return nodeCount; } + private int getActualNodeCount() { + int count = 0; + for (NodeEntry e = head; e != null; e = e.next) { + count++; + } + return count; + } + /** * The id of the micro block, with a block always associated with a lower id than its * successors. @@ -685,6 +712,7 @@ */ public void prependChildrenTo(MicroBlock newBlock) { if (tail != null) { + assert head != null; tail.next = newBlock.head; newBlock.head = head; head = tail = null; @@ -697,6 +725,11 @@ public String toString() { return String.format("MicroBlock[id=%d]", id); } + + @Override + public int hashCode() { + return id; + } } /** @@ -706,9 +739,9 @@ private final Node node; private NodeEntry next; - NodeEntry(Node node, NodeEntry next) { + NodeEntry(Node node) { this.node = node; - this.next = next; + this.next = null; } public NodeEntry getNext() { @@ -720,7 +753,8 @@ } } - private void scheduleEarliestIterative(BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph) { + private void scheduleEarliestIterative(BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph, + boolean withGuardOrder) { NodeMap entries = graph.createNodeMap(); NodeStack stack = new NodeStack(); @@ -729,62 +763,44 @@ MicroBlock startBlock = null; int nextId = 1; for (Block b : cfg.reversePostOrder()) { - FixedNode current = b.getBeginNode(); - while (true) { + for (FixedNode current : b.getBeginNode().getBlockNodes()) { MicroBlock microBlock = new MicroBlock(nextId++); - entries.put(current, microBlock); - visited.checkAndMarkInc(current); - + entries.set(current, microBlock); + boolean isNew = visited.checkAndMarkInc(current); + assert isNew; if (startBlock == null) { startBlock = microBlock; } - - // Process inputs of this fixed node. - for (Node input : current.inputs()) { - if (entries.get(input) == null) { - processStack(input, startBlock, entries, visited, stack); - } - } - - if (current == b.getEndNode()) { - // Break loop when reaching end node. - break; - } - - current = ((FixedWithNextNode) current).next(); } } - // Now process guards. - for (GuardNode guardNode : graph.getNodes(GuardNode.TYPE)) { - if (entries.get(guardNode) == null) { - processStack(guardNode, startBlock, entries, visited, stack); + if (graph.getGuardsStage().allowsFloatingGuards() && graph.getNodes(GuardNode.TYPE).isNotEmpty()) { + // Now process guards. + if (GuardPriorities.getValue(graph.getOptions()) && withGuardOrder) { + EnumMap> guardsByPriority = new EnumMap<>(GuardPriority.class); + for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) { + guardsByPriority.computeIfAbsent(guard.computePriority(), p -> new ArrayList<>()).add(guard); + } + // `EnumMap.values` returns values in "natural" key order + for (List guards : guardsByPriority.values()) { + processNodes(visited, entries, stack, startBlock, guards); + } + GuardOrder.resortGuards(graph, entries, stack); + } else { + processNodes(visited, entries, stack, startBlock, graph.getNodes(GuardNode.TYPE)); } + } else { + assert graph.getNodes(GuardNode.TYPE).isEmpty(); } // Now process inputs of fixed nodes. for (Block b : cfg.reversePostOrder()) { - FixedNode current = b.getBeginNode(); - while (true) { - - // Process inputs of this fixed node. - for (Node input : current.inputs()) { - if (entries.get(input) == null) { - processStack(input, startBlock, entries, visited, stack); - } - } - - if (current == b.getEndNode()) { - // Break loop when reaching end node. - break; - } - - current = ((FixedWithNextNode) current).next(); + for (FixedNode current : b.getBeginNode().getBlockNodes()) { + processNodes(visited, entries, stack, startBlock, current.inputs()); } } if (visited.getCounter() < graph.getNodeCount()) { - // Visit back input edges of loop phis. boolean changed; boolean unmarkedPhi; @@ -829,36 +845,29 @@ if (fixedNode instanceof ControlSplitNode) { ControlSplitNode controlSplitNode = (ControlSplitNode) fixedNode; MicroBlock endBlock = entries.get(fixedNode); - MicroBlock primarySuccessor = entries.get(controlSplitNode.getPrimarySuccessor()); - endBlock.prependChildrenTo(primarySuccessor); + AbstractBeginNode primarySuccessor = controlSplitNode.getPrimarySuccessor(); + if (primarySuccessor != null) { + endBlock.prependChildrenTo(entries.get(primarySuccessor)); + } else { + assert endBlock.tail == null; + } } } - // Initialize with begin nodes + // Create lists for each block for (Block b : cfg.reversePostOrder()) { - - FixedNode current = b.getBeginNode(); + // Count nodes in block int totalCount = 0; - while (true) { - + for (FixedNode current : b.getBeginNode().getBlockNodes()) { MicroBlock microBlock = entries.get(current); totalCount += microBlock.getNodeCount() + 1; - - if (current == b.getEndNode()) { - // Break loop when reaching end node. - break; - } - - current = ((FixedWithNextNode) current).next(); } // Initialize with begin node, it is always the first node. ArrayList nodes = new ArrayList<>(totalCount); blockToNodes.put(b, nodes); - current = b.getBeginNode(); - while (true) { - + for (FixedNode current : b.getBeginNode().getBlockNodes()) { MicroBlock microBlock = entries.get(current); nodeToBlock.set(current, b); nodes.add(current); @@ -869,19 +878,20 @@ nodes.add(nextNode); next = next.getNext(); } - - if (current == b.getEndNode()) { - // Break loop when reaching end node. - break; - } - - current = ((FixedWithNextNode) current).next(); } } assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes); } + private static void processNodes(NodeBitMap visited, NodeMap entries, NodeStack stack, MicroBlock startBlock, Iterable nodes) { + for (Node node : nodes) { + if (entries.get(node) == null) { + processStack(node, startBlock, entries, visited, stack); + } + } + } + private static void processStackPhi(NodeStack stack, PhiNode phiNode, NodeMap nodeToBlock, NodeBitMap visited) { stack.pop(); if (visited.checkAndMarkInc(phiNode)) { @@ -944,6 +954,166 @@ } } + private static class GuardOrder { + /** + * After an earliest schedule, this will re-sort guards to honor their + * {@linkplain StaticDeoptimizingNode#computePriority() priority}. + * + * Note that this only changes the order of nodes within {@linkplain MicroBlock + * micro-blocks}, nodes will not be moved from one micro-block to another. + */ + private static void resortGuards(StructuredGraph graph, NodeMap entries, NodeStack stack) { + assert stack.isEmpty(); + EconomicSet blocksWithGuards = EconomicSet.create(IDENTITY); + for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) { + MicroBlock block = entries.get(guard); + assert block != null : guard + "should already be scheduled to a micro-block"; + blocksWithGuards.add(block); + } + assert !blocksWithGuards.isEmpty(); + NodeMap priorities = graph.createNodeMap(); + NodeBitMap blockNodes = graph.createNodeBitMap(); + for (MicroBlock block : blocksWithGuards) { + MicroBlock newBlock = resortGuards(block, stack, blockNodes, priorities); + assert stack.isEmpty(); + assert blockNodes.isEmpty(); + if (newBlock != null) { + assert block.getNodeCount() == newBlock.getNodeCount(); + block.head = newBlock.head; + block.tail = newBlock.tail; + } + } + } + + /** + * This resorts guards within one micro-block. + * + * {@code stack}, {@code blockNodes} and {@code priorities} are just temporary + * data-structures which are allocated once by the callers of this method. They should + * be in their "initial"/"empty" state when calling this method and when it returns. + */ + private static MicroBlock resortGuards(MicroBlock block, NodeStack stack, NodeBitMap blockNodes, NodeMap priorities) { + if (!propagatePriority(block, stack, priorities, blockNodes)) { + return null; + } + + Function transitiveGuardPriorityGetter = priorities::get; + Comparator globalGuardPriorityComparator = Comparator.comparing(transitiveGuardPriorityGetter).thenComparing(GuardNode::computePriority).thenComparingInt(Node::hashCode); + + SortedSet availableGuards = new TreeSet<>(globalGuardPriorityComparator); + MicroBlock newBlock = new MicroBlock(block.getId()); + + NodeBitMap sorted = blockNodes; + sorted.invert(); + + for (NodeEntry e = block.head; e != null; e = e.next) { + checkIfAvailable(e.node, stack, sorted, newBlock, availableGuards, false); + } + do { + while (!stack.isEmpty()) { + checkIfAvailable(stack.pop(), stack, sorted, newBlock, availableGuards, true); + } + Iterator iterator = availableGuards.iterator(); + if (iterator.hasNext()) { + addNodeToResort(iterator.next(), stack, sorted, newBlock, true); + iterator.remove(); + } + } while (!stack.isEmpty() || !availableGuards.isEmpty()); + + blockNodes.clearAll(); + return newBlock; + } + + /** + * This checks if {@code n} can be scheduled, if it is the case, it schedules it now by + * calling {@link #addNodeToResort(Node, NodeStack, NodeBitMap, MicroBlock, boolean)}. + */ + private static void checkIfAvailable(Node n, NodeStack stack, NodeBitMap sorted, Instance.MicroBlock newBlock, SortedSet availableGuardNodes, boolean pushUsages) { + if (sorted.isMarked(n)) { + return; + } + for (Node in : n.inputs()) { + if (!sorted.isMarked(in)) { + return; + } + } + if (n instanceof GuardNode) { + availableGuardNodes.add((GuardNode) n); + } else { + addNodeToResort(n, stack, sorted, newBlock, pushUsages); + } + } + + /** + * Add a node to the re-sorted micro-block. This also pushes nodes that need to be + * (re-)examined on the stack. + */ + private static void addNodeToResort(Node n, NodeStack stack, NodeBitMap sorted, MicroBlock newBlock, boolean pushUsages) { + sorted.mark(n); + newBlock.add(n); + if (pushUsages) { + for (Node u : n.usages()) { + if (!sorted.isMarked(u)) { + stack.push(u); + } + } + } + } + + /** + * This fills in a map of transitive priorities ({@code priorities}). It also marks the + * nodes from this micro-block in {@code blockNodes}. + * + * The transitive priority of a guard is the highest of its priority and the priority of + * the guards that depend on it (transitively). + * + * This method returns {@code false} if no re-ordering is necessary in this micro-block. + */ + private static boolean propagatePriority(MicroBlock block, NodeStack stack, NodeMap priorities, NodeBitMap blockNodes) { + assert stack.isEmpty(); + assert blockNodes.isEmpty(); + GuardPriority lowestPriority = GuardPriority.highest(); + for (NodeEntry e = block.head; e != null; e = e.next) { + blockNodes.mark(e.node); + if (e.node instanceof GuardNode) { + GuardNode guard = (GuardNode) e.node; + GuardPriority priority = guard.computePriority(); + if (lowestPriority != null) { + if (priority.isLowerPriorityThan(lowestPriority)) { + lowestPriority = priority; + } else if (priority.isHigherPriorityThan(lowestPriority)) { + lowestPriority = null; + } + } + stack.push(guard); + priorities.set(guard, priority); + } + } + if (lowestPriority != null) { + stack.clear(); + blockNodes.clearAll(); + return false; + } + + do { + Node current = stack.pop(); + assert blockNodes.isMarked(current); + GuardPriority priority = priorities.get(current); + for (Node input : current.inputs()) { + if (!blockNodes.isMarked(input)) { + continue; + } + GuardPriority inputPriority = priorities.get(input); + if (inputPriority == null || inputPriority.isLowerPriorityThan(priority)) { + priorities.set(input, priority); + stack.push(input); + } + } + } while (!stack.isEmpty()); + return true; + } + } + /** * Processes the inputs of given block. Pushes unprocessed inputs onto the stack. Returns * null if there were still unprocessed inputs, otherwise returns the earliest block given @@ -960,7 +1130,7 @@ if (inputBlock == null) { earliestBlock = null; stack.push(input); - } else if (earliestBlock != null && inputBlock.getId() >= earliestBlock.getId()) { + } else if (earliestBlock != null && inputBlock.getId() > earliestBlock.getId()) { earliestBlock = inputBlock; } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,8 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.GraalGraphError; @@ -55,8 +57,6 @@ import org.graalvm.compiler.phases.graph.StatelessPostOrderNodeIterator; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; public final class GraphOrder { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.phases.util; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.CodeGenProviders; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; @@ -90,6 +91,11 @@ } @Override + public ArrayOffsetProvider getArrayOffsetProvider() { + return lowerer; + } + + @Override public ConstantReflectionProvider getConstantReflection() { return constantReflection; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java Sat Feb 10 09:25:35 2018 +0100 @@ -143,9 +143,9 @@ "org.graalvm.compiler.phases.BasePhase.dumpAfter", "org.graalvm.compiler.phases.BasePhase.dumpBefore", "org.graalvm.compiler.core.GraalCompiler.emitFrontEnd", - "org.graalvm.compiler.truffle.PartialEvaluator.fastPartialEvaluation", - "org.graalvm.compiler.truffle.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings", - "org.graalvm.compiler.truffle.TruffleCompiler.compileMethodHelper", + "org.graalvm.compiler.truffle.compiler.PartialEvaluator.fastPartialEvaluation", + "org.graalvm.compiler.truffle.compiler.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings", + "org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph", "org.graalvm.compiler.core.test.VerifyDebugUsageTest$ValidDumpUsagePhase.run", "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidConcatDumpUsagePhase.run", "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidDumpUsagePhase.run")); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,10 @@ */ package org.graalvm.compiler.phases.verify; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; @@ -40,10 +42,9 @@ import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.phases.VerifyPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicSet; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; public class VerifyGraphAddUsage extends VerifyPhase { private static final Method ADD_OR_UNIQUE; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java Sat Feb 10 09:25:35 2018 +0100 @@ -33,6 +33,7 @@ import java.util.Map; import java.util.TreeMap; +import org.graalvm.collections.UnmodifiableMapCursor; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; import org.graalvm.compiler.core.common.alloc.Trace; @@ -66,7 +67,6 @@ import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; -import org.graalvm.util.UnmodifiableMapCursor; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.TargetDescription; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,12 +23,15 @@ package org.graalvm.compiler.replacements.amd64; import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.word.Word; import org.graalvm.word.Pointer; -import sun.misc.Unsafe; +import jdk.vm.ci.meta.JavaKind; // JaCoCo Exclude @@ -38,6 +41,19 @@ @ClassSubstitution(String.class) public class AMD64StringSubstitutions { + @Fold + static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { + return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char); + } + + @Fold + static int charArrayIndexScale(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { + return arrayOffsetProvider.arrayScalingFactor(JavaKind.Char); + } + + /** Marker value for the {@link InjectedParameter} injected parameter. */ + static final ArrayOffsetProvider INJECTED = null; + // Only exists in JDK <= 8 @MethodSubstitution(isStatic = true, optional = true) public static int indexOf(char[] source, int sourceOffset, int sourceCount, @@ -62,8 +78,8 @@ } assert sourceCount - fromIndex > 0 && targetCount > 0; - Pointer sourcePointer = Word.objectToTrackedPointer(source).add(Unsafe.ARRAY_CHAR_BASE_OFFSET).add(totalOffset * Unsafe.ARRAY_CHAR_INDEX_SCALE); - Pointer targetPointer = Word.objectToTrackedPointer(target).add(Unsafe.ARRAY_CHAR_BASE_OFFSET).add(targetOffset * Unsafe.ARRAY_CHAR_INDEX_SCALE); + Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); + Pointer targetPointer = Word.objectToTrackedPointer(target).add(charArrayBaseOffset(INJECTED)).add(targetOffset * charArrayIndexScale(INJECTED)); int result = AMD64StringIndexOfNode.optimizedStringIndexPointer(sourcePointer, sourceCount - fromIndex, targetPointer, targetCount); if (result >= 0) { return result + totalOffset; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -79,7 +79,7 @@ @Override protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { - InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null); + InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), getProviders().getLowerer(), null); new PluginFactory_FoldTest().registerPlugins(invocationPlugins, injection); BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider(); Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017, 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.test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.phases.HighTier; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Test; + +public class NestedExceptionHandlerTest extends GraalCompilerTest { + + @BytecodeParserNeverInline(invokeWithException = true) + public static void foo() { + } + + @BytecodeParserNeverInline(invokeWithException = true) + public static void bar() { + throw new NegativeArraySizeException(); + } + + public static int nestedExceptionHandler() { + int flag = 0; + try { + try { + try { + foo(); + } catch (NegativeArraySizeException e) { + flag = -1; + } + bar(); + } catch (NullPointerException e) { + flag = -2; + } + } catch (Throwable e) { + GraalDirectives.deoptimize(); + } + return flag; + } + + @Test + public void testNestedExceptionHandler() { + test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "nestedExceptionHandler"); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; +import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.java.GraphBuilderPhase; @@ -43,7 +44,6 @@ import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,10 +24,13 @@ import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; +import org.graalvm.compiler.api.replacements.Fold; +import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.debug.DebugHandlersFactory; -import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.options.OptionValues; @@ -38,7 +41,7 @@ import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import jdk.vm.ci.code.TargetDescription; -import sun.misc.Unsafe; +import jdk.vm.ci.meta.JavaKind; public class ConstantStringIndexOfSnippets implements Snippets { public static class Templates extends AbstractTemplates { @@ -91,6 +94,14 @@ return cache; } + @Fold + static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { + return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char); + } + + /** Marker value for the {@link InjectedParameter} injected parameter. */ + static final ArrayOffsetProvider INJECTED = null; + @Snippet public static int indexOfConstant(char[] source, int sourceOffset, int sourceCount, @ConstantParameter char[] target, int targetOffset, int targetCount, @@ -109,7 +120,7 @@ int targetCountLess1 = targetCount - 1; int sourceEnd = sourceCount - targetCountLess1; - long base = Unsafe.ARRAY_CHAR_BASE_OFFSET; + long base = charArrayBaseOffset(INJECTED); int lastChar = UnsafeAccess.UNSAFE.getChar(target, base + targetCountLess1 * 2); outer_loop: for (long i = sourceOffset + fromIndex; i < sourceEnd;) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -921,8 +921,7 @@ public abstract int arrayLengthOffset(); - public abstract int arrayBaseOffset(JavaKind elementKind); - + @Override public int arrayScalingFactor(JavaKind elementKind) { return target.arch.getPlatformKind(elementKind).getSizeInBytes(); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java Sat Feb 10 09:25:35 2018 +0100 @@ -27,7 +27,7 @@ import java.util.List; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; -import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.ConditionAnchorNode; @@ -184,7 +184,7 @@ } if (condition == null || (!(condition instanceof CompareNode)) || ((CompareNode) condition).getY() != testValue) { // Re-use previously generated condition if the trueValue for the test is the same - condition = createCompareNode(result.graph(), Condition.EQ, result, testValue, null, NodeView.DEFAULT); + condition = createCompareNode(result.graph(), CanonicalCondition.EQ, result, testValue, null, NodeView.DEFAULT); } return condition; } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,6 +23,7 @@ package org.graalvm.compiler.replacements; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -40,12 +41,15 @@ private final MetaAccessProvider metaAccess; private final SnippetReflectionProvider snippetReflection; private final ForeignCallsProvider foreignCalls; + private final ArrayOffsetProvider arrayOffsetProvider; private final WordTypes wordTypes; - public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) { + public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ArrayOffsetProvider arrayOffsetProvider, + WordTypes wordTypes) { this.metaAccess = metaAccess; this.snippetReflection = snippetReflection; this.foreignCalls = foreignCalls; + this.arrayOffsetProvider = arrayOffsetProvider; this.wordTypes = wordTypes; } @@ -73,6 +77,8 @@ return type.cast(foreignCalls); } else if (type.equals(SnippetReflectionProvider.class)) { return type.cast(snippetReflection); + } else if (type.equals(ArrayOffsetProvider.class)) { + return type.cast(arrayOffsetProvider); } else { throw new GraalError("Cannot handle injected argument of type %s.", type.getName()); } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Sat Feb 10 09:25:35 2018 +0100 @@ -32,6 +32,8 @@ import java.util.List; import java.util.Map; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.core.common.PermanentBailoutException; @@ -102,8 +104,6 @@ import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.inlining.InliningUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.code.BailoutException; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -36,6 +36,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.Snippet; @@ -47,9 +49,9 @@ import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.debug.DebugCloseable; -import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Description; +import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.graph.Node; @@ -81,8 +83,6 @@ import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.word.Word; import org.graalvm.compiler.word.WordOperationPlugin; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -274,10 +274,13 @@ if (plugin instanceof MethodSubstitutionPlugin) { MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin; ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess); - StructuredGraph graph = graphs.get(substitute); + StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(substitute) : null; if (graph == null) { try (DebugContext debug = openDebugContext("Substitution_", method)) { graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method); + if (!UseSnippetGraphCache.getValue(options)) { + return graph; + } graph.freeze(); graphs.putIfAbsent(substitute, graph); graph = graphs.get(substitute); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Sat Feb 10 09:25:35 2018 +0100 @@ -47,11 +47,27 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; +import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Local; +import jdk.vm.ci.meta.LocalVariableTable; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; +import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter; import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter; -import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -59,15 +75,15 @@ import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugHandlersFactory; -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.DebugContext.Description; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; -import org.graalvm.compiler.graph.Graph.Mark; +import org.graalvm.compiler.debug.DebugContext.Description; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.loop.LoopEx; import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.loop.phases.LoopTransformations; @@ -86,15 +102,15 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.PhiNode; -import org.graalvm.compiler.nodes.PiNode.Placeholder; -import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValueNodeUtil; +import org.graalvm.compiler.nodes.PiNode.Placeholder; +import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; +import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.LoadIndexedNode; import org.graalvm.compiler.nodes.java.StoreIndexedNode; @@ -115,35 +131,19 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.FloatingReadPhase; -import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl; import org.graalvm.compiler.phases.common.GuardLoweringPhase; import org.graalvm.compiler.phases.common.LoweringPhase; import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl; import org.graalvm.compiler.phases.common.inlining.InliningUtil; import org.graalvm.compiler.phases.tiers.PhaseContext; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode; import org.graalvm.util.CollectionsUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.UnmodifiableEconomicMap; import org.graalvm.word.LocationIdentity; import org.graalvm.word.WordBase; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Local; -import jdk.vm.ci.meta.LocalVariableTable; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.vm.ci.meta.Signature; - /** * A snippet template is a graph created by parsing a snippet method and then specialized by binding * constants to the snippet's {@link ConstantParameter} parameters. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Sat Feb 10 09:25:35 2018 +0100 @@ -37,10 +37,13 @@ import java.lang.reflect.Field; import java.util.Arrays; +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.SpeculationLog; import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; import org.graalvm.compiler.core.common.calc.UnsignedMath; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; @@ -456,23 +459,16 @@ @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { - // the mirroring and negation operations get the condition into canonical form - boolean mirror = condition.canonicalMirror(); - boolean negate = condition.canonicalNegate(); + CanonicalizedCondition canonical = condition.canonicalize(); StructuredGraph graph = b.getGraph(); - ValueNode lhs = mirror ? y : x; - ValueNode rhs = mirror ? x : y; - - ValueNode trueValue = ConstantNode.forBoolean(!negate, graph); - ValueNode falseValue = ConstantNode.forBoolean(negate, graph); + ValueNode lhs = canonical.mustMirror() ? y : x; + ValueNode rhs = canonical.mustMirror() ? x : y; - Condition cond = mirror ? condition.mirror() : condition; - if (negate) { - cond = cond.negate(); - } + ValueNode trueValue = ConstantNode.forBoolean(!canonical.mustNegate(), graph); + ValueNode falseValue = ConstantNode.forBoolean(canonical.mustNegate(), graph); - LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, cond, lhs, rhs, NodeView.DEFAULT); + LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, canonical.getCanonicalCondition(), lhs, rhs, NodeView.DEFAULT); b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue)); return true; } @@ -728,6 +724,24 @@ } } + private static final class DirectiveSpeculationReason implements SpeculationLog.SpeculationReason { + private final BytecodePosition pos; + + private DirectiveSpeculationReason(BytecodePosition pos) { + this.pos = pos; + } + + @Override + public int hashCode() { + return pos.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DirectiveSpeculationReason && ((DirectiveSpeculationReason) obj).pos.equals(this.pos); + } + } + private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) { Registration r = new Registration(plugins, GraalDirectives.class); r.register0("deoptimize", new InvocationPlugin() { @@ -746,6 +760,23 @@ } }); + r.register0("deoptimizeAndInvalidateWithSpeculation", new InvocationPlugin() { + @Override + public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { + GraalError.guarantee(b.getGraph().getSpeculationLog() != null, "A speculation log is need to use `deoptimizeAndInvalidateWithSpeculation`"); + BytecodePosition pos = new BytecodePosition(null, b.getMethod(), b.bci()); + DirectiveSpeculationReason reason = new DirectiveSpeculationReason(pos); + JavaConstant speculation; + if (b.getGraph().getSpeculationLog().maySpeculate(reason)) { + speculation = b.getGraph().getSpeculationLog().speculate(reason); + } else { + speculation = JavaConstant.defaultForKind(JavaKind.Object); + } + b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter, speculation)); + return true; + } + }); + r.register0("inCompiledCode", new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java Sat Feb 10 09:25:35 2018 +0100 @@ -46,8 +46,8 @@ private final ResolvedJavaType type; private final List codeAttributes; - private static final int MAJOR_VERSION_JAVA_MIN = 51; - private static final int MAJOR_VERSION_JAVA_MAX = 55; + private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7 + private static final int MAJOR_VERSION_JAVA_MAX = 55; // JDK11 private static final int MAGIC = 0xCAFEBABE; /** diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,12 +29,12 @@ import java.io.IOException; import java.io.InputStream; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.serviceprovider.JDK9Method; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java Sat Feb 10 09:25:35 2018 +0100 @@ -54,6 +54,7 @@ public static final byte CONSTANT_NameAndType = 12; public static final byte CONSTANT_MethodHandle = 15; public static final byte CONSTANT_MethodType = 16; + public static final byte CONSTANT_Dynamic = 17; public static final byte CONSTANT_InvokeDynamic = 18; // @formatter:on diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java Sat Feb 10 09:25:35 2018 +0100 @@ -112,6 +112,9 @@ case ClassfileConstant.CONSTANT_MethodType: skipFully(stream, 2); // descriptor_index return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodType_info"); + case ClassfileConstant.CONSTANT_Dynamic: + skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index + return new ClassfileConstant.Unsupported(tag, "CONSTANT_Dynamic_info"); case ClassfileConstant.CONSTANT_InvokeDynamic: skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info"); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Sat Feb 10 09:25:35 2018 +0100 @@ -62,7 +62,7 @@ @Override public boolean inferStamp() { - return updateStamp(computeStamp(getObject())); + return updateStamp(stamp.improveWith(computeStamp(getObject()))); } protected Stamp computeStamp(ValueNode object) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Sat Feb 10 09:25:35 2018 +0100 @@ -37,6 +37,8 @@ import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.MirroredTypeException; import javax.lang.model.type.TypeMirror; @@ -84,8 +86,8 @@ try { annotation.value(); } catch (MirroredTypeException ex) { - TypeMirror serviceInterface = ex.getTypeMirror(); - if (verifyAnnotation(serviceInterface, serviceProvider)) { + TypeMirror service = ex.getTypeMirror(); + if (verifyAnnotation(service, serviceProvider)) { if (serviceProvider.getNestingKind().isNested()) { /* * This is a simplifying constraint that means we don't have to process the @@ -94,7 +96,30 @@ String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); } else { - serviceProviders.put(serviceProvider, ex.getTypeMirror().toString()); + /* + * Since the definition of the service class is not necessarily modifiable, + * we need to support a non-top-level service class and ensure its name is + * properly expressed with '$' separating nesting levels instead of '.'. + */ + TypeElement serviceElement = (TypeElement) processingEnv.getTypeUtils().asElement(service); + String serviceName = serviceElement.getSimpleName().toString(); + Element enclosing = serviceElement.getEnclosingElement(); + while (enclosing != null) { + final ElementKind kind = enclosing.getKind(); + if (kind == ElementKind.PACKAGE) { + serviceName = ((PackageElement) enclosing).getQualifiedName().toString() + "." + serviceName; + break; + } else if (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE) { + serviceName = ((TypeElement) enclosing).getSimpleName().toString() + "$" + serviceName; + enclosing = enclosing.getEnclosingElement(); + } else { + String msg = String.format("Cannot generate provider descriptor for service class %s as it is not nested in a package, class or interface", + serviceElement.getQualifiedName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + return; + } + } + serviceProviders.put(serviceProvider, serviceName); } } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,7 +24,6 @@ import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM; import static org.graalvm.compiler.debug.DebugContext.NO_DESCRIPTION; -import static org.graalvm.compiler.debug.DebugContext.NO_GLOBAL_METRIC_VALUES; import java.io.PrintStream; import java.io.PrintWriter; @@ -36,16 +35,17 @@ import java.util.Collections; import java.util.List; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugDumpHandler; +import org.graalvm.compiler.debug.DebugHandlersFactory; +import org.graalvm.compiler.debug.GlobalMetrics; import org.graalvm.compiler.options.OptionValues; import org.junit.After; import org.junit.Assert; import org.junit.internal.ComparisonCriteria; import org.junit.internal.ExactComparisonCriteria; +import jdk.vm.ci.meta.ResolvedJavaMethod; import sun.misc.Unsafe; /** @@ -398,7 +398,7 @@ /** * Gets a {@link DebugContext} object corresponding to {@code options}, creating a new one if - * none currently exists.Debug contexts created by this method will have their + * none currently exists. Debug contexts created by this method will have their * {@link DebugDumpHandler}s closed in {@link #afterTest()}. * * @param options currently active options @@ -423,11 +423,21 @@ } else { descr = new DebugContext.Description(method, id == null ? method.getName() : id); } - DebugContext debug = DebugContext.create(options, descr, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, getDebugHandlersFactories()); + DebugContext debug = DebugContext.create(options, descr, globalMetrics, DEFAULT_LOG_STREAM, getDebugHandlersFactories()); cached.add(debug); return debug; } + private static final GlobalMetrics globalMetrics = new GlobalMetrics(); + + static { + Runtime.getRuntime().addShutdownHook(new Thread("GlobalMetricsPrinter") { + @Override + public void run() { + globalMetrics.print(new OptionValues(OptionValues.newOptionMap())); + } + }); + } private final ThreadLocal> cachedDebugs = new ThreadLocal<>(); @After @@ -435,6 +445,7 @@ List cached = cachedDebugs.get(); if (cached != null) { for (DebugContext debug : cached) { + debug.close(); debug.closeDumpHandlers(true); } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -22,8 +22,6 @@ */ package org.graalvm.compiler.test; -import org.graalvm.util.CollectionsUtil; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -37,6 +35,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.graalvm.util.CollectionsUtil; + /** * Utility methods for spawning a VM in a subprocess during unit tests. */ diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,8 +25,8 @@ import java.util.Iterator; import java.util.Map; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.UnmodifiableMapCursor; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.UnmodifiableMapCursor; public abstract class EffectsBlockState> { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,9 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.cfg.BlockMap; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.Stamp; @@ -59,9 +62,6 @@ import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.LoopInfo; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; public abstract class EffectsClosure> extends EffectsPhase.Closure { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.core.common.util.CompilationAlarm; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Graph.NodeEventScope; @@ -39,7 +40,6 @@ import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicSet; public abstract class EffectsPhase extends BasePhase { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,8 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugContext; @@ -35,8 +37,6 @@ import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,11 @@ import java.util.Iterator; import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; +import org.graalvm.collections.Pair; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.graph.Node; @@ -61,11 +66,6 @@ import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; -import org.graalvm.util.Pair; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.ConstantReflectionProvider; @@ -186,7 +186,7 @@ JavaKind accessKind = load.accessKind(); JavaKind componentKind = type.getComponentType().getJavaKind(); long offset = load.offset().asJavaConstant().asLong(); - int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); + int index = VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); ValueNode object = GraphUtil.unproxify(load.object()); LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind); ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this); @@ -212,7 +212,7 @@ if (store.offset().isConstant()) { long offset = store.offset().asJavaConstant().asLong(); boolean overflowAccess = isOverflowAccess(accessKind, componentKind); - int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); + int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects); } else { processIdentity(state, location); diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,6 +28,9 @@ import java.util.List; import java.util.function.IntUnaryOperator; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; @@ -68,9 +71,6 @@ import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; import org.graalvm.compiler.virtual.nodes.VirtualObjectState; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalysisIterations; import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalyzeOnly; +import org.graalvm.collections.EconomicSet; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; @@ -37,7 +38,6 @@ import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.util.EconomicSet; public class PartialEscapePhase extends EffectsPhase { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,10 +24,10 @@ import java.util.Iterator; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.util.Equivalence; import org.graalvm.word.LocationIdentity; -import org.graalvm.util.EconomicMap; /** * This class maintains a set of known values, identified by base object, locations and offset. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java Sat Feb 10 09:25:35 2018 +0100 @@ -28,7 +28,10 @@ import java.util.Iterator; import java.util.List; -import jdk.vm.ci.meta.ResolvedJavaType; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.EconomicSet; +import org.graalvm.collections.Equivalence; +import org.graalvm.collections.MapCursor; import org.graalvm.compiler.core.common.cfg.Loop; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; @@ -60,13 +63,10 @@ import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry; import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.UnsafeLoadCacheEntry; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; import org.graalvm.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaType; /** * This closure initially handled a set of nodes that is disjunct from diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,8 @@ import java.util.List; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TTY; @@ -35,8 +37,6 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.Equivalence; import jdk.vm.ci.meta.ResolvedJavaMethod; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,7 @@ import java.util.List; +import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; @@ -108,6 +109,11 @@ return constantFieldProvider; } + @Override + public ArrayOffsetProvider getArrayOffsetProvider() { + return loweringProvider; + } + public void reset(PartialEscapeBlockState newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) { deleted = false; state = newState; @@ -160,7 +166,7 @@ * Special case: Allow storing a single long or double value into two consecutive * int slots. */ - int nextIndex = virtual.entryIndexForOffset(offset + 4, JavaKind.Int); + int nextIndex = virtual.entryIndexForOffset(getArrayOffsetProvider(), offset + 4, JavaKind.Int); if (nextIndex != -1) { canVirtualize = true; assert nextIndex == index + 1 : "expected to be sequential"; diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Sat Feb 10 09:25:35 2018 +0100 @@ -31,7 +31,9 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.bytecode.BridgeMethodUtils; +import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; @@ -409,31 +411,30 @@ private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) { assert left.getStackKind() == wordKind && right.getStackKind() == wordKind; - // mirroring gets the condition into canonical form - boolean mirror = condition.canonicalMirror(); + CanonicalizedCondition canonical = condition.canonicalize(); - ValueNode a = mirror ? right : left; - ValueNode b = mirror ? left : right; + ValueNode a = canonical.mustMirror() ? right : left; + ValueNode b = canonical.mustMirror() ? left : right; CompareNode comparison; - if (condition == Condition.EQ || condition == Condition.NE) { + if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) { comparison = new IntegerEqualsNode(a, b); - } else if (condition.isUnsigned()) { + } else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) { comparison = new IntegerBelowNode(a, b); } else { + assert canonical.getCanonicalCondition() == CanonicalCondition.LT; comparison = new IntegerLessThanNode(a, b); } ConstantNode trueValue = graph.add(forInt(1)); ConstantNode falseValue = graph.add(forInt(0)); - if (condition.canonicalNegate()) { + if (canonical.mustNegate()) { ConstantNode temp = trueValue; trueValue = falseValue; falseValue = temp; } - ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue)); - return materialize; + return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue)); } protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) { diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphJavadocSnippets.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphJavadocSnippets.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2017, 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.graphio; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +final class GraphJavadocSnippets { + static GraphStructure acmeGraphStructure() { + // @formatter:off + // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure + class AcmeGraphStructure implements + GraphStructure { + + @Override + public AcmeGraph graph(AcmeGraph currentGraph, Object obj) { + return obj instanceof AcmeGraph ? (AcmeGraph) obj : null; + } + + @Override + public Iterable nodes(AcmeGraph graph) { + return graph.allNodes(); + } + + @Override + public int nodesCount(AcmeGraph graph) { + return graph.allNodes().size(); + } + + @Override + public int nodeId(AcmeNode node) { + return node.id; + } + + @Override + public boolean nodeHasPredecessor(AcmeNode node) { + return node.id > 0; + } + + @Override + public void nodeProperties( + AcmeGraph graph, AcmeNode node, Map properties + ) { + properties.put("id", node.id); + } + + @Override + public AcmeNodeType nodeClass(Object obj) { + return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null; + } + + @Override + public AcmeNode node(Object obj) { + return obj instanceof AcmeNode ? (AcmeNode) obj : null; + } + + @Override + public AcmeNodeType classForNode(AcmeNode node) { + // we have only one type of nodes + return AcmeNodeType.STANDARD; + } + + + @Override + public String nameTemplate(AcmeNodeType nodeClass) { + return "Acme ({p#id})"; + } + + @Override + public Object nodeClassType(AcmeNodeType nodeClass) { + return nodeClass.getClass(); + } + + @Override + public AcmePorts portInputs(AcmeNodeType nodeClass) { + return AcmePorts.INPUT; + } + + @Override + public AcmePorts portOutputs(AcmeNodeType nodeClass) { + return AcmePorts.OUTPUT; + } + + @Override + public int portSize(AcmePorts port) { + return port == AcmePorts.OUTPUT ? 1 : 0; + } + + @Override + public boolean edgeDirect(AcmePorts port, int index) { + return false; + } + + @Override + public String edgeName(AcmePorts port, int index) { + return port.name(); + } + + @Override + public Object edgeType(AcmePorts port, int index) { + return port; + } + + @Override + public Collection edgeNodes( + AcmeGraph graph, AcmeNode node, AcmePorts port, int index + ) { + if (port == AcmePorts.OUTPUT) { + return node.outgoing.targets; + } + return null; + } + } + + // END: org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure + + return new AcmeGraphStructure(); + } + + // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#buildOutput + static GraphOutput buildOutput(WritableByteChannel channel) + throws IOException { + return GraphOutput.newBuilder(acmeGraphStructure()). + // use the latest version; currently 5.0 + protocolVersion(5, 0). + build(channel); + } + // END: org.graalvm.graphio.GraphJavadocSnippets#buildOutput + + // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#buildAll + static GraphOutput buildAll(WritableByteChannel channel) + throws IOException { + GraphBlocks graphBlocks = acmeBlocks(); + GraphElements graphElements = acmeElements(); + GraphTypes graphTypes = acmeTypes(); + + return GraphOutput.newBuilder(acmeGraphStructure()). + protocolVersion(5, 0). + blocks(graphBlocks). + elements(graphElements). + types(graphTypes). + build(channel); + } + // END: org.graalvm.graphio.GraphJavadocSnippets#buildAll + + private static GraphTypes acmeTypes() { + GraphTypes graphTypes = null; + // in real world don't return null + return graphTypes; + } + + private static GraphElements acmeElements() { + GraphElements graphElements = null; + // in real world don't return null + return graphElements; + } + + private static GraphBlocks acmeBlocks() { + GraphBlocks graphBlocks = null; + // in real world don't return null + return graphBlocks; + } + + private static class AcmeGraph { + final AcmeNode root; + + AcmeGraph(AcmeNode root) { + this.root = root; + } + + Set allNodes() { + return allNodes(root, new LinkedHashSet<>()); + } + + private static Set allNodes(AcmeNode node, Set collectTo) { + if (collectTo.add(node)) { + for (AcmeNode target : node.outgoing.targets) { + allNodes(target, collectTo); + } + } + return collectTo; + } + } + + private static class AcmeNode { + final int id; + final AcmeEdges outgoing; + + AcmeNode(int id) { + this.id = id; + this.outgoing = new AcmeEdges(); + } + + void linkTo(AcmeNode target) { + outgoing.targets.add(target); + } + } + + private enum AcmeNodeType { + STANDARD + } + + private enum AcmePorts { + INPUT, + OUTPUT; + } + + private static class AcmeEdges { + final Set targets; + + AcmeEdges() { + this.targets = new LinkedHashSet<>(); + } + } + + private static class AcmeBlocks { + } + + private static class AcmeMethod { + } + + private static class AcmeField { + } + + private static class AcmeSignature { + } + + private static class AcmeCodePosition { + } + + // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#dump + static void dump(File toFile) throws IOException { + try ( + FileChannel ch = new FileOutputStream(toFile).getChannel(); + GraphOutput output = buildOutput(ch); + ) { + AcmeNode root = new AcmeNode(0); + AcmeNode n1 = new AcmeNode(1); + AcmeNode n2 = new AcmeNode(2); + AcmeNode n3 = new AcmeNode(3); + + root.linkTo(n1); + root.linkTo(n2); + n1.linkTo(n3); + n2.linkTo(n3); + + AcmeGraph diamondGraph = new AcmeGraph(root); + + output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null); + output.print(diamondGraph, null, 0, "Diamond graph #%d", 1); + output.endGroup(); + } + } + // END: org.graalvm.graphio.GraphJavadocSnippets#dump + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphSnippets.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphSnippets.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -/* - * Copyright (c) 2017, 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.graphio; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -final class GraphSnippets { - static GraphStructure acmeGraphStructure() { - // @formatter:off - // BEGIN: org.graalvm.graphio.GraphSnippets#acmeGraphStructure - class AcmeGraphStructure implements - GraphStructure { - - @Override - public AcmeGraph graph(AcmeGraph currentGraph, Object obj) { - return obj instanceof AcmeGraph ? (AcmeGraph) obj : null; - } - - @Override - public Iterable nodes(AcmeGraph graph) { - return graph.allNodes(); - } - - @Override - public int nodesCount(AcmeGraph graph) { - return graph.allNodes().size(); - } - - @Override - public int nodeId(AcmeNode node) { - return node.id; - } - - @Override - public boolean nodeHasPredecessor(AcmeNode node) { - return node.id > 0; - } - - @Override - public void nodeProperties( - AcmeGraph graph, AcmeNode node, Map properties - ) { - properties.put("id", node.id); - } - - @Override - public AcmeNodeType nodeClass(Object obj) { - return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null; - } - - @Override - public AcmeNode node(Object obj) { - return obj instanceof AcmeNode ? (AcmeNode) obj : null; - } - - @Override - public AcmeNodeType classForNode(AcmeNode node) { - // we have only one type of nodes - return AcmeNodeType.STANDARD; - } - - - @Override - public String nameTemplate(AcmeNodeType nodeClass) { - return "Acme ({p#id})"; - } - - @Override - public Object nodeClassType(AcmeNodeType nodeClass) { - return nodeClass.getClass(); - } - - @Override - public AcmePorts portInputs(AcmeNodeType nodeClass) { - return AcmePorts.INPUT; - } - - @Override - public AcmePorts portOutputs(AcmeNodeType nodeClass) { - return AcmePorts.OUTPUT; - } - - @Override - public int portSize(AcmePorts port) { - return port == AcmePorts.OUTPUT ? 1 : 0; - } - - @Override - public boolean edgeDirect(AcmePorts port, int index) { - return false; - } - - @Override - public String edgeName(AcmePorts port, int index) { - return port.name(); - } - - @Override - public Object edgeType(AcmePorts port, int index) { - return port; - } - - @Override - public Collection edgeNodes( - AcmeGraph graph, AcmeNode node, AcmePorts port, int index - ) { - if (port == AcmePorts.OUTPUT) { - return node.outgoing.targets; - } - return null; - } - } - - // END: org.graalvm.graphio.GraphSnippets#acmeGraphStructure - - return new AcmeGraphStructure(); - } - - // BEGIN: org.graalvm.graphio.GraphSnippets#buildOutput - static GraphOutput buildOutput(WritableByteChannel channel) - throws IOException { - return GraphOutput.newBuilder(acmeGraphStructure()). - // use the latest version; currently 5.0 - protocolVersion(5, 0). - build(channel); - } - // END: org.graalvm.graphio.GraphSnippets#buildOutput - - // BEGIN: org.graalvm.graphio.GraphSnippets#buildAll - static GraphOutput buildAll(WritableByteChannel channel) - throws IOException { - GraphBlocks graphBlocks = acmeBlocks(); - GraphElements graphElements = acmeElements(); - GraphTypes graphTypes = acmeTypes(); - - return GraphOutput.newBuilder(acmeGraphStructure()). - protocolVersion(5, 0). - blocks(graphBlocks). - elements(graphElements). - types(graphTypes). - build(channel); - } - // END: org.graalvm.graphio.GraphSnippets#buildAll - - private static GraphTypes acmeTypes() { - GraphTypes graphTypes = null; - // in real world don't return null - return graphTypes; - } - - private static GraphElements acmeElements() { - GraphElements graphElements = null; - // in real world don't return null - return graphElements; - } - - private static GraphBlocks acmeBlocks() { - GraphBlocks graphBlocks = null; - // in real world don't return null - return graphBlocks; - } - - private static class AcmeGraph { - final AcmeNode root; - - AcmeGraph(AcmeNode root) { - this.root = root; - } - - Set allNodes() { - return allNodes(root, new LinkedHashSet<>()); - } - - private static Set allNodes(AcmeNode node, Set collectTo) { - if (collectTo.add(node)) { - for (AcmeNode target : node.outgoing.targets) { - allNodes(target, collectTo); - } - } - return collectTo; - } - } - - private static class AcmeNode { - final int id; - final AcmeEdges outgoing; - - AcmeNode(int id) { - this.id = id; - this.outgoing = new AcmeEdges(); - } - - void linkTo(AcmeNode target) { - outgoing.targets.add(target); - } - } - - private enum AcmeNodeType { - STANDARD - } - - private enum AcmePorts { - INPUT, - OUTPUT; - } - - private static class AcmeEdges { - final Set targets; - - AcmeEdges() { - this.targets = new LinkedHashSet<>(); - } - } - - private static class AcmeBlocks { - } - - private static class AcmeMethod { - } - - private static class AcmeField { - } - - private static class AcmeSignature { - } - - private static class AcmeCodePosition { - } - - // BEGIN: org.graalvm.graphio.GraphSnippets#dump - static void dump(File toFile) throws IOException { - try ( - FileChannel ch = new FileOutputStream(toFile).getChannel(); - GraphOutput output = buildOutput(ch); - ) { - AcmeNode root = new AcmeNode(0); - AcmeNode n1 = new AcmeNode(1); - AcmeNode n2 = new AcmeNode(2); - AcmeNode n3 = new AcmeNode(3); - - root.linkTo(n1); - root.linkTo(n2); - n1.linkTo(n3); - n2.linkTo(n3); - - AcmeGraph diamondGraph = new AcmeGraph(root); - - output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null); - output.print(diamondGraph, null, 0, "Diamond graph #%d", 1); - output.endGroup(); - } - } - // END: org.graalvm.graphio.GraphSnippets#dump - -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,13 +24,12 @@ /** * Send your graphs to IGV via a socket or a file. This package allows one to easily encode - * any graph-like data structure and send it for visualization to - * OracleLab's Ideal Graph Visualizer tool. Assuming you already have your own data - * structure that contains nodes and edges among them, creating a - * {@link org.graalvm.graphio.GraphOutput} specialized for your data is a matter of implementing a - * single interface: + * any graph-like data structure and send it for visualization to OracleLab's Ideal Graph + * Visualizer tool. Assuming you already have your own data structure that contains + * nodes and edges among them, creating a {@link org.graalvm.graphio.GraphOutput} + * specialized for your data is a matter of implementing a single interface: * - * {@link org.graalvm.graphio.GraphSnippets#acmeGraphStructure} + * {@link org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure} * * The {@link org.graalvm.graphio.GraphStructure} interface defines the set of operations that are * needed by the graph protocol to encode a graph into the IGV expected format. The @@ -43,7 +42,7 @@ * {@link org.graalvm.graphio.GraphOutput}. To do so use the associated * {@link org.graalvm.graphio.GraphOutput.Builder builder} just like shown in the following method: * - * {@link org.graalvm.graphio.GraphSnippets#buildOutput} + * {@link org.graalvm.graphio.GraphJavadocSnippets#buildOutput} * * Now you are ready to dump your graph into IGV. Where to obtain the right channel? One * option is to create a {@link java.nio.channels.FileChannel} and dump the data into a file @@ -51,7 +50,7 @@ * 4445 (the default port IGV listens to) and dump the data there. Here is an * example: * - * {@link org.graalvm.graphio.GraphSnippets#dump} + * {@link org.graalvm.graphio.GraphJavadocSnippets#dump} * * Call the {@code dump} method with pointer to file {@code diamond.bgv} and then you can open the * file in IGV. The result will look like this: @@ -75,7 +74,7 @@ * {@link org.graalvm.graphio.GraphOutput.Builder} instance methods, which may, but need not be * called at all. Here is an example: * - * {@link org.graalvm.graphio.GraphSnippets#buildAll} + * {@link org.graalvm.graphio.GraphJavadocSnippets#buildAll} * * All these interfaces follow the * singletonizer API pattern again - e.g. diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2017, 2017, 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.util.test; + +import static org.junit.Assert.assertEquals; + +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; +import org.graalvm.compiler.test.GraalTest; +import org.graalvm.util.ObjectSizeEstimate; +import org.junit.Assume; +import org.junit.Test; + +public class CollectionSizeTest { + + /** + * Tests the memory size of an empty map and a map with only one or two entries. + */ + @Test + public void testSize() { + Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier); + EconomicMap map = EconomicMap.create(Equivalence.IDENTITY); + assertEquals(49, ObjectSizeEstimate.forObject(map).getTotalBytes()); + + Integer value = 1; + map.put(value, value); + assertEquals(153, ObjectSizeEstimate.forObject(map).getTotalBytes()); + + Integer secondValue = 2; + map.put(secondValue, secondValue); + assertEquals(153 + 20, ObjectSizeEstimate.forObject(map).getTotalBytes()); + } + + /** + * Tests whether the map actually compresses the entries array when a large number of entries + * are deleted. + */ + @Test + public void testCompress() { + Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier); + EconomicMap map = EconomicMap.create(); + + // Measuring size of map with one entry. + Object firstValue = 0; + map.put(firstValue, firstValue); + ObjectSizeEstimate afterFirstValue = ObjectSizeEstimate.forObject(map); + + // Add 999 more entries. + for (int i = 1; i < 1000; ++i) { + Object value = i; + map.put(value, value); + } + ObjectSizeEstimate beforeRemove = ObjectSizeEstimate.forObject(map); + + // Remove 999 first entries. + for (int i = 0; i < 999; ++i) { + map.removeKey(i); + } + ObjectSizeEstimate afterRemove = ObjectSizeEstimate.forObject(map); + + // Check that size is same size as with one entry. + assertEquals(afterFirstValue, afterRemove); + + // Add 999 new entries. + for (int i = 0; i < 999; ++i) { + Object value = i; + map.put(value, value); + } + ObjectSizeEstimate afterAdd = ObjectSizeEstimate.forObject(map); + + // Check that entries array is same size again. + assertEquals(beforeRemove.getPointerCount(), afterAdd.getPointerCount()); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionTest.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,536 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util.test; - -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Random; -import java.util.function.BiFunction; - -import org.graalvm.util.CollectionsUtil; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; -import org.graalvm.util.ObjectSizeEstimate; -import org.graalvm.util.UnmodifiableMapCursor; -import org.junit.Assert; -import org.junit.Test; - -public class CollectionTest { - - /** - * Tests the memory size of an empty map and a map with only one or two entries. - */ - @Test - public void testSize() { - EconomicMap map = EconomicMap.create(Equivalence.IDENTITY); - assertEquals(48, ObjectSizeEstimate.forObject(map).getTotalBytes()); - - Integer value = 1; - map.put(value, value); - assertEquals(152, ObjectSizeEstimate.forObject(map).getTotalBytes()); - - Integer secondValue = 2; - map.put(secondValue, secondValue); - assertEquals(152 + 20, ObjectSizeEstimate.forObject(map).getTotalBytes()); - } - - /** - * Tests whether the map actually compresses the entries array when a large number of entries - * are deleted. - */ - @Test - public void testCompress() { - EconomicMap map = EconomicMap.create(); - - // Measuring size of map with one entry. - Object firstValue = 0; - map.put(firstValue, firstValue); - ObjectSizeEstimate afterFirstValue = ObjectSizeEstimate.forObject(map); - - // Add 999 more entries. - for (int i = 1; i < 1000; ++i) { - Object value = i; - map.put(value, value); - } - ObjectSizeEstimate beforeRemove = ObjectSizeEstimate.forObject(map); - - // Remove 999 first entries. - for (int i = 0; i < 999; ++i) { - map.removeKey(i); - } - ObjectSizeEstimate afterRemove = ObjectSizeEstimate.forObject(map); - - // Check that size is same size as with one entry. - assertEquals(afterFirstValue, afterRemove); - - // Add 999 new entries. - for (int i = 0; i < 999; ++i) { - Object value = i; - map.put(value, value); - } - ObjectSizeEstimate afterAdd = ObjectSizeEstimate.forObject(map); - - // Check that entries array is same size again. - assertEquals(beforeRemove.getPointerCount(), afterAdd.getPointerCount()); - } - - private static int[] createRandomRange(Random random, int count) { - int[] result = new int[count]; - for (int i = 0; i < count; ++i) { - int range = random.nextInt(14); - if (range == 0 || range > 10) { - range = Integer.MAX_VALUE; - } else if (range == 10) { - range = 100; - } - result[i] = range; - } - return result; - } - - private static final class BadHashClass { - private int value; - - BadHashClass(int randomInt) { - this.value = randomInt; - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public boolean equals(Object other) { - if (other instanceof BadHashClass) { - BadHashClass badHashClass = (BadHashClass) other; - return badHashClass.value == value; - } - return false; - } - } - - interface MapAction { - Object perform(EconomicMap map, int randomInt); - } - - static final Object EXISTING_VALUE = new Object(); - - static final MapAction[] INCREASE_ACTIONS = new MapAction[]{ - (map, randomInt) -> map.put(randomInt, "value"), - (map, randomInt) -> map.get(randomInt) - }; - - static final MapAction[] ACTIONS = new MapAction[]{ - (map, randomInt) -> map.removeKey(randomInt), - (map, randomInt) -> map.put(randomInt, "value"), - (map, randomInt) -> map.put(randomInt, null), - (map, randomInt) -> map.put(EXISTING_VALUE, randomInt), - (map, randomInt) -> { - if (randomInt == 0) { - map.clear(); - } - return map.isEmpty(); - }, - (map, randomInt) -> map.containsKey(randomInt), - (map, randomInt) -> map.get(randomInt), - (map, randomInt) -> map.put(new BadHashClass(randomInt), "unique"), - (map, randomInt) -> { - if (randomInt == 0) { - map.replaceAll((key, value) -> Objects.toString(value) + "!"); - } - return map.isEmpty(); - } - - }; - - @Test - public void testVeryLarge() { - EconomicMap map = EconomicMap.create(); - EconomicMap referenceMap = createDebugMap(); - - Random random = new Random(0); - for (int i = 0; i < 200000; ++i) { - for (int j = 0; j < INCREASE_ACTIONS.length; ++j) { - int nextInt = random.nextInt(10000000); - MapAction action = INCREASE_ACTIONS[j]; - Object result = action.perform(map, nextInt); - Object referenceResult = action.perform(referenceMap, nextInt); - Assert.assertEquals(result, referenceResult); - } - } - } - - /** - * Tests a sequence of random operations on the map. - */ - @Test - public void testAddRemove() { - EconomicMap map = EconomicMap.create(); - EconomicMap referenceMap = createDebugMap(); - - for (int seed = 0; seed < 10; ++seed) { - Random random = new Random(seed); - int[] ranges = createRandomRange(random, ACTIONS.length); - int value = random.nextInt(10000); - for (int i = 0; i < value; ++i) { - for (int j = 0; j < ACTIONS.length; ++j) { - if (random.nextInt(ranges[j]) == 0) { - int nextInt = random.nextInt(100); - MapAction action = ACTIONS[j]; - Object result = action.perform(map, nextInt); - Object referenceResult = action.perform(referenceMap, nextInt); - Assert.assertEquals(result, referenceResult); - if (j % 100 == 0) { - checkEquality(map, referenceMap); - } - } - } - - if (random.nextInt(20) == 0) { - removeElement(random.nextInt(100), map, referenceMap); - } - } - } - } - - private static void removeElement(int index, EconomicMap map, EconomicMap referenceMap) { - Assert.assertEquals(referenceMap.size(), map.size()); - MapCursor cursor = map.getEntries(); - MapCursor referenceCursor = referenceMap.getEntries(); - int z = 0; - while (cursor.advance()) { - Assert.assertTrue(referenceCursor.advance()); - Assert.assertEquals(referenceCursor.getKey(), cursor.getKey()); - Assert.assertEquals(referenceCursor.getValue(), cursor.getValue()); - if (index == z) { - cursor.remove(); - referenceCursor.remove(); - } - ++z; - } - - Assert.assertFalse(referenceCursor.advance()); - } - - private static void checkEquality(EconomicMap map, EconomicMap referenceMap) { - Assert.assertEquals(referenceMap.size(), map.size()); - - // Check entries. - UnmodifiableMapCursor cursor = map.getEntries(); - UnmodifiableMapCursor referenceCursor = referenceMap.getEntries(); - while (cursor.advance()) { - Assert.assertTrue(referenceCursor.advance()); - Assert.assertEquals(referenceCursor.getKey(), cursor.getKey()); - Assert.assertEquals(referenceCursor.getValue(), cursor.getValue()); - } - - // Check keys. - Iterator iterator = map.getKeys().iterator(); - Iterator referenceIterator = referenceMap.getKeys().iterator(); - while (iterator.hasNext()) { - Assert.assertTrue(referenceIterator.hasNext()); - Assert.assertEquals(iterator.next(), referenceIterator.next()); - } - - // Check values. - iterator = map.getValues().iterator(); - referenceIterator = referenceMap.getValues().iterator(); - while (iterator.hasNext()) { - Assert.assertTrue(referenceIterator.hasNext()); - Assert.assertEquals(iterator.next(), referenceIterator.next()); - } - Assert.assertFalse(referenceIterator.hasNext()); - } - - public static EconomicMap createDebugMap() { - final LinkedHashMap linkedMap = new LinkedHashMap<>(); - final EconomicMap sparseMap = EconomicMap.create(); - return new EconomicMap() { - - @Override - public V get(K key) { - V result = linkedMap.get(key); - V sparseResult = sparseMap.get(key); - assert Objects.equals(result, sparseResult); - return result; - } - - @Override - public V put(K key, V value) { - V result = linkedMap.put(key, value); - assert Objects.equals(result, sparseMap.put(key, value)); - return result; - } - - @Override - public int size() { - int result = linkedMap.size(); - assert result == sparseMap.size(); - return result; - } - - @Override - public boolean containsKey(K key) { - boolean result = linkedMap.containsKey(key); - assert result == sparseMap.containsKey(key); - return result; - } - - @Override - public void clear() { - linkedMap.clear(); - sparseMap.clear(); - } - - @Override - public V removeKey(K key) { - V result = linkedMap.remove(key); - assert Objects.equals(result, sparseMap.removeKey(key)); - return result; - } - - @Override - public Iterable getValues() { - - Iterator iterator = linkedMap.values().iterator(); - Iterator sparseIterator = sparseMap.getValues().iterator(); - return new Iterable() { - - @Override - public Iterator iterator() { - return new Iterator() { - - @Override - public boolean hasNext() { - boolean result = iterator.hasNext(); - boolean otherResult = sparseIterator.hasNext(); - assert result == otherResult; - return result; - } - - @Override - public V next() { - V sparseNext = sparseIterator.next(); - V next = iterator.next(); - assert Objects.equals(sparseNext, next); - return next; - } - - @Override - public void remove() { - iterator.remove(); - sparseIterator.remove(); - } - }; - } - - }; - } - - @Override - public Iterable getKeys() { - - Iterator iterator = linkedMap.keySet().iterator(); - Iterator sparseIterator = sparseMap.getKeys().iterator(); - return new Iterable() { - - @Override - public Iterator iterator() { - return new Iterator() { - - @Override - public boolean hasNext() { - boolean result = iterator.hasNext(); - boolean otherResult = sparseIterator.hasNext(); - assert result == otherResult; - return result; - } - - @Override - public K next() { - K sparseNext = sparseIterator.next(); - K next = iterator.next(); - assert Objects.equals(sparseNext, next); - return next; - } - - @Override - public void remove() { - iterator.remove(); - sparseIterator.remove(); - } - }; - } - - }; - } - - @Override - public boolean isEmpty() { - boolean result = linkedMap.isEmpty(); - assert result == sparseMap.isEmpty(); - return result; - } - - @Override - public MapCursor getEntries() { - Iterator> iterator = linkedMap.entrySet().iterator(); - MapCursor cursor = sparseMap.getEntries(); - return new MapCursor() { - - private Map.Entry current; - - @Override - public boolean advance() { - boolean result = iterator.hasNext(); - boolean otherResult = cursor.advance(); - assert result == otherResult; - if (result) { - current = iterator.next(); - } - - return result; - } - - @Override - public K getKey() { - K key = current.getKey(); - assert key == cursor.getKey(); - return key; - } - - @Override - public V getValue() { - V value = current.getValue(); - assert Objects.equals(value, cursor.getValue()); - return value; - } - - @Override - public void remove() { - iterator.remove(); - cursor.remove(); - } - }; - } - - @Override - public void replaceAll(BiFunction function) { - linkedMap.replaceAll(function); - sparseMap.replaceAll(function); - } - }; - } - - @Test - public void testIterableConcat() { - List i1 = Arrays.asList("1", "2", "3"); - List i2 = Arrays.asList(); - List i3 = Arrays.asList("4", "5"); - List i4 = Arrays.asList(); - List i5 = Arrays.asList("6"); - List iNull = null; - - List actual = new ArrayList<>(); - List expected = new ArrayList<>(); - expected.addAll(i1); - expected.addAll(i2); - expected.addAll(i3); - expected.addAll(i4); - expected.addAll(i5); - Iterable iterable = CollectionsUtil.concat(Arrays.asList(i1, i2, i3, i4, i5)); - for (String s : iterable) { - actual.add(s); - } - Assert.assertEquals(expected, actual); - - Iterator iter = iterable.iterator(); - while (iter.hasNext()) { - iter.next(); - } - try { - iter.next(); - Assert.fail("Expected NoSuchElementException"); - } catch (NoSuchElementException e) { - // Expected - } - try { - CollectionsUtil.concat(i1, iNull); - Assert.fail("Expected NullPointerException"); - } catch (NullPointerException e) { - // Expected - } - - Iterable emptyIterable = CollectionsUtil.concat(Collections.emptyList()); - Assert.assertFalse(emptyIterable.iterator().hasNext()); - } - - @Test - public void testSetRemoval() { - ArrayList initialList = new ArrayList<>(); - ArrayList removalList = new ArrayList<>(); - ArrayList finalList = new ArrayList<>(); - EconomicSet set = EconomicSet.create(Equivalence.IDENTITY); - set.add(1); - set.add(2); - set.add(3); - set.add(4); - set.add(5); - set.add(6); - set.add(7); - set.add(8); - set.add(9); - Iterator i1 = set.iterator(); - while (i1.hasNext()) { - initialList.add(i1.next()); - } - int size = 0; - Iterator i2 = set.iterator(); - while (i2.hasNext()) { - Integer elem = i2.next(); - if (size++ < 8) { - i2.remove(); - } - removalList.add(elem); - } - Iterator i3 = set.iterator(); - while (i3.hasNext()) { - finalList.add(i3.next()); - } - Assert.assertEquals(initialList, removalList); - Assert.assertEquals(1, finalList.size()); - Assert.assertEquals(new Integer(9), finalList.get(0)); - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionUtilTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionUtilTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017, 2017, 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.util.test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.graalvm.util.CollectionsUtil; +import org.junit.Assert; +import org.junit.Test; + +public class CollectionUtilTest { + + private static int sum(Iterable iterable) { + int sum = 0; + for (int i : iterable) { + sum += i; + } + return sum; + } + + private static int indexOf(Iterable iterable, int element) { + int index = 0; + for (int i : iterable) { + if (i == element) { + return index; + } + index++; + } + return -1; + } + + @Test + public void testConcat() { + List a = Arrays.asList(1, 2); + List b = Arrays.asList(3, 4, 5); + Assert.assertEquals(sum(CollectionsUtil.concat(a, b)), 15); + Assert.assertEquals(sum(CollectionsUtil.concat(b, a)), 15); + Assert.assertEquals(indexOf(CollectionsUtil.concat(a, b), 5), 4); + Assert.assertEquals(indexOf(CollectionsUtil.concat(b, a), 5), 2); + } + + @Test + public void testMatch() { + String[] array = {"a", "b", "c", "d", "e"}; + Assert.assertTrue(CollectionsUtil.allMatch(array, s -> !s.isEmpty())); + Assert.assertFalse(CollectionsUtil.allMatch(array, s -> !s.startsWith("c"))); + Assert.assertFalse(CollectionsUtil.anyMatch(array, String::isEmpty)); + Assert.assertTrue(CollectionsUtil.anyMatch(array, s -> s.startsWith("c"))); + } + + @Test + public void testFilterToList() { + String[] array = {"a", "b", "", "d", "e"}; + Assert.assertEquals(CollectionsUtil.filterToList(Arrays.asList(array), String::isEmpty).size(), 1); + } + + @Test + public void testFilterAndMapToArray() { + String[] array = {"a", "b", "", "d", "e"}; + String[] newArray = CollectionsUtil.filterAndMapToArray(array, s -> !s.isEmpty(), String::toUpperCase, String[]::new); + Assert.assertArrayEquals(newArray, new String[]{"A", "B", "D", "E"}); + } + + @Test + public void testMapToArray() { + String[] array = {"a", "b", "c", "d", "e"}; + String[] newArray = CollectionsUtil.mapToArray(array, String::toUpperCase, String[]::new); + Assert.assertArrayEquals(newArray, new String[]{"A", "B", "C", "D", "E"}); + } + + @Test + public void testMapAndJoin() { + String[] array = {"a", "b", "c", "d", "e"}; + Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", "), "A, B, C, D, E"); + Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", ", "'"), "'A, 'B, 'C, 'D, 'E"); + Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", ", "'", "'"), "'A', 'B', 'C', 'D', 'E'"); + + Assert.assertEquals(CollectionsUtil.mapAndJoin(Arrays.asList(array), String::toUpperCase, ", "), "A, B, C, D, E"); + Assert.assertEquals(CollectionsUtil.mapAndJoin(Arrays.asList(array), String::toUpperCase, ", ", "'"), "'A, 'B, 'C, 'D, 'E"); + } + + @Test + public void testIterableConcat() { + List i1 = Arrays.asList("1", "2", "3"); + List i2 = Arrays.asList(); + List i3 = Arrays.asList("4", "5"); + List i4 = Arrays.asList(); + List i5 = Arrays.asList("6"); + List iNull = null; + + List actual = new ArrayList<>(); + List expected = new ArrayList<>(); + expected.addAll(i1); + expected.addAll(i2); + expected.addAll(i3); + expected.addAll(i4); + expected.addAll(i5); + Iterable iterable = CollectionsUtil.concat(Arrays.asList(i1, i2, i3, i4, i5)); + for (String s : iterable) { + actual.add(s); + } + Assert.assertEquals(expected, actual); + + Iterator iter = iterable.iterator(); + while (iter.hasNext()) { + iter.next(); + } + try { + iter.next(); + Assert.fail("Expected NoSuchElementException"); + } catch (NoSuchElementException e) { + // Expected + } + try { + CollectionsUtil.concat(i1, iNull); + Assert.fail("Expected NullPointerException"); + } catch (NullPointerException e) { + // Expected + } + + Iterable emptyIterable = CollectionsUtil.concat(Collections.emptyList()); + Assert.assertFalse(emptyIterable.iterator().hasNext()); + } + +} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/CollectionsUtil.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/CollectionsUtil.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/CollectionsUtil.java Sat Feb 10 09:25:35 2018 +0100 @@ -37,7 +37,10 @@ /** * This class contains utility methods for commonly used functional patterns for collections. */ -public class CollectionsUtil { +public final class CollectionsUtil { + + private CollectionsUtil() { + } /** * Concatenates two iterables into a single iterable. The iterator exposed by the returned @@ -93,10 +96,26 @@ }; } + /** + * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate + * {@code predicate} on all elements if not necessary for determining the result. If + * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated. + * + * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or + * {@code inputs} is empty, otherwise {@code false}. + */ public static boolean allMatch(T[] inputs, Predicate predicate) { return allMatch(Arrays.asList(inputs), predicate); } + /** + * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate + * {@code predicate} on all elements if not necessary for determining the result. If + * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated. + * + * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or + * {@code inputs} is empty, otherwise {@code false}. + */ public static boolean allMatch(Iterable inputs, Predicate predicate) { for (T t : inputs) { if (!predicate.test(t)) { @@ -106,10 +125,28 @@ return true; } + /** + * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate + * {@code predicate} on all elements if not necessary for determining the result. If + * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not + * evaluated. + * + * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise + * {@code false}. + */ public static boolean anyMatch(T[] inputs, Predicate predicate) { return anyMatch(Arrays.asList(inputs), predicate); } + /** + * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate + * {@code predicate} on all elements if not necessary for determining the result. If + * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not + * evaluated. + * + * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise + * {@code false}. + */ public static boolean anyMatch(Iterable inputs, Predicate predicate) { for (T t : inputs) { if (predicate.test(t)) { @@ -119,10 +156,21 @@ return false; } + /** + * Returns a new list consisting of the elements in {@code inputs} that match {@code predicate}. + * + * @return the new list. + */ public static List filterToList(List inputs, Predicate predicate) { return filterToList(inputs, predicate, ArrayList::new); } + /** + * Appends elements of {@code inputs} that match {@code predicate} to the list generated by + * {@code listGenerator}. + * + * @return the list generated by {@code listGenerator}. + */ public static List filterToList(List inputs, Predicate predicate, Supplier> listGenerator) { List resultList = listGenerator.get(); for (T t : inputs) { @@ -134,8 +182,10 @@ } /** - * Filters the inputs, maps them given the mapping function and adds them in the array provided - * by the generator. + * Filters {@code inputs} with {@code predicate}, applies {@code mapper} and adds them in the + * array provided by {@code arrayGenerator}. + * + * @return the array provided by {@code arrayGenerator}. */ public static R[] filterAndMapToArray(T[] inputs, Predicate predicate, Function mapper, IntFunction arrayGenerator) { List resultList = new ArrayList<>(); @@ -148,13 +198,21 @@ } /** - * Maps the inputs given the mapping function and adds them in the array provided by the - * generator. + * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided + * by {@code arrayGenerator}. + * + * @return the array provided by {@code arrayGenerator}. */ public static R[] mapToArray(T[] inputs, Function mapper, IntFunction arrayGenerator) { return mapToArray(Arrays.asList(inputs), mapper, arrayGenerator); } + /** + * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided + * by {@code arrayGenerator}. + * + * @return the array provided by {@code arrayGenerator}. + */ public static R[] mapToArray(Collection inputs, Function mapper, IntFunction arrayGenerator) { R[] result = arrayGenerator.apply(inputs.size()); int idx = 0; @@ -164,26 +222,62 @@ return result; } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(T[] inputs, Function mapper, String delimiter) { return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, "", ""); } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter} and starting with {@code prefix}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(T[] inputs, Function mapper, String delimiter, String prefix) { return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, ""); } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(T[] inputs, Function mapper, String delimiter, String prefix, String suffix) { return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, suffix); } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(Iterable inputs, Function mapper, String delimiter) { return mapAndJoin(inputs, mapper, delimiter, "", ""); } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter} and starting with {@code prefix}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(Iterable inputs, Function mapper, String delimiter, String prefix) { return mapAndJoin(inputs, mapper, delimiter, prefix, ""); } + /** + * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated + * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}. + * + * @return a new String that is composed from {@code inputs}. + */ public static String mapAndJoin(Iterable inputs, Function mapper, String delimiter, String prefix, String suffix) { StringBuilder strb = new StringBuilder(); String sep = ""; @@ -193,4 +287,5 @@ } return strb.toString(); } + } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -import java.util.Iterator; -import java.util.Map; -import java.util.function.BiFunction; - -import org.graalvm.util.impl.EconomicMapImpl; - -/** - * Memory efficient map data structure. - */ -public interface EconomicMap extends UnmodifiableEconomicMap { - - V put(K key, V value); - - default void putAll(EconomicMap other) { - MapCursor e = other.getEntries(); - while (e.advance()) { - put(e.getKey(), e.getValue()); - } - } - - void clear(); - - V removeKey(K key); - - @Override - MapCursor getEntries(); - - void replaceAll(BiFunction function); - - default void putAll(UnmodifiableEconomicMap other) { - UnmodifiableMapCursor entry = other.getEntries(); - while (entry.advance()) { - put(entry.getKey(), entry.getValue()); - } - } - - /** - * Creates a new map that guarantees insertion order on the key set with the default - * {@link Equivalence#DEFAULT} comparison strategy for keys. - */ - static EconomicMap create() { - return EconomicMap.create(Equivalence.DEFAULT); - } - - /** - * Creates a new map that guarantees insertion order on the key set with the default - * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified - * capacity. - */ - static EconomicMap create(int initialCapacity) { - return EconomicMap.create(Equivalence.DEFAULT, initialCapacity); - } - - /** - * Creates a new map that guarantees insertion order on the key set with the given comparison - * strategy for keys. - */ - static EconomicMap create(Equivalence strategy) { - return EconomicMapImpl.create(strategy); - } - - /** - * Creates a new map that guarantees insertion order on the key set with the default - * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the - * specified existing map. - */ - static EconomicMap create(UnmodifiableEconomicMap m) { - return EconomicMap.create(Equivalence.DEFAULT, m); - } - - /** - * Creates a new map that guarantees insertion order on the key set and copies all elements from - * the specified existing map. - */ - static EconomicMap create(Equivalence strategy, UnmodifiableEconomicMap m) { - return EconomicMapImpl.create(strategy, m); - } - - /** - * Creates a new map that guarantees insertion order on the key set and initializes with a - * specified capacity. - */ - static EconomicMap create(Equivalence strategy, int initialCapacity) { - return EconomicMapImpl.create(strategy, initialCapacity); - } - - /** - * Wraps an existing {@link java.util.Map} as an {@link org.graalvm.util.EconomicMap}. - */ - static EconomicMap wrapMap(Map map) { - return new EconomicMap() { - - @Override - public V get(K key) { - V result = map.get(key); - return result; - } - - @Override - public V put(K key, V value) { - V result = map.put(key, value); - return result; - } - - @Override - public int size() { - int result = map.size(); - return result; - } - - @Override - public boolean containsKey(K key) { - return map.containsKey(key); - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public V removeKey(K key) { - V result = map.remove(key); - return result; - } - - @Override - public Iterable getValues() { - return map.values(); - } - - @Override - public Iterable getKeys() { - return map.keySet(); - } - - @Override - public boolean isEmpty() { - return map.isEmpty(); - } - - @Override - public MapCursor getEntries() { - Iterator> iterator = map.entrySet().iterator(); - return new MapCursor() { - - private Map.Entry current; - - @Override - public boolean advance() { - boolean result = iterator.hasNext(); - if (result) { - current = iterator.next(); - } - - return result; - } - - @Override - public K getKey() { - return current.getKey(); - } - - @Override - public V getValue() { - return current.getValue(); - } - - @Override - public void remove() { - iterator.remove(); - } - }; - } - - @Override - public void replaceAll(BiFunction function) { - map.replaceAll(function); - } - }; - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicSet.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicSet.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -import java.util.Iterator; - -import org.graalvm.util.impl.EconomicMapImpl; - -/** - * Memory efficient set data structure. - */ -public interface EconomicSet extends UnmodifiableEconomicSet { - - boolean add(E element); - - void remove(E element); - - void clear(); - - default void addAll(EconomicSet values) { - addAll(values.iterator()); - } - - default void addAll(Iterable values) { - addAll(values.iterator()); - } - - default void addAll(Iterator values) { - while (values.hasNext()) { - add(values.next()); - } - } - - default void removeAll(EconomicSet values) { - removeAll(values.iterator()); - } - - default void removeAll(Iterable values) { - removeAll(values.iterator()); - } - - default void removeAll(Iterator values) { - while (values.hasNext()) { - remove(values.next()); - } - } - - default void retainAll(EconomicSet values) { - Iterator iterator = iterator(); - while (iterator.hasNext()) { - E key = iterator.next(); - if (!values.contains(key)) { - iterator.remove(); - } - } - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements with the - * default {@link Equivalence#DEFAULT} comparison strategy. - */ - static EconomicSet create() { - return EconomicSet.create(Equivalence.DEFAULT); - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements. - */ - static EconomicSet create(Equivalence strategy) { - return EconomicMapImpl.create(strategy); - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements with the - * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the - * specified collection. - */ - static EconomicSet create(int initialCapacity) { - return EconomicSet.create(Equivalence.DEFAULT, initialCapacity); - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements with the - * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the - * specified collection. - */ - static EconomicSet create(UnmodifiableEconomicSet c) { - return EconomicSet.create(Equivalence.DEFAULT, c); - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements and - * initializes with the given capacity. - */ - static EconomicSet create(Equivalence strategy, int initialCapacity) { - return EconomicMapImpl.create(strategy, initialCapacity); - } - - /** - * Creates a new set guaranteeing insertion order when iterating over its elements and inserts - * all elements of the specified collection. - */ - static EconomicSet create(Equivalence strategy, UnmodifiableEconomicSet c) { - return EconomicMapImpl.create(strategy, c); - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Equivalence.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Equivalence.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -/** - * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT}, - * {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}. - */ -public abstract class Equivalence { - - /** - * Default equivalence calling {@link #equals(Object)} to check equality and {@link #hashCode()} - * for obtaining hash values. Do not change the logic of this class as it may be inlined in - * other places. - */ - public static final Equivalence DEFAULT = new Equivalence() { - - @Override - public boolean equals(Object a, Object b) { - return a.equals(b); - } - - @Override - public int hashCode(Object o) { - return o.hashCode(); - } - }; - - /** - * Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining - * hash values. Do not change the logic of this class as it may be inlined in other places. - */ - public static final Equivalence IDENTITY = new Equivalence() { - - @Override - public boolean equals(Object a, Object b) { - return a == b; - } - - @Override - public int hashCode(Object o) { - return o.hashCode(); - } - }; - - /** - * Identity equivalence using {@code ==} to check equality and - * {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of - * this class as it may be inlined in other places. - */ - public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() { - - @Override - public boolean equals(Object a, Object b) { - return a == b; - } - - @Override - public int hashCode(Object o) { - return System.identityHashCode(o); - } - }; - - /** - * Subclass for creating custom equivalence definitions. - */ - protected Equivalence() { - } - - public abstract boolean equals(Object a, Object b); - - public abstract int hashCode(Object o); -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/MapCursor.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/MapCursor.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -/** - * Cursor to iterate over a mutable map. - */ -public interface MapCursor extends UnmodifiableMapCursor { - /** - * Remove the current entry from the map. May only be called once. After calling - * {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on - * the current entry. - */ - void remove(); -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,6 +26,9 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; +import org.graalvm.collections.EconomicMap; +import org.graalvm.collections.Equivalence; + /** * Calculates approximate estimates of the size of an object graph. * @@ -193,8 +196,8 @@ } else { size.recordPointer(); if (maxDepth > 1) { - f.setAccessible(true); try { + f.setAccessible(true); Object inner = f.get(o); if (inner != null) { if (depth < maxDepth && !identityHashMap.containsKey(inner)) { @@ -205,6 +208,14 @@ } } catch (IllegalArgumentException | IllegalAccessException e) { throw new UnsupportedOperationException("Must have access privileges to traverse object graph"); + } catch (RuntimeException e) { + if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) { + // This is a newly introduced exception in JDK9 and thus + // cannot be declared in the catch clause. + throw new UnsupportedOperationException("Target class is not exported to the current module.", e); + } else { + throw e; + } } } } diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Pair.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Pair.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -import java.util.Objects; - -/** - * Utility class representing a pair of values. - */ -public final class Pair { - private static final Pair EMPTY = new Pair<>(null, null); - - private final L left; - private final R right; - - @SuppressWarnings("unchecked") - public static Pair empty() { - return (Pair) EMPTY; - } - - public static Pair createLeft(L left) { - if (left == null) { - return empty(); - } else { - return new Pair<>(left, null); - } - } - - public static Pair createRight(R right) { - if (right == null) { - return empty(); - } else { - return new Pair<>(null, right); - } - } - - public static Pair create(L left, R right) { - if (right == null && left == null) { - return empty(); - } else { - return new Pair<>(left, right); - } - } - - private Pair(L left, R right) { - this.left = left; - this.right = right; - } - - public L getLeft() { - return left; - } - - public R getRight() { - return right; - } - - @Override - public int hashCode() { - return Objects.hashCode(left) + 31 * Objects.hashCode(right); - } - - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof Pair) { - Pair pair = (Pair) obj; - return Objects.equals(left, pair.left) && Objects.equals(right, pair.right); - } - - return false; - } - - @Override - public String toString() { - return String.format("(%s, %s)", left, right); - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicMap.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicMap.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -/** - * Unmodifiable memory efficient map data structure. - */ -public interface UnmodifiableEconomicMap { - - V get(K key); - - default V get(K key, V defaultValue) { - V v = get(key); - if (v == null) { - return defaultValue; - } - return v; - } - - boolean containsKey(K key); - - int size(); - - boolean isEmpty(); - - Iterable getValues(); - - Iterable getKeys(); - - UnmodifiableMapCursor getEntries(); -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicSet.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicSet.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -/** - * Unmodifiable memory efficient set data structure. - */ -public interface UnmodifiableEconomicSet extends Iterable { - - boolean contains(E element); - - int size(); - - boolean isEmpty(); - - default E[] toArray(E[] target) { - if (target.length != size()) { - throw new UnsupportedOperationException("Length of target array must equal the size of the set."); - } - - int index = 0; - for (E element : this) { - target[index++] = element; - } - - return target; - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableMapCursor.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableMapCursor.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util; - -/** - * Cursor to iterate over a map without changing its contents. - */ -public interface UnmodifiableMapCursor { - /** - * Advances to the next entry. - * - * @return {@code true} if a next entry exists, {@code false} if there is no next entry. - */ - boolean advance(); - - /** - * The key of the current entry. - */ - K getKey(); - - /** - * The value of the current entry. - */ - V getValue(); -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java Tue Feb 13 14:41:54 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,852 +0,0 @@ -/* - * Copyright (c) 2017, 2017, 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.util.impl; - -import java.util.Iterator; -import java.util.Objects; -import java.util.function.BiFunction; - -import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; -import org.graalvm.util.EconomicSet; -import org.graalvm.util.UnmodifiableEconomicMap; -import org.graalvm.util.UnmodifiableEconomicSet; -import org.graalvm.util.MapCursor; - -/** - * Implementation of a map with a memory-efficient structure that always preserves insertion order - * when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal - * {@link #INITIAL_CAPACITY} or smaller 256. - * - * The key/value pairs are kept in an expanding flat object array with keys at even indices and - * values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there - * is no additional hash data structure and comparisons are done via linear checking of the - * key/value pairs. For the case where the equality check is particularly cheap (e.g., just an - * object identity comparison), this limit below which the map is without an actual hash table is - * higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}. - * - * When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash - * array where an entry of 0 means no hit and otherwise denotes the entry number in the - * {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit - * within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of - * integer values in other cases. - * - * Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take - * the place of the values in the {@link #entries} array. - * - * Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the - * map falls below a specific threshold, the map will be compressed via the - * {@link #maybeCompress(int)} method. - */ -public final class EconomicMapImpl implements EconomicMap, EconomicSet { - - /** - * Initial number of key/value pair entries that is allocated in the first entries array. - */ - private static final int INITIAL_CAPACITY = 4; - - /** - * Maximum number of entries that are moved linearly forward if a key is removed. - */ - private static final int COMPRESS_IMMEDIATE_CAPACITY = 8; - - /** - * Minimum number of key/value pair entries added when the entries array is increased in size. - */ - private static final int MIN_CAPACITY_INCREASE = 8; - - /** - * Number of entries above which a hash table is created. - */ - private static final int HASH_THRESHOLD = 4; - - /** - * Number of entries above which a hash table is created when equality can be checked with - * object identity. - */ - private static final int HASH_THRESHOLD_IDENTITY_COMPARE = 8; - - /** - * Maximum number of entries allowed in the map. - */ - private static final int MAX_ELEMENT_COUNT = Integer.MAX_VALUE >> 1; - - /** - * Number of entries above which more than 1 byte is necessary for the hash index. - */ - private static final int LARGE_HASH_THRESHOLD = ((1 << Byte.SIZE) << 1); - - /** - * Number of entries above which more than 2 bytes are are necessary for the hash index. - */ - private static final int VERY_LARGE_HASH_THRESHOLD = (LARGE_HASH_THRESHOLD << Byte.SIZE); - - /** - * Total number of entries (actual entries plus deleted entries). - */ - private int totalEntries; - - /** - * Number of deleted entries. - */ - private int deletedEntries; - - /** - * Entries array with even indices storing keys and odd indices storing values. - */ - private Object[] entries; - - /** - * Hash array that is interpreted either as byte or short or int array depending on number of - * map entries. - */ - private byte[] hashArray; - - /** - * The strategy used for comparing keys or {@code null} for denoting special strategy - * {@link Equivalence#IDENTITY}. - */ - private final Equivalence strategy; - - /** - * Intercept method for debugging purposes. - */ - private static EconomicMapImpl intercept(EconomicMapImpl map) { - return map; - } - - public static EconomicMapImpl create(Equivalence strategy) { - return intercept(new EconomicMapImpl<>(strategy)); - } - - public static EconomicMapImpl create(Equivalence strategy, int initialCapacity) { - return intercept(new EconomicMapImpl<>(strategy, initialCapacity)); - } - - public static EconomicMapImpl create(Equivalence strategy, UnmodifiableEconomicMap other) { - return intercept(new EconomicMapImpl<>(strategy, other)); - } - - public static EconomicMapImpl create(Equivalence strategy, UnmodifiableEconomicSet other) { - return intercept(new EconomicMapImpl<>(strategy, other)); - } - - private EconomicMapImpl(Equivalence strategy) { - if (strategy == Equivalence.IDENTITY) { - this.strategy = null; - } else { - this.strategy = strategy; - } - } - - private EconomicMapImpl(Equivalence strategy, int initialCapacity) { - this(strategy); - init(initialCapacity); - } - - private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicMap other) { - this(strategy); - if (!initFrom(other)) { - init(other.size()); - putAll(other); - } - } - - private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicSet other) { - this(strategy); - if (!initFrom(other)) { - init(other.size()); - addAll(other); - } - } - - @SuppressWarnings("unchecked") - private boolean initFrom(Object o) { - if (o instanceof EconomicMapImpl) { - EconomicMapImpl otherMap = (EconomicMapImpl) o; - // We are only allowed to directly copy if the strategies of the two maps are the same. - if (strategy == otherMap.strategy) { - totalEntries = otherMap.totalEntries; - deletedEntries = otherMap.deletedEntries; - if (otherMap.entries != null) { - entries = otherMap.entries.clone(); - } - if (otherMap.hashArray != null) { - hashArray = otherMap.hashArray.clone(); - } - return true; - } - } - return false; - } - - private void init(int size) { - if (size > INITIAL_CAPACITY) { - entries = new Object[size << 1]; - } - } - - /** - * Links the collisions. Needs to be immutable class for allowing efficient shallow copy from - * other map on construction. - */ - private static final class CollisionLink { - - CollisionLink(Object value, int next) { - this.value = value; - this.next = next; - } - - final Object value; - - /** - * Index plus one of the next entry in the collision link chain. - */ - final int next; - } - - @SuppressWarnings("unchecked") - @Override - public V get(K key) { - Objects.requireNonNull(key); - - int index = find(key); - if (index != -1) { - return (V) getValue(index); - } - return null; - } - - private int find(K key) { - if (hasHashArray()) { - return findHash(key); - } else { - return findLinear(key); - } - } - - private int findLinear(K key) { - for (int i = 0; i < totalEntries; i++) { - Object entryKey = entries[i << 1]; - if (entryKey != null && compareKeys(key, entryKey)) { - return i; - } - } - return -1; - } - - private boolean compareKeys(Object key, Object entryKey) { - if (key == entryKey) { - return true; - } - if (strategy != null && strategy != Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { - if (strategy == Equivalence.DEFAULT) { - return key.equals(entryKey); - } else { - return strategy.equals(key, entryKey); - } - } - return false; - } - - private int findHash(K key) { - int index = getHashArray(getHashIndex(key)) - 1; - if (index != -1) { - Object entryKey = getKey(index); - if (compareKeys(key, entryKey)) { - return index; - } else { - Object entryValue = getRawValue(index); - if (entryValue instanceof CollisionLink) { - return findWithCollision(key, (CollisionLink) entryValue); - } - } - } - - return -1; - } - - private int findWithCollision(K key, CollisionLink initialEntryValue) { - int index; - Object entryKey; - CollisionLink entryValue = initialEntryValue; - while (true) { - CollisionLink collisionLink = entryValue; - index = collisionLink.next; - entryKey = getKey(index); - if (compareKeys(key, entryKey)) { - return index; - } else { - Object value = getRawValue(index); - if (value instanceof CollisionLink) { - entryValue = (CollisionLink) getRawValue(index); - } else { - return -1; - } - } - } - } - - private int getHashArray(int index) { - if (entries.length < LARGE_HASH_THRESHOLD) { - return (hashArray[index] & 0xFF); - } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { - int adjustedIndex = index << 1; - return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8); - } else { - int adjustedIndex = index << 2; - return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8) | ((hashArray[adjustedIndex + 2] & 0xFF) << 16) | ((hashArray[adjustedIndex + 3] & 0xFF) << 24); - } - } - - private void setHashArray(int index, int value) { - if (entries.length < LARGE_HASH_THRESHOLD) { - hashArray[index] = (byte) value; - } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { - int adjustedIndex = index << 1; - hashArray[adjustedIndex] = (byte) value; - hashArray[adjustedIndex + 1] = (byte) (value >> 8); - } else { - int adjustedIndex = index << 2; - hashArray[adjustedIndex] = (byte) value; - hashArray[adjustedIndex + 1] = (byte) (value >> 8); - hashArray[adjustedIndex + 2] = (byte) (value >> 16); - hashArray[adjustedIndex + 3] = (byte) (value >> 24); - } - } - - private int findAndRemoveHash(Object key) { - int hashIndex = getHashIndex(key); - int index = getHashArray(hashIndex) - 1; - if (index != -1) { - Object entryKey = getKey(index); - if (compareKeys(key, entryKey)) { - Object value = getRawValue(index); - int nextIndex = -1; - if (value instanceof CollisionLink) { - CollisionLink collisionLink = (CollisionLink) value; - nextIndex = collisionLink.next; - } - setHashArray(hashIndex, nextIndex + 1); - return index; - } else { - Object entryValue = getRawValue(index); - if (entryValue instanceof CollisionLink) { - return findAndRemoveWithCollision(key, (CollisionLink) entryValue, index); - } - } - } - - return -1; - } - - private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryValue, int initialIndexValue) { - int index; - Object entryKey; - CollisionLink entryValue = initialEntryValue; - int lastIndex = initialIndexValue; - while (true) { - CollisionLink collisionLink = entryValue; - index = collisionLink.next; - entryKey = getKey(index); - if (compareKeys(key, entryKey)) { - Object value = getRawValue(index); - if (value instanceof CollisionLink) { - CollisionLink thisCollisionLink = (CollisionLink) value; - setRawValue(lastIndex, new CollisionLink(collisionLink.value, thisCollisionLink.next)); - } else { - setRawValue(lastIndex, collisionLink.value); - } - return index; - } else { - Object value = getRawValue(index); - if (value instanceof CollisionLink) { - entryValue = (CollisionLink) getRawValue(index); - lastIndex = index; - } else { - return -1; - } - } - } - } - - private int getHashIndex(Object key) { - int hash; - if (strategy != null && strategy != Equivalence.DEFAULT) { - if (strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { - hash = System.identityHashCode(key); - } else { - hash = strategy.hashCode(key); - } - } else { - hash = key.hashCode(); - } - hash = hash ^ (hash >>> 16); - return hash & (getHashTableSize() - 1); - } - - @SuppressWarnings("unchecked") - @Override - public V put(K key, V value) { - if (key == null) { - throw new UnsupportedOperationException("null not supported as key!"); - } - int index = find(key); - if (index != -1) { - Object oldValue = getValue(index); - setValue(index, value); - return (V) oldValue; - } - - int nextEntryIndex = totalEntries; - if (entries == null) { - entries = new Object[INITIAL_CAPACITY << 1]; - } else if (entries.length == nextEntryIndex << 1) { - grow(); - - assert entries.length > totalEntries << 1; - // Can change if grow is actually compressing. - nextEntryIndex = totalEntries; - } - - setKey(nextEntryIndex, key); - setValue(nextEntryIndex, value); - totalEntries++; - - if (hasHashArray()) { - // Rehash on collision if hash table is more than three quarters full. - boolean rehashOnCollision = (getHashTableSize() < (size() + (size() >> 1))); - putHashEntry(key, nextEntryIndex, rehashOnCollision); - } else if (totalEntries > getHashThreshold()) { - createHash(); - } - - return null; - } - - /** - * Number of entries above which a hash table should be constructed. - */ - private int getHashThreshold() { - if (strategy == null || strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) { - return HASH_THRESHOLD_IDENTITY_COMPARE; - } else { - return HASH_THRESHOLD; - } - } - - private void grow() { - int entriesLength = entries.length; - int newSize = (entriesLength >> 1) + Math.max(MIN_CAPACITY_INCREASE, entriesLength >> 2); - if (newSize > MAX_ELEMENT_COUNT) { - throw new UnsupportedOperationException("map grown too large!"); - } - Object[] newEntries = new Object[newSize << 1]; - System.arraycopy(entries, 0, newEntries, 0, entriesLength); - entries = newEntries; - if ((entriesLength < LARGE_HASH_THRESHOLD && newEntries.length >= LARGE_HASH_THRESHOLD) || - (entriesLength < VERY_LARGE_HASH_THRESHOLD && newEntries.length > VERY_LARGE_HASH_THRESHOLD)) { - // Rehash in order to change number of bits reserved for hash indices. - createHash(); - } - } - - /** - * Compresses the graph if there is a large number of deleted entries and returns the translated - * new next index. - */ - private int maybeCompress(int nextIndex) { - if (entries.length != INITIAL_CAPACITY << 1 && deletedEntries >= (totalEntries >> 1) + (totalEntries >> 2)) { - return compressLarge(nextIndex); - } - return nextIndex; - } - - /** - * Compresses the graph and returns the translated new next index. - */ - private int compressLarge(int nextIndex) { - int size = INITIAL_CAPACITY; - int remaining = totalEntries - deletedEntries; - - while (size <= remaining) { - size += Math.max(MIN_CAPACITY_INCREASE, size >> 1); - } - - Object[] newEntries = new Object[size << 1]; - int z = 0; - int newNextIndex = remaining; - for (int i = 0; i < totalEntries; ++i) { - Object key = getKey(i); - if (i == nextIndex) { - newNextIndex = z; - } - if (key != null) { - newEntries[z << 1] = key; - newEntries[(z << 1) + 1] = getValue(i); - z++; - } - } - - this.entries = newEntries; - totalEntries = z; - deletedEntries = 0; - if (z <= getHashThreshold()) { - this.hashArray = null; - } else { - createHash(); - } - return newNextIndex; - } - - private int getHashTableSize() { - if (entries.length < LARGE_HASH_THRESHOLD) { - return hashArray.length; - } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) { - return hashArray.length >> 1; - } else { - return hashArray.length >> 2; - } - } - - private void createHash() { - int entryCount = size(); - - // Calculate smallest 2^n that is greater number of entries. - int size = getHashThreshold(); - while (size <= entryCount) { - size <<= 1; - } - - // Give extra size to avoid collisions. - size <<= 1; - - if (this.entries.length >= VERY_LARGE_HASH_THRESHOLD) { - // Every entry has 4 bytes. - size <<= 2; - } else if (this.entries.length >= LARGE_HASH_THRESHOLD) { - // Every entry has 2 bytes. - size <<= 1; - } else { - // Entries are very small => give extra size to further reduce collisions. - size <<= 1; - } - - hashArray = new byte[size]; - for (int i = 0; i < totalEntries; i++) { - Object entryKey = getKey(i); - if (entryKey != null) { - putHashEntry(entryKey, i, false); - } - } - } - - private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) { - int hashIndex = getHashIndex(key); - int oldIndex = getHashArray(hashIndex) - 1; - if (oldIndex != -1 && rehashOnCollision) { - this.createHash(); - return; - } - setHashArray(hashIndex, entryIndex + 1); - Object value = getRawValue(entryIndex); - if (oldIndex != -1) { - assert entryIndex != oldIndex : "this cannot happend and would create an endless collision link cycle"; - if (value instanceof CollisionLink) { - CollisionLink collisionLink = (CollisionLink) value; - setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex)); - } else { - setRawValue(entryIndex, new CollisionLink(getRawValue(entryIndex), oldIndex)); - } - } else { - if (value instanceof CollisionLink) { - CollisionLink collisionLink = (CollisionLink) value; - setRawValue(entryIndex, collisionLink.value); - } - } - } - - @Override - public int size() { - return totalEntries - deletedEntries; - } - - @Override - public boolean containsKey(K key) { - return find(key) != -1; - } - - @Override - public void clear() { - entries = null; - hashArray = null; - totalEntries = deletedEntries = 0; - } - - private boolean hasHashArray() { - return hashArray != null; - } - - @SuppressWarnings("unchecked") - @Override - public V removeKey(K key) { - if (key == null) { - throw new UnsupportedOperationException("null not supported as key!"); - } - int index; - if (hasHashArray()) { - index = this.findAndRemoveHash(key); - } else { - index = this.findLinear(key); - } - - if (index != -1) { - Object value = getValue(index); - remove(index); - return (V) value; - } - return null; - } - - /** - * Removes the element at the specific index and returns the index of the next element. This can - * be a different value if graph compression was triggered. - */ - private int remove(int indexToRemove) { - int index = indexToRemove; - int entriesAfterIndex = totalEntries - index - 1; - int result = index + 1; - - // Without hash array, compress immediately. - if (entriesAfterIndex <= COMPRESS_IMMEDIATE_CAPACITY && !hasHashArray()) { - while (index < totalEntries - 1) { - setKey(index, getKey(index + 1)); - setRawValue(index, getRawValue(index + 1)); - index++; - } - result--; - } - - setKey(index, null); - setRawValue(index, null); - if (index == totalEntries - 1) { - // Make sure last element is always non-null. - totalEntries--; - while (index > 0 && getKey(index - 1) == null) { - totalEntries--; - deletedEntries--; - index--; - } - } else { - deletedEntries++; - result = maybeCompress(result); - } - - return result; - } - - private abstract class SparseMapIterator implements Iterator { - - protected int current; - - @Override - public boolean hasNext() { - return current < totalEntries; - } - - @Override - public void remove() { - if (hasHashArray()) { - EconomicMapImpl.this.findAndRemoveHash(getKey(current - 1)); - } - current = EconomicMapImpl.this.remove(current - 1); - } - } - - @Override - public Iterable getValues() { - return new Iterable() { - @Override - public Iterator iterator() { - return new SparseMapIterator() { - @SuppressWarnings("unchecked") - @Override - public V next() { - Object result; - while (true) { - result = getValue(current); - if (result == null && getKey(current) == null) { - // values can be null, double-check if key is also null - current++; - } else { - current++; - break; - } - } - return (V) result; - } - }; - } - }; - } - - @Override - public Iterable getKeys() { - return this; - } - - @Override - public boolean isEmpty() { - return this.size() == 0; - } - - @Override - public MapCursor getEntries() { - return new MapCursor() { - int current = -1; - - @Override - public boolean advance() { - current++; - if (current >= totalEntries) { - return false; - } else { - while (EconomicMapImpl.this.getKey(current) == null) { - // Skip over null entries - current++; - } - return true; - } - } - - @SuppressWarnings("unchecked") - @Override - public K getKey() { - return (K) EconomicMapImpl.this.getKey(current); - } - - @SuppressWarnings("unchecked") - @Override - public V getValue() { - return (V) EconomicMapImpl.this.getValue(current); - } - - @Override - public void remove() { - if (hasHashArray()) { - EconomicMapImpl.this.findAndRemoveHash(EconomicMapImpl.this.getKey(current)); - } - current = EconomicMapImpl.this.remove(current) - 1; - } - }; - } - - @SuppressWarnings("unchecked") - @Override - public void replaceAll(BiFunction function) { - for (int i = 0; i < totalEntries; i++) { - Object entryKey = getKey(i); - if (entryKey != null) { - Object newValue = function.apply((K) entryKey, (V) getValue(i)); - setValue(i, newValue); - } - } - } - - private Object getKey(int index) { - return entries[index << 1]; - } - - private void setKey(int index, Object newValue) { - entries[index << 1] = newValue; - } - - private void setValue(int index, Object newValue) { - Object oldValue = getRawValue(index); - if (oldValue instanceof CollisionLink) { - CollisionLink collisionLink = (CollisionLink) oldValue; - setRawValue(index, new CollisionLink(newValue, collisionLink.next)); - } else { - setRawValue(index, newValue); - } - } - - private void setRawValue(int index, Object newValue) { - entries[(index << 1) + 1] = newValue; - } - - private Object getRawValue(int index) { - return entries[(index << 1) + 1]; - } - - private Object getValue(int index) { - Object object = getRawValue(index); - if (object instanceof CollisionLink) { - return ((CollisionLink) object).value; - } - return object; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("map(size=").append(size()).append(", {"); - MapCursor cursor = getEntries(); - while (cursor.advance()) { - builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append("),"); - } - builder.append("})"); - return builder.toString(); - } - - @Override - public Iterator iterator() { - return new SparseMapIterator() { - @SuppressWarnings("unchecked") - @Override - public K next() { - Object result; - while ((result = getKey(current++)) == null) { - // skip null entries - } - return (K) result; - } - }; - } - - @Override - public boolean contains(K element) { - return containsKey(element); - } - - @SuppressWarnings("unchecked") - @Override - public boolean add(K element) { - return put(element, (V) element) == null; - } - - @Override - public void remove(K element) { - removeKey(element); - } -} diff -r 0006d97556ba -r 7c23209e4873 src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml Tue Feb 13 14:41:54 2018 -0500 +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml Sat Feb 10 09:25:35 2018 +0100 @@ -40,7 +40,7 @@ - + diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/gtest/gc/shared/test_oopStorage.cpp --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp Sat Feb 10 09:25:35 2018 +0100 @@ -70,6 +70,10 @@ return storage._allocate_mutex; } + static bool reduce_deferred_updates(OopStorage& storage) { + return storage.reduce_deferred_updates(); + } + static bool block_is_empty(const Block& block) { return block.is_empty(); } @@ -127,9 +131,31 @@ return list.chead() == NULL; } -static void release_entry(OopStorage& storage, oop* entry) { +static bool process_deferred_updates(OopStorage& storage) { + MutexLockerEx ml(TestAccess::allocate_mutex(storage), Mutex::_no_safepoint_check_flag); + bool result = false; + while (TestAccess::reduce_deferred_updates(storage)) { + result = true; + } + return result; +} + +static void release_entry(OopStorage& storage, oop* entry, bool process_deferred = true) { *entry = NULL; storage.release(entry); + if (process_deferred) { + process_deferred_updates(storage); + } +} + +static size_t empty_block_count(const OopStorage& storage) { + const TestAccess::BlockList& list = TestAccess::allocate_list(storage); + size_t count = 0; + for (const OopBlock* block = list.ctail(); + (block != NULL) && block->is_empty(); + ++count, block = list.prev(*block)) + {} + return count; } class OopStorageTest : public ::testing::Test { @@ -188,31 +214,22 @@ class OopStorageTestWithAllocation::VM_DeleteBlocksAtSafepoint : public VM_GTestExecuteAtSafepoint { public: - VM_DeleteBlocksAtSafepoint(OopStorage* storage, size_t retain) : - _storage(storage), _retain(retain) - {} + VM_DeleteBlocksAtSafepoint(OopStorage* storage) : _storage(storage) {} void doit() { - _storage->delete_empty_blocks_safepoint(_retain); + _storage->delete_empty_blocks_safepoint(); } private: OopStorage* _storage; - size_t _retain; }; static bool is_allocate_list_sorted(const OopStorage& storage) { // The allocate_list isn't strictly sorted. Rather, all empty - // blocks are segregated to the end of the list. And the number of - // empty blocks should match empty_block_count(). - size_t expected_empty = storage.empty_block_count(); + // blocks are segregated to the end of the list. const TestAccess::BlockList& list = TestAccess::allocate_list(storage); const OopBlock* block = list.ctail(); - for (size_t i = 0; i < expected_empty; ++i, block = list.prev(*block)) { - if ((block == NULL) || !block->is_empty()) { - return false; - } - } + for ( ; (block != NULL) && block->is_empty(); block = list.prev(*block)) {} for ( ; block != NULL; block = list.prev(*block)) { if (block->is_empty()) { return false; @@ -243,7 +260,7 @@ EXPECT_EQ(1u, _storage.block_count()); EXPECT_EQ(1u, list_length(TestAccess::allocate_list(_storage))); - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); const OopBlock* block = TestAccess::allocate_list(_storage).chead(); EXPECT_NE(block, (OopBlock*)NULL); @@ -259,7 +276,7 @@ EXPECT_EQ(1u, _storage.block_count()); EXPECT_EQ(1u, list_length(TestAccess::allocate_list(_storage))); - EXPECT_EQ(1u, _storage.empty_block_count()); + EXPECT_EQ(1u, empty_block_count(_storage)); const OopBlock* new_block = TestAccess::allocate_list(_storage).chead(); EXPECT_EQ(block, new_block); @@ -322,14 +339,14 @@ TestAccess::BlockList& active_list = TestAccess::active_list(_storage); TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage); - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); entries[0] = _storage.allocate(); ASSERT_TRUE(entries[0] != NULL); EXPECT_EQ(1u, list_length(active_list)); EXPECT_EQ(1u, _storage.block_count()); EXPECT_EQ(1u, list_length(allocate_list)); - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); const OopBlock* block = active_list.chead(); EXPECT_EQ(1u, TestAccess::block_allocation_count(*block)); @@ -339,7 +356,7 @@ entries[i] = _storage.allocate(); EXPECT_EQ(i + 1, _storage.allocation_count()); ASSERT_TRUE(entries[i] != NULL); - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); if (block == NULL) { ASSERT_FALSE(is_list_empty(allocate_list)); @@ -374,7 +391,7 @@ EXPECT_EQ(list_length(active_list), list_length(allocate_list)); EXPECT_EQ(list_length(active_list), _storage.block_count()); - EXPECT_EQ(list_length(active_list), _storage.empty_block_count()); + EXPECT_EQ(list_length(active_list), empty_block_count(_storage)); for (const OopBlock* block = allocate_list.chead(); block != NULL; block = allocate_list.next(*block)) { @@ -386,7 +403,7 @@ static const size_t step = 11; ASSERT_NE(0u, _max_entries % step); // max_entries and step are mutually prime - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); TestAccess::BlockList& active_list = TestAccess::active_list(_storage); TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage); @@ -409,7 +426,7 @@ EXPECT_EQ(list_length(active_list), list_length(allocate_list)); EXPECT_EQ(list_length(active_list), _storage.block_count()); EXPECT_EQ(0u, total_allocation_count(active_list)); - EXPECT_EQ(list_length(allocate_list), _storage.empty_block_count()); + EXPECT_EQ(list_length(allocate_list), empty_block_count(_storage)); } TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) { @@ -417,7 +434,7 @@ static const size_t allocate_step = 5; ASSERT_NE(0u, _max_entries % release_step); // max_entries and step are mutually prime - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); TestAccess::BlockList& active_list = TestAccess::active_list(_storage); TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage); @@ -449,7 +466,7 @@ EXPECT_EQ(list_length(active_list), list_length(allocate_list)); EXPECT_EQ(list_length(active_list), _storage.block_count()); EXPECT_EQ(0u, total_allocation_count(active_list)); - EXPECT_EQ(list_length(allocate_list), _storage.empty_block_count()); + EXPECT_EQ(list_length(allocate_list), empty_block_count(_storage)); } template @@ -471,11 +488,12 @@ EXPECT_EQ(_max_entries - nrelease, _storage.allocation_count()); for (size_t i = 0; i < nrelease; ++i) { - release_entry(_storage, _entries[2 * i + 1]); + release_entry(_storage, _entries[2 * i + 1], false); EXPECT_EQ(_max_entries - nrelease - (i + 1), _storage.allocation_count()); } + EXPECT_TRUE(process_deferred_updates(_storage)); - EXPECT_EQ(_storage.block_count(), _storage.empty_block_count()); + EXPECT_EQ(_storage.block_count(), empty_block_count(_storage)); FREE_C_HEAP_ARRAY(oop*, to_release); } @@ -607,8 +625,9 @@ } while (allocated > 0) { - release_entry(_storage, entries[--allocated]); + release_entry(_storage, entries[--allocated], false); } + process_deferred_updates(_storage); } class OopStorageTestIteration : public OopStorageTestWithAllocation { @@ -627,16 +646,17 @@ memset(_states, 0, sizeof(_states)); size_t initial_release = 0; - for ( ; _storage.empty_block_count() < 2; ++initial_release) { + for ( ; empty_block_count(_storage) < 2; ++initial_release) { ASSERT_GT(_max_entries, initial_release); release_entry(_storage, _entries[initial_release]); _states[0][initial_release] = mark_released; } for (size_t i = initial_release; i < _max_entries; i += 3) { - release_entry(_storage, _entries[i]); + release_entry(_storage, _entries[i], false); _states[0][i] = mark_released; } + process_deferred_updates(_storage); } class VerifyState; @@ -1006,30 +1026,21 @@ EXPECT_EQ(initial_active_size, _storage.block_count()); ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test - for (size_t i = 0; _storage.empty_block_count() < 3; ++i) { + for (size_t i = 0; empty_block_count(_storage) < 3; ++i) { ASSERT_GT(_max_entries, i); release_entry(_storage, _entries[i]); } EXPECT_EQ(initial_active_size, list_length(active_list)); EXPECT_EQ(initial_active_size, _storage.block_count()); - EXPECT_EQ(3u, _storage.empty_block_count()); + EXPECT_EQ(3u, empty_block_count(_storage)); { ThreadInVMfromNative invm(JavaThread::current()); - VM_DeleteBlocksAtSafepoint op(&_storage, 2); + VM_DeleteBlocksAtSafepoint op(&_storage); VMThread::execute(&op); } - EXPECT_EQ(2u, _storage.empty_block_count()); - EXPECT_EQ(initial_active_size - 1, list_length(active_list)); - EXPECT_EQ(initial_active_size - 1, _storage.block_count()); - - { - ThreadInVMfromNative invm(JavaThread::current()); - VM_DeleteBlocksAtSafepoint op(&_storage, 0); - VMThread::execute(&op); - } - EXPECT_EQ(0u, _storage.empty_block_count()); + EXPECT_EQ(0u, empty_block_count(_storage)); EXPECT_EQ(initial_active_size - 3, list_length(active_list)); EXPECT_EQ(initial_active_size - 3, _storage.block_count()); } @@ -1041,22 +1052,17 @@ EXPECT_EQ(initial_active_size, _storage.block_count()); ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test - for (size_t i = 0; _storage.empty_block_count() < 3; ++i) { + for (size_t i = 0; empty_block_count(_storage) < 3; ++i) { ASSERT_GT(_max_entries, i); release_entry(_storage, _entries[i]); } EXPECT_EQ(initial_active_size, list_length(active_list)); EXPECT_EQ(initial_active_size, _storage.block_count()); - EXPECT_EQ(3u, _storage.empty_block_count()); + EXPECT_EQ(3u, empty_block_count(_storage)); - _storage.delete_empty_blocks_concurrent(2); - EXPECT_EQ(2u, _storage.empty_block_count()); - EXPECT_EQ(initial_active_size - 1, list_length(active_list)); - EXPECT_EQ(initial_active_size - 1, _storage.block_count()); - - _storage.delete_empty_blocks_concurrent(0); - EXPECT_EQ(0u, _storage.empty_block_count()); + _storage.delete_empty_blocks_concurrent(); + EXPECT_EQ(0u, empty_block_count(_storage)); EXPECT_EQ(initial_active_size - 3, list_length(active_list)); EXPECT_EQ(initial_active_size - 3, _storage.block_count()); } @@ -1075,13 +1081,14 @@ for (size_t i = 0; i < _max_entries; ++i) { if ((_entries[i] != retained) && (_entries[i] != released)) { - release_entry(_storage, _entries[i]); + // Leave deferred release updates to block deletion. + release_entry(_storage, _entries[i], false); } } { ThreadInVMfromNative invm(JavaThread::current()); - VM_DeleteBlocksAtSafepoint op(&_storage, 0); + VM_DeleteBlocksAtSafepoint op(&_storage); VMThread::execute(&op); } EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained)); @@ -1121,12 +1128,14 @@ TEST_VM_F(OopStorageTestWithAllocation, print_storage) { // Release the first 1/2 for (size_t i = 0; i < (_max_entries / 2); ++i) { - release_entry(_storage, _entries[i]); + // Deferred updates don't affect print output. + release_entry(_storage, _entries[i], false); _entries[i] = NULL; } // Release every other remaining for (size_t i = _max_entries / 2; i < _max_entries; i += 2) { - release_entry(_storage, _entries[i]); + // Deferred updates don't affect print output. + release_entry(_storage, _entries[i], false); _entries[i] = NULL; } @@ -1137,24 +1146,17 @@ size_t expected_blocks = (_max_entries + entries_per_block - 1) / entries_per_block; EXPECT_EQ(expected_blocks, _storage.block_count()); - size_t expected_empties = (_max_entries / 2) / entries_per_block; - EXPECT_EQ(expected_empties, _storage.empty_block_count()); - - size_t expected_used = expected_blocks - expected_empties; - - double expected_usage = (100.0 * expected_entries) / (expected_used * entries_per_block); + double expected_usage = (100.0 * expected_entries) / (expected_blocks * entries_per_block); { ResourceMark rm; stringStream expected_st; expected_st.print("Test Storage: " SIZE_FORMAT " entries in " SIZE_FORMAT - " blocks (%.F%%), " SIZE_FORMAT - " empties, " SIZE_FORMAT " bytes", + " blocks (%.F%%), " SIZE_FORMAT " bytes", expected_entries, - expected_used, + expected_blocks, expected_usage, - expected_empties, _storage.total_memory_usage()); stringStream st; _storage.print_on(&st); diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java --- a/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ /* * @test * @bug 8030976 8059226 + * @requires !vm.graal.enabled * @library /test/lib / * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/TestNUMAPageSize.java --- a/test/hotspot/jtreg/gc/TestNUMAPageSize.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/TestNUMAPageSize.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,11 +23,10 @@ /** * @test TestNUMAPageSize + * @key gc regression * @summary Make sure that start up with NUMA support does not cause problems. * @bug 8061467 * @requires (vm.opt.AggressiveOpts == null) | (vm.opt.AggressiveOpts == false) - * @key gc - * @key regression * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize */ diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/arguments/TestAlignmentToUseLargePages.java --- a/test/hotspot/jtreg/gc/arguments/TestAlignmentToUseLargePages.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/arguments/TestAlignmentToUseLargePages.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,11 +23,10 @@ /** * @test TestAlignmentToUseLargePages + * @key gc regression * @summary All parallel GC variants may use large pages without the requirement that the * heap alignment is large page aligned. Other collectors also need to start up with odd sized heaps. * @bug 8024396 - * @key gc - * @key regression * @requires vm.gc=="null" * @run main/othervm -Xms71M -Xmx91M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UseLargePages TestAlignmentToUseLargePages * @run main/othervm -Xms71M -Xmx91M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseLargePages TestAlignmentToUseLargePages diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/cms/GuardShrinkWarning.java --- a/test/hotspot/jtreg/gc/cms/GuardShrinkWarning.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/cms/GuardShrinkWarning.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,10 +23,9 @@ /** * @test GuardShrinkWarning + * @key gc regression * @summary Remove warning about CMS generation shrinking. * @bug 8012111 - * @key gc - * @key regression * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/g1/Test2GbHeap.java --- a/test/hotspot/jtreg/gc/g1/Test2GbHeap.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/g1/Test2GbHeap.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,13 +23,12 @@ /* * @test Test2GbHeap + * @key gc regression * @bug 8031686 * @summary Regression test to ensure we can start G1 with 2gb heap. * Skip test on 32 bit system: it typically does not support the many and large virtual memory reservations needed. * @requires vm.gc.G1 * @requires vm.bits != "32" - * @key gc - * @key regression * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java --- a/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,8 +23,7 @@ /* * @test - * @key regression - * @key gc + * @key regression gc * @bug 8027756 * @requires vm.gc.G1 * @library /test/lib diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/g1/TestParallelAlwaysPreTouch.java --- a/test/hotspot/jtreg/gc/g1/TestParallelAlwaysPreTouch.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/g1/TestParallelAlwaysPreTouch.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,13 +23,12 @@ /* * @test + * @key gc regression * @bug 8169703 * @summary Regression test to ensure AlwaysPreTouch with multiple threads works at mutator time. * Allocates a few humongous objects that will be allocated by expanding the heap, causing concurrent parallel * pre-touch. * @requires vm.gc.G1 - * @key gc - * @key regression * @run main/othervm -XX:+UseG1GC -Xms10M -Xmx100m -XX:G1HeapRegionSize=1M -XX:+AlwaysPreTouch -XX:PreTouchParallelChunkSize=512k -Xlog:gc+ergo+heap=debug,gc+heap=debug,gc=debug TestParallelAlwaysPreTouch */ diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/logging/TestUnifiedLoggingSwitchStress.java --- a/test/hotspot/jtreg/gc/logging/TestUnifiedLoggingSwitchStress.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/logging/TestUnifiedLoggingSwitchStress.java Sat Feb 10 09:25:35 2018 +0100 @@ -39,9 +39,8 @@ /** * @test TestUnifiedLoggingSwitchStress + * @key gc stress * @summary Switches gc log level on fly while stressing memory/gc - * @key gc - * @key stress * @requires !vm.flightRecorder * @library /test/lib / * @modules java.management java.base/jdk.internal.misc diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/parallel/AdaptiveGCBoundary.java --- a/test/hotspot/jtreg/gc/parallel/AdaptiveGCBoundary.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/parallel/AdaptiveGCBoundary.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,10 +23,9 @@ /** * @test AdaptiveGCBoundary + * @key gc regression * @summary UseAdaptiveGCBoundary is broken * @bug 8014546 - * @key gc - * @key regression * @library /test/lib * @modules java.base/jdk.internal.misc * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java --- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java Sat Feb 10 09:25:35 2018 +0100 @@ -23,8 +23,7 @@ /* * @test TestStressG1Humongous - * @key gc - * @key stress + * @key gc stress * @summary Stress G1 by humongous allocations in situation near OOM * @requires vm.gc.G1 * @requires !vm.flightRecorder diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithAllocateHeapAt.java --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithAllocateHeapAt.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithAllocateHeapAt.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,7 @@ /* * @test TestGCBasherWithAllocateHeapAt - * @key gc - * @key stress + * @key gc stress * @requires vm.gc.G1 * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress Java heap allocation with AllocateHeapAt flag using GC basher. diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithCMS.java --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithCMS.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithCMS.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,7 @@ /* * @test TestGCBasherWithCMS - * @key gc - * @key stress + * @key gc stress * @requires vm.gc.ConcMarkSweep * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the CMS GC by trying to make old objects more likely to be garbage than young objects. diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,7 @@ /* * @test TestGCBasherWithG1 - * @key gc - * @key stress + * @key gc stress * @requires vm.gc.G1 * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the G1 GC by trying to make old objects more likely to be garbage than young objects. diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithParallel.java --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithParallel.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithParallel.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,7 @@ /* * @test TestGCBasherWithParallel - * @key gc - * @key stress + * @key gc stress * @requires vm.gc.Parallel * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the Parallel GC by trying to make old objects more likely to be garbage than young objects. diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithSerial.java --- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithSerial.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithSerial.java Sat Feb 10 09:25:35 2018 +0100 @@ -26,8 +26,7 @@ /* * @test TestGCBasherWithSerial - * @key gc - * @key stress + * @key gc stress * @requires vm.gc.Serial * @requires vm.flavor == "server" & !vm.emulatedClient * @summary Stress the Serial GC by trying to make old objects more likely to be garbage than young objects. diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithCMS.java --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithCMS.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithCMS.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,9 +24,8 @@ /* * @test TestSystemGCWithCMS + * @key gc stress * @bug 8190703 - * @key gc - * @key stress * @requires vm.gc.ConcMarkSweep * @summary Stress the CMS GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseConcMarkSweepGC TestSystemGCWithCMS 270 diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,9 +24,8 @@ /* * @test TestSystemGCWithG1 + * @key gc stress * @bug 8190703 - * @key gc - * @key stress * @requires vm.gc.G1 * @summary Stress the G1 GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC TestSystemGCWithG1 270 diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,9 +24,8 @@ /* * @test TestSystemGCWithParallel + * @key gc stress * @bug 8190703 - * @key gc - * @key stress * @requires vm.gc.Parallel * @summary Stress the Parallel GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * @run main/othervm/timeout=300 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC TestSystemGCWithParallel 270 diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java --- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,9 +24,8 @@ /* * @test TestSystemGCWithSerial + * @key gc stress * @bug 8190703 - * @key gc - * @key stress * @requires vm.gc.Serial * @summary Stress the Serial GC full GC by allocating objects of different lifetimes concurrently with System.gc(). * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC TestSystemGCWithSerial 270 diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, 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,6 +47,8 @@ {"InitialRAMFraction", "64"}, {"AssumeMP", "false"}, {"UseMembar", "true"}, + {"CompilerThreadHintNoPreempt", "true"}, + {"VMThreadHintNoPreempt", "false"}, // deprecated alias flags (see also aliased_jvm_flags): {"DefaultMaxRAMFraction", "4"}, diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018, 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 8193184 + * @key nmt + * @summary Check class counters in summary report + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run main/othervm -Xbootclasspath/a:. -XX:NativeMemoryTracking=summary JcmdSummaryClass + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.JDKToolFinder; + + +import java.util.regex.*; + +public class JcmdSummaryClass { + + public static void main(String args[]) throws Exception { + ProcessBuilder pb = new ProcessBuilder(); + OutputAnalyzer output; + // Grab my own PID + String pid = Long.toString(ProcessTools.getProcessId()); + + // Run 'jcmd VM.native_memory baseline=true' + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory"}); + pb.start().waitFor(); + + String classes_line = "classes #\\d+"; + String instance_array_classes_line = "instance classes #\\d+, array classes #\\d+"; + output = new OutputAnalyzer(pb.start()); + output.shouldMatch(classes_line); + output.shouldMatch(instance_array_classes_line); + } +} diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java Sat Feb 10 09:25:35 2018 +0100 @@ -29,6 +29,7 @@ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti * @requires vm.cds * @requires vm.flavor != "minimal" + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * jdk.jartool/sun.tools.jar * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti * @requires vm.cds * @requires vm.flavor != "minimal" + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * jdk.jartool/sun.tools.jar * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java --- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti * @requires vm.cds * @requires vm.flavor != "minimal" + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * jdk.jartool/sun.tools.jar * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/appcds/jvmti/parallelLoad/ParallelLoadAndTransformTest.java --- a/test/hotspot/jtreg/runtime/appcds/jvmti/parallelLoad/ParallelLoadAndTransformTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/appcds/jvmti/parallelLoad/ParallelLoadAndTransformTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -30,6 +30,7 @@ * /test/hotspot/jtreg/runtime/appcds/test-classes /test/hotspot/jtreg/runtime/appcds/jvmti * /test/hotspot/jtreg/testlibrary/jvmti * @requires vm.cds + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * java.management * jdk.jartool/sun.tools.jar diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformInterfaceImplementorAppCDS.java --- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformInterfaceImplementorAppCDS.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformInterfaceImplementorAppCDS.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,7 @@ * /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes * @requires vm.cds * @requires vm.flavor != "minimal" + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * jdk.jartool/sun.tools.jar * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformSuperSubAppCDS.java --- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformSuperSubAppCDS.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformSuperSubAppCDS.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,7 @@ * /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes * @requires vm.cds * @requires vm.flavor != "minimal" + * @requires !vm.graal.enabled * @modules java.base/jdk.internal.misc * jdk.jartool/sun.tools.jar * java.management diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-ppc64le --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-ppc64le Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,10 @@ +# test on x86_64 uses Oracle Linux but we do not have this for ppc64le +# so use some other Linux where OpenJDK works +# FROM oraclelinux:7.2 +FROM ppc64le/ubuntu + +COPY /jdk /jdk + +ENV JAVA_HOME=/jdk + +CMD ["/bin/bash"] diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/CanGenerateAllClassHook.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/CanGenerateAllClassHook.java Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2018, 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 8161605 + * @summary Tests that jvmtiEnv::GetPotentialCapabilities reports + * can_generate_all_class_hook_events capability with CDS (-Xshare:on) + * at ONLOAD and LIVE phases + * @library /test/lib + * @compile CanGenerateAllClassHook.java + * @run main/othervm/native CanGenerateAllClassHook + */ + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import java.io.File; +import java.io.IOException; + +/* + * The simplest way to test is to use system classes.jsa, + * but we cannot rely on tested JRE/JDK has it. + * So the test runs 2 java processes - + * 1st to generate custom shared archive file: + * java -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile= -Xshare:dump + * and 2nd to perform the actual testing using generated shared archive: + * java -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile= -Xshare:on + * -agentlib: CanGenerateAllClassHook + */ +public class CanGenerateAllClassHook { + + private static final String agentLib = "CanGenerateAllClassHook"; + + private static native int getClassHookAvail(); + private static native int getOnLoadClassHookAvail(); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + // this is master run + + final File jsaFile = File.createTempFile(agentLib, ".jsa"); + jsaFile.deleteOnExit(); + final String jsaPath = jsaFile.getAbsolutePath(); + + log("generating CDS archive..."); + execJava( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + jsaPath, + "-Xshare:dump") + .shouldHaveExitValue(0); + log("CDS generation completed."); + + OutputAnalyzer output = execJava( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + jsaPath, + "-Xshare:on", + "-agentlib:" + agentLib, + // copy java.library.path + "-Djava.library.path=" + System.getProperty("java.library.path"), + // specify "-showversion" to ensure the test runs in shared mode + "-showversion", + // class to run + CanGenerateAllClassHook.class.getCanonicalName(), + // and arg + "test"); + // Xshare:on can cause intermittent failure + // checkExec handles this. + CDSTestUtils.checkExec(output); + + log("Test PASSED."); + } else { + // this is test run + try { + System.loadLibrary(agentLib); + } catch (UnsatisfiedLinkError ex) { + System.err.println("Failed to load " + agentLib + " lib"); + System.err.println("java.library.path: " + System.getProperty("java.library.path")); + throw ex; + } + + final int onLoadValue = getOnLoadClassHookAvail(); + final int liveValue = getClassHookAvail(); + // Possible values returned: + // 1 - the capability is supported; + // 0 - the capability is not supported; + // -1 - error occured. + + log("can_generate_all_class_hook_events value capability:"); + log("ONLOAD phase: " + (onLoadValue < 0 ? "Failed to read" : onLoadValue)); + log("LIVE phase: " + (liveValue < 0 ? "Failed to read" : liveValue)); + if (onLoadValue != 1 || liveValue != 1) { + throw new RuntimeException("The can_generate_all_class_hook_events capability " + + " is expected to be available in both ONLOAD and LIVE phases"); + } + } + } + + private static void log(String msg) { + System.out.println(msg); + System.out.flush(); + } + + private static OutputAnalyzer execJava(String... args) throws IOException { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + log("[STDERR]\n" + output.getStderr()); + log("[STDOUT]\n" + output.getStdout()); + + return output; + } + +} diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/libCanGenerateAllClassHook.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/libCanGenerateAllClassHook.c Sat Feb 10 09:25:35 2018 +0100 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2018, 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. + */ + +#include +#include +#include "jvmti.h" +#include "jni.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_ARG + +#ifdef __cplusplus +#define JNI_ENV_ARG(x, y) y +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG(x,y) x, y +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + + +static jvmtiEnv *jvmti = NULL; + +typedef enum { + Yes = 1, + No = 0, + Error = -1 +} IsAvail; + +static IsAvail onLoadIsAvail = Error; + +void reportError(const char *msg, int err) { + printf("%s, error: %d\n", msg, err); +} + +static IsAvail isClassHookAvail() { + IsAvail result = Error; + do { + jvmtiCapabilities caps; + jvmtiPhase phase; + jvmtiError err; + + if (jvmti == NULL) { + reportError("jvmti is NULL", -1); + break; + } + + err = (*jvmti)->GetPhase(jvmti, &phase); + if (err != JVMTI_ERROR_NONE) { + reportError("GetPhase failed", err); + break; + } + + err = (*jvmti)->GetPotentialCapabilities(jvmti, &caps); + if (err != JVMTI_ERROR_NONE) { + reportError("GetPotentialCapabilities failed", err); + break; + } + + result = caps.can_generate_all_class_hook_events ? Yes : No; + + printf("isClassHookAvail: phase=%d, value=%d\n", phase, result); + } while (0); + return result; +} + + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) +{ + jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == NULL) { + reportError("GetEnv failed", res); + return JNI_ERR; + } + + // check and save can_generate_all_class_hook_events for ONLOAD phase + onLoadIsAvail = isClassHookAvail(); + + return JNI_OK; +} + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { + return JNI_VERSION_9; +} + + +JNIEXPORT jint JNICALL +Java_CanGenerateAllClassHook_getClassHookAvail(JNIEnv *env, jclass cls) { + return isClassHookAvail(); +} + +JNIEXPORT jint JNICALL +Java_CanGenerateAllClassHook_getOnLoadClassHookAvail(JNIEnv *env, jclass cls) { + return onLoadIsAvail; +} + + +#ifdef __cplusplus +} +#endif + diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,9 +48,9 @@ LingeredApp.startApp(null, theApp); System.out.println("Started LingeredApp with pid " + theApp.getPid()); - // Run the 'jstack -v' command to get the address of a Method* - // and the oop address of a java.lang.ref.ReferenceQueue$Lock - // object + // Run the 'jstack -v' command to get the address of a Method*, + // the oop address of a java.lang.ref.ReferenceQueue$Lock + // and the oop address of a java.lang.Class object List cmds = List.of("jstack -v"); String jstackOutput = test.run(theApp.getPid(), cmds, null, null); @@ -62,26 +62,37 @@ return; } - String addressString = null; Map tokensMap = new HashMap<>(); - tokensMap.put("waiting to lock", + tokensMap.put("(a java.lang.Class for LingeredAppWithLock)", "instance of Oop for java/lang/Class"); - tokensMap.put("Method\\*=", "Type is Method"); - tokensMap.put("waiting to re-lock in wait", + tokensMap.put("Method*=", "Type is Method"); + tokensMap.put("(a java.lang.ref.ReferenceQueue$Lock)", "instance of Oop for java/lang/ref/ReferenceQueue$Lock"); + String[] lines = jstackOutput.split("\\R"); + for (String key: tokensMap.keySet()) { cmds = new ArrayList(); Map> expStrMap = new HashMap<>(); - String[] snippets = jstackOutput.split(key); - String[] tokens = snippets[1].split(" "); - for (String token: tokens) { - if (token.contains("0x")) { - addressString = token.replace("<", "").replace(">", ""); - break; - } - } + String addressString = null; + for (String line : lines) { + if (line.contains(key)) { + // Escape the token "Method*=" because the split method uses + // a regex, not just a straight String. + String escapedKey = key.replace("*","\\*"); + String[] words = line.split(escapedKey+"|[ ]"); + for (String word : words) { + word = word.replace("<","").replace(">",""); + if (word.startsWith("0x")) { + addressString = word; + break; + } + } + if (addressString != null) + break; + } + } String cmd = "inspect " + addressString; cmds.add(cmd); diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/serviceability/sa/ClhsdbWhere.java --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbWhere.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbWhere.java Sat Feb 10 09:25:35 2018 +0100 @@ -56,9 +56,8 @@ "Java Stack Trace for Sweeper thread", "CompilerThread", "Java Stack Trace for Finalizer", - "java.lang.ref.Reference", - "private static void processPendingReferences", - "private static native void waitForReferencePendingList", + "Java Stack Trace for Signal Dispatcher", + "Java Stack Trace for Reference Handler", "Java Stack Trace for main", "public static void main")); diff -r 0006d97556ba -r 7c23209e4873 test/hotspot/jtreg/testlibrary/jvmti/TransformerAgent.java --- a/test/hotspot/jtreg/testlibrary/jvmti/TransformerAgent.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/hotspot/jtreg/testlibrary/jvmti/TransformerAgent.java Sat Feb 10 09:25:35 2018 +0100 @@ -57,17 +57,25 @@ static class SimpleTransformer implements ClassFileTransformer { - public byte[] transform(ClassLoader loader, String name, Class classBeingRedefined, - ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException { + public byte[] transform(ClassLoader loader, String name, Class classBeingRedefined, + ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException { + try { + log("SimpleTransformer called for: " + name + "@" + incrCounter(name)); + if (!shouldTransform(name)) + return null; - log("SimpleTransformer called for: " + name + "@" + incrCounter(name)); - if (!shouldTransform(name)) - return null; - - log("transforming: class name = " + name); - int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern, - TransformUtil.AfterPattern); - log("replaced the string, nrOfReplacements = " + nrOfReplacements); + log("transforming: class name = " + name); + int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern, + TransformUtil.AfterPattern); + log("replaced the string, nrOfReplacements = " + nrOfReplacements); + } catch (Throwable t) { + // The retransform native code that called this method does not propagate + // exceptions. Instead of getting an uninformative generic error, catch + // problems here and print it, then exit. + log("Transformation failed!"); + t.printStackTrace(); + System.exit(1); + } return buffer; } diff -r 0006d97556ba -r 7c23209e4873 test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java --- a/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -24,6 +24,7 @@ /* * @test * @bug 8164512 8191360 + * @requires vm.compMode != "Xcomp" * @summary verify if the native library is unloaded when the class loader is GC'ed * @build p.Test * @run main/othervm/native -Xcheck:jni NativeLibraryTest diff -r 0006d97556ba -r 7c23209e4873 test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java --- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -25,6 +25,7 @@ * @test * @bug 8186046 8195694 * @summary Test dynamic constant bootstraps + * @requires os.arch != "sparcv9" * @library /lib/testlibrary/bytecode /java/lang/invoke/common * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper * @run testng ConstantBootstrapsTest diff -r 0006d97556ba -r 7c23209e4873 test/jdk/sun/misc/SunMiscSignalTest.java --- a/test/jdk/sun/misc/SunMiscSignalTest.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/jdk/sun/misc/SunMiscSignalTest.java Sat Feb 10 09:25:35 2018 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, 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 @@ -112,7 +112,6 @@ Object[][] posixSignals = { {"HUP", IsSupported.YES, registerXrs, raiseXrs, invokedXrs}, {"QUIT", IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO}, - {"BUS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, {"USR1", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, {"USR2", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, {"PIPE", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, @@ -132,6 +131,14 @@ {"SYS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, }; + Object[][] posixNonOSXSignals = { + {"BUS", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs}, + }; + + Object[][] posixOSXSignals = { + {"BUS", IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO}, + }; + Object[][] windowsSignals = { {"HUP", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, {"QUIT", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, @@ -155,7 +162,9 @@ {"SYS", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO}, }; - return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : posixSignals)); + Object[][] combinedPosixSignals = concatArrays(posixSignals, + (Platform.isOSX() ? posixOSXSignals : posixNonOSXSignals)); + return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : combinedPosixSignals)); } // Provider of invalid signal names diff -r 0006d97556ba -r 7c23209e4873 test/jtreg-ext/requires/VMProps.java --- a/test/jtreg-ext/requires/VMProps.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/jtreg-ext/requires/VMProps.java Sat Feb 10 09:25:35 2018 +0100 @@ -352,9 +352,11 @@ * @return true if docker is supported in a given environment */ protected String dockerSupport() { - // currently docker testing is only supported for Linux-x64 - if (! ( Platform.isLinux() && Platform.isX64() ) ) + // currently docker testing is only supported for Linux-x64 and Linux-ppc64le + String arch = System.getProperty("os.arch"); + if (! (Platform.isLinux() && (Platform.isX64() || arch.equals("ppc64le")))) { return "false"; + } boolean isSupported; try { diff -r 0006d97556ba -r 7c23209e4873 test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java --- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java Tue Feb 13 14:41:54 2018 -0500 +++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java Sat Feb 10 09:25:35 2018 +0100 @@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import jdk.test.lib.Platform; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -109,7 +110,9 @@ * The jdk will be placed under the "/jdk/" folder inside the docker file system. * * @param imageName name of the image to be created, including version tag - * @param dockerfile name of the dockerfile residing in the test source + * @param dockerfile name of the dockerfile residing in the test source; + * we check for a platform specific dockerfile as well + * and use this one in case it exists * @param buildDirName name of the docker build/staging directory, which will * be created in the jtreg's scratch folder * @throws Exception @@ -122,6 +125,11 @@ if (Files.exists(buildDir)) { throw new RuntimeException("The docker build directory already exists: " + buildDir); } + // check for the existance of a platform specific docker file as well + String platformSpecificDockerfile = dockerfile + "-" + Platform.getOsArch(); + if (Files.exists(Paths.get(Utils.TEST_SRC, platformSpecificDockerfile))) { + dockerfile = platformSpecificDockerfile; + } Path jdkSrcDir = Paths.get(Utils.TEST_JDK); Path jdkDstDir = buildDir.resolve("jdk");