--- a/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -370,3 +370,4 @@
3aa52182b3ad7c5b3a61cf05a59dd07e4c5884e5 jdk-9+125
03e7b2c5ae345be3caf981d76ceb3efe5ff447f8 jdk-9+126
8e45018bde9de4ad15b972ae62874bba52dba2d5 jdk-9+127
+5bf88dce615f6804f9e101a96ffa7c9dfb4fbbbe jdk-9+128
--- a/.hgtags-top-repo Wed Jul 27 08:33:15 2016 -0400
+++ b/.hgtags-top-repo Wed Jul 27 13:33:55 2016 +0000
@@ -370,3 +370,4 @@
9aa7d40f3a453f51e47f4c1b19eff5740a74a9f8 jdk-9+125
3a58466296d36944454756ef01e7513ac5e14a16 jdk-9+126
8fa686245bd2a072ece3392743460030f0854520 jdk-9+127
+b30ae794d974d7dd3eb4e84203f70021823fa6c6 jdk-9+128
--- a/common/autoconf/boot-jdk.m4 Wed Jul 27 08:33:15 2016 -0400
+++ b/common/autoconf/boot-jdk.m4 Wed Jul 27 13:33:55 2016 +0000
@@ -345,6 +345,9 @@
# Disable special log output when a debug build is used as Boot JDK...
ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA])
+ # Force en-US environment
+ ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA])
+
# Apply user provided options.
ADD_JVM_ARG_IF_OK([$with_boot_jdk_jvmargs],boot_jdk_jvmargs,[$JAVA])
--- a/common/autoconf/generated-configure.sh Wed Jul 27 08:33:15 2016 -0400
+++ b/common/autoconf/generated-configure.sh Wed Jul 27 13:33:55 2016 +0000
@@ -5094,7 +5094,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1467960715
+DATE_WHEN_GENERATED=1469202305
###############################################################################
#
@@ -65048,6 +65048,23 @@
fi
+ # Force en-US environment
+
+ $ECHO "Check if jvm arg is ok: -Duser.language=en -Duser.country=US" >&5
+ $ECHO "Command: $JAVA -Duser.language=en -Duser.country=US -version" >&5
+ OUTPUT=`$JAVA -Duser.language=en -Duser.country=US -version 2>&1`
+ FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
+ FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
+ if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+ boot_jdk_jvmargs="$boot_jdk_jvmargs -Duser.language=en -Duser.country=US"
+ JVM_ARG_OK=true
+ else
+ $ECHO "Arg failed:" >&5
+ $ECHO "$OUTPUT" >&5
+ JVM_ARG_OK=false
+ fi
+
+
# Apply user provided options.
$ECHO "Check if jvm arg is ok: $with_boot_jdk_jvmargs" >&5
--- a/corba/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/corba/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -370,3 +370,4 @@
1d48e67d1b91eb9f72e49e69a4021edb85e357fc jdk-9+125
c7f5ba08fcd4b8416e62c21229f9a07c95498919 jdk-9+126
8fab452b6f4710762ba1d8e55fd62db00b1355fe jdk-9+127
+1f093d3f8cd99cd37c3b0af4cf5c3bffaa9c8b98 jdk-9+128
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/activation/ORBD.java Wed Jul 27 08:33:15 2016 -0400
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/activation/ORBD.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,4 @@
/*
- *
* Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -22,7 +21,6 @@
* 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 com.sun.corba.se.impl.activation;
--- a/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java Wed Jul 27 08:33:15 2016 -0400
+++ b/corba/src/java.corba/share/classes/com/sun/corba/se/impl/orbutil/ORBUtility.java Wed Jul 27 13:33:55 2016 +0000
@@ -34,21 +34,13 @@
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Map;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Set;
-import java.util.Map.Entry;
-import java.util.Collection;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Enumeration;
-import java.util.Properties;
-import java.util.IdentityHashMap;
import java.util.StringTokenizer;
import java.util.NoSuchElementException;
@@ -165,8 +157,18 @@
* Return default ValueHandler
*/
public static ValueHandler createValueHandler() {
+ ValueHandler vh;
+ try {
+ vh = AccessController.doPrivileged(new PrivilegedExceptionAction<ValueHandler>() {
+ public ValueHandler run() throws Exception {
return Util.createValueHandler();
}
+ });
+ } catch (PrivilegedActionException e) {
+ throw new InternalError(e.getCause());
+ }
+ return vh;
+ }
/**
* Returns true if it was accurately determined that the remote ORB is
@@ -664,7 +666,16 @@
* ValueHandler.
*/
public static byte getMaxStreamFormatVersion() {
- ValueHandler vh = Util.createValueHandler();
+ ValueHandler vh;
+ try {
+ vh = AccessController.doPrivileged(new PrivilegedExceptionAction<ValueHandler>() {
+ public ValueHandler run() throws Exception {
+ return Util.createValueHandler();
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new InternalError(e.getCause());
+ }
if (!(vh instanceof javax.rmi.CORBA.ValueHandlerMultiFormat))
return ORBConstants.STREAM_FORMAT_VERSION_1;
--- a/corba/src/java.corba/share/classes/javax/rmi/CORBA/Util.java Wed Jul 27 08:33:15 2016 -0400
+++ b/corba/src/java.corba/share/classes/javax/rmi/CORBA/Util.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@
import java.rmi.Remote;
import java.io.File;
import java.io.FileInputStream;
+import java.io.SerializablePermission;
import java.net.MalformedURLException ;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -195,6 +196,8 @@
*/
public static ValueHandler createValueHandler() {
+ isCustomSerializationPermitted();
+
if (utilDelegate != null) {
return utilDelegate.createValueHandler();
}
@@ -337,6 +340,7 @@
// security reasons. If you know a better solution how to share this code
// then remove it from PortableRemoteObject. Also in Stub.java
private static Object createDelegate(String classKey) {
+
String className = (String)
AccessController.doPrivileged(new GetPropertyAction(classKey));
if (className == null) {
@@ -345,7 +349,6 @@
className = props.getProperty(classKey);
}
}
-
if (className == null) {
return new com.sun.corba.se.impl.javax.rmi.CORBA.Util();
}
@@ -389,4 +392,14 @@
new GetORBPropertiesFileAction());
}
+ private static void isCustomSerializationPermitted() {
+ SecurityManager sm = System.getSecurityManager();
+ if ( sm != null) {
+ // check that a serialization permission has been
+ // set to allow the loading of the Util delegate
+ // which provides access to custom ValueHandler
+ sm.checkPermission(new SerializablePermission(
+ "enableCustomValueHandler"));
}
+ }
+}
--- a/hotspot/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -530,3 +530,4 @@
bb640b49741af3f57f9994129934c46fc173219f jdk-9+125
adc8c84b7cf8c540d920182f78a2bc982366432a jdk-9+126
352357128f602dcf0426b1cbe011a4685a4d9f97 jdk-9+127
+22bf6db9767b1b3a1994cbf32eb3331f31ae2093 jdk-9+128
--- a/hotspot/make/test/JtregNative.gmk Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/make/test/JtregNative.gmk Wed Jul 27 13:33:55 2016 +0000
@@ -51,6 +51,7 @@
$(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
$(HOTSPOT_TOPDIR)/test/compiler/calls \
$(HOTSPOT_TOPDIR)/test/compiler/native \
+ $(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
$(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
#
@@ -64,6 +65,7 @@
ifeq ($(TOOLCHAIN_TYPE), solstudio)
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libSimpleClassFileLoadHook := -lc
+ BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libGetNamedModuleTest := -lc
endif
BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1742,11 +1742,11 @@
}
typedef struct {
- Elf32_Half code; // Actual value as defined in elf.h
- Elf32_Half compat_class; // Compatibility of archs at VM's sense
- char elf_class; // 32 or 64 bit
- char endianess; // MSB or LSB
- char* name; // String representation
+ Elf32_Half code; // Actual value as defined in elf.h
+ Elf32_Half compat_class; // Compatibility of archs at VM's sense
+ unsigned char elf_class; // 32 or 64 bit
+ unsigned char endianess; // MSB or LSB
+ char* name; // String representation
} arch_t;
#ifndef EM_486
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1320,36 +1320,8 @@
}
bool os::supports_vtime() { return true; }
-
-bool os::enable_vtime() {
- int fd = ::open("/proc/self/ctl", O_WRONLY);
- if (fd == -1) {
- return false;
- }
-
- long cmd[] = { PCSET, PR_MSACCT };
- int res = ::write(fd, cmd, sizeof(long) * 2);
- ::close(fd);
- if (res != sizeof(long) * 2) {
- return false;
- }
- return true;
-}
-
-bool os::vtime_enabled() {
- int fd = ::open("/proc/self/status", O_RDONLY);
- if (fd == -1) {
- return false;
- }
-
- pstatus_t status;
- int res = os::read(fd, (void*) &status, sizeof(pstatus_t));
- ::close(fd);
- if (res != sizeof(pstatus_t)) {
- return false;
- }
- return status.pr_flags & PR_MSACCT;
-}
+bool os::enable_vtime() { return false; }
+bool os::vtime_enabled() { return false; }
double os::elapsedVTime() {
return (double)gethrvtime() / (double)hrtime_hz;
--- a/hotspot/src/share/vm/classfile/altHashing.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/altHashing.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -224,7 +224,7 @@
static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
-static const jint ONE_INT[] = { 0x83828180};
+static const jint ONE_INT[] = { (jint)0x83828180};
static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
static const jbyte EIGHT_BYTE[] = {
@@ -235,7 +235,7 @@
(jchar) 0x8180, (jchar) 0x8382,
(jchar) 0x8584, (jchar) 0x8786};
-static const jint TWO_INT[] = { 0x83828180, 0x87868584};
+static const jint TWO_INT[] = { (jint)0x83828180, (jint)0x87868584};
static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -142,7 +142,9 @@
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
- _handles->oops_do(f);
+ if (_handles != NULL) {
+ _handles->oops_do(f);
+ }
if (klass_closure != NULL) {
classes_do(klass_closure);
}
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -270,6 +270,10 @@
// For reading from/writing to the CDS archive
void serialize(SerializeClosure* soc);
+
+ uintx base_address() {
+ return (uintx) _base_address;
+ }
};
////////////////////////////////////////////////////////////////////////
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -871,12 +871,17 @@
int java_lang_Class::oop_size(oop java_class) {
assert(_oop_size_offset != 0, "must be set");
- return java_class->int_field(_oop_size_offset);
-}
+ int size = java_class->int_field(_oop_size_offset);
+ assert(size > 0, "Oop size must be greater than zero, not %d", size);
+ return size;
+}
+
void java_lang_Class::set_oop_size(oop java_class, int size) {
assert(_oop_size_offset != 0, "must be set");
+ assert(size > 0, "Oop size must be greater than zero, not %d", size);
java_class->int_field_put(_oop_size_offset, size);
}
+
int java_lang_Class::static_oop_field_count(oop java_class) {
assert(_static_oop_field_count_offset != 0, "must be set");
return java_class->int_field(_static_oop_field_count_offset);
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -275,7 +275,6 @@
static int static_oop_field_count(oop java_class);
static void set_static_oop_field_count(oop java_class, int size);
-
static GrowableArray<Klass*>* fixup_mirror_list() {
return _fixup_mirror_list;
}
--- a/hotspot/src/share/vm/classfile/modules.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/modules.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -820,6 +820,28 @@
}
+jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
+ assert(ModuleEntryTable::javabase_defined(),
+ "Attempt to call get_named_module before java.base is defined");
+ assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
+ "Class loader is not a subclass of java.lang.ClassLoader");
+ assert(package_str != NULL, "the package_str should not be NULL");
+
+ if (strlen(package_str) == 0) {
+ return NULL;
+ }
+ TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
+ const PackageEntry* const pkg_entry =
+ get_package_entry_by_name(package_sym, h_loader, THREAD);
+ const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
+
+ if (module_entry != NULL && module_entry->module() != NULL && module_entry->is_named()) {
+ return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->module()));
+ }
+ return NULL;
+}
+
+
// This method is called by JFR and by the above method.
jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
const PackageEntry* const pkg_entry =
--- a/hotspot/src/share/vm/classfile/modules.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/modules.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -121,6 +121,7 @@
// IllegalArgumentException is thrown if loader is neither null nor a subtype of
// java/lang/ClassLoader.
static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
+ static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
// If package is defined by loader, return the
// java.lang.reflect.Module object for the module in which the package is defined.
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -238,6 +238,29 @@
}
}
+u4 SymbolTable::encode_shared(Symbol* sym) {
+ assert(DumpSharedSpaces, "called only during dump time");
+ uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+ uintx offset = uintx(sym) - base_address;
+ assert(offset < 0x7fffffff, "sanity");
+ return u4(offset);
+}
+
+Symbol* SymbolTable::decode_shared(u4 offset) {
+ assert(!DumpSharedSpaces, "called only during runtime");
+ uintx base_address = _shared_table.base_address();
+ Symbol* sym = (Symbol*)(base_address + offset);
+
+#ifndef PRODUCT
+ const char* s = (const char*)sym->bytes();
+ int len = sym->utf8_length();
+ unsigned int hash = hash_symbol(s, len);
+ assert(sym == lookup_shared(s, len, hash), "must be shared symbol");
+#endif
+
+ return sym;
+}
+
// Pick hashing algorithm.
unsigned int SymbolTable::hash_symbol(const char* s, int len) {
return use_alternate_hashcode() ?
--- a/hotspot/src/share/vm/classfile/symbolTable.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/symbolTable.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -253,6 +253,8 @@
// Sharing
static void serialize(SerializeClosure* soc);
+ static u4 encode_shared(Symbol* sym);
+ static Symbol* decode_shared(u4 offset);
// Rehash the symbol table if it gets out of balance
static void rehash_table();
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -78,7 +78,19 @@
TRAPS) {
return NULL;
}
+
static void serialize(SerializeClosure* soc) {}
+
+ // The (non-application) CDS implementation supports only classes in the boot
+ // class loader, which ensures that the verification constraints are the same
+ // during archive creation time and runtime. Thus we can do the constraint checks
+ // entirely during archive creation time.
+ static bool add_verification_constraint(Klass* k, Symbol* name,
+ Symbol* from_name, bool from_field_is_protected,
+ bool from_is_array, bool from_is_object) {return false;}
+ static void finalize_verification_constraints() {}
+ static void check_verification_constraints(instanceKlassHandle klass,
+ TRAPS) {}
};
#endif // SHARE_VM_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP
--- a/hotspot/src/share/vm/classfile/verificationType.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/verificationType.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionaryShared.hpp"
#include "classfile/verificationType.hpp"
#include "classfile/verifier.hpp"
@@ -41,6 +42,39 @@
}
}
+bool VerificationType::resolve_and_check_assignability(instanceKlassHandle klass, Symbol* name,
+ Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, TRAPS) {
+ Klass* obj = SystemDictionary::resolve_or_fail(
+ name, Handle(THREAD, klass->class_loader()),
+ Handle(THREAD, klass->protection_domain()), true, CHECK_false);
+ if (log_is_enabled(Debug, class, resolve)) {
+ Verifier::trace_class_resolution(obj, klass());
+ }
+
+ KlassHandle this_class(THREAD, obj);
+
+ if (this_class->is_interface() && (!from_field_is_protected ||
+ from_name != vmSymbols::java_lang_Object())) {
+ // If we are not trying to access a protected field or method in
+ // java.lang.Object then, for arrays, we only allow assignability
+ // to interfaces java.lang.Cloneable and java.io.Serializable.
+ // Otherwise, we treat interfaces as java.lang.Object.
+ return !from_is_array ||
+ this_class == SystemDictionary::Cloneable_klass() ||
+ this_class == SystemDictionary::Serializable_klass();
+ } else if (from_is_object) {
+ Klass* from_class = SystemDictionary::resolve_or_fail(
+ from_name, Handle(THREAD, klass->class_loader()),
+ Handle(THREAD, klass->protection_domain()), true, CHECK_false);
+ if (log_is_enabled(Debug, class, resolve)) {
+ Verifier::trace_class_resolution(from_class, klass());
+ }
+ return InstanceKlass::cast(from_class)->is_subclass_of(this_class());
+ }
+
+ return false;
+}
+
bool VerificationType::is_reference_assignable_from(
const VerificationType& from, ClassVerifier* context,
bool from_field_is_protected, TRAPS) const {
@@ -58,33 +92,17 @@
// any object or array is assignable to java.lang.Object
return true;
}
- Klass* obj = SystemDictionary::resolve_or_fail(
- name(), Handle(THREAD, klass->class_loader()),
- Handle(THREAD, klass->protection_domain()), true, CHECK_false);
- if (log_is_enabled(Debug, class, resolve)) {
- Verifier::trace_class_resolution(obj, klass());
+
+ if (DumpSharedSpaces && SystemDictionaryShared::add_verification_constraint(klass(),
+ name(), from.name(), from_field_is_protected, from.is_array(),
+ from.is_object())) {
+ // If add_verification_constraint() returns true, the resolution/check should be
+ // delayed until runtime.
+ return true;
}
- KlassHandle this_class(THREAD, obj);
-
- if (this_class->is_interface() && (!from_field_is_protected ||
- from.name() != vmSymbols::java_lang_Object())) {
- // If we are not trying to access a protected field or method in
- // java.lang.Object then, for arrays, we only allow assignability
- // to interfaces java.lang.Cloneable and java.io.Serializable.
- // Otherwise, we treat interfaces as java.lang.Object.
- return !from.is_array() ||
- this_class == SystemDictionary::Cloneable_klass() ||
- this_class == SystemDictionary::Serializable_klass();
- } else if (from.is_object()) {
- Klass* from_class = SystemDictionary::resolve_or_fail(
- from.name(), Handle(THREAD, klass->class_loader()),
- Handle(THREAD, klass->protection_domain()), true, CHECK_false);
- if (log_is_enabled(Debug, class, resolve)) {
- Verifier::trace_class_resolution(from_class, klass());
- }
- return InstanceKlass::cast(from_class)->is_subclass_of(this_class());
- }
+ return resolve_and_check_assignability(klass(), name(), from.name(),
+ from_field_is_protected, from.is_array(), from.is_object(), THREAD);
} else if (is_array() && from.is_array()) {
VerificationType comp_this = get_component(context, CHECK_false);
VerificationType comp_from = from.get_component(context, CHECK_false);
--- a/hotspot/src/share/vm/classfile/verificationType.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/verificationType.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -333,6 +333,12 @@
bool is_reference_assignable_from(
const VerificationType&, ClassVerifier*, bool from_field_is_protected,
TRAPS) const;
+
+ public:
+ static bool resolve_and_check_assignability(instanceKlassHandle klass, Symbol* name,
+ Symbol* from_name, bool from_field_is_protected,
+ bool from_is_array, bool from_is_object,
+ TRAPS);
};
#endif // SHARE_VM_CLASSFILE_VERIFICATIONTYPE_HPP
--- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -2377,9 +2377,17 @@
case Bytecodes::_ifnonnull:
target = bcs.dest();
if (visited_branches->contains(bci)) {
- if (bci_stack->is_empty()) return true;
- // Pop a bytecode starting offset and scan from there.
- bcs.set_start(bci_stack->pop());
+ if (bci_stack->is_empty()) {
+ if (handler_stack->is_empty()) {
+ return true;
+ } else {
+ // Parse the catch handlers for try blocks containing athrow.
+ bcs.set_start(handler_stack->pop());
+ }
+ } else {
+ // Pop a bytecode starting offset and scan from there.
+ bcs.set_start(bci_stack->pop());
+ }
} else {
if (target > bci) { // forward branch
if (target >= code_length) return false;
@@ -2402,9 +2410,17 @@
case Bytecodes::_goto_w:
target = (opcode == Bytecodes::_goto ? bcs.dest() : bcs.dest_w());
if (visited_branches->contains(bci)) {
- if (bci_stack->is_empty()) return true;
- // Been here before, pop new starting offset from stack.
- bcs.set_start(bci_stack->pop());
+ if (bci_stack->is_empty()) {
+ if (handler_stack->is_empty()) {
+ return true;
+ } else {
+ // Parse the catch handlers for try blocks containing athrow.
+ bcs.set_start(handler_stack->pop());
+ }
+ } else {
+ // Been here before, pop new starting offset from stack.
+ bcs.set_start(bci_stack->pop());
+ }
} else {
if (target >= code_length) return false;
// Continue scanning from the target onward.
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1256,9 +1256,7 @@
// set between the last GC or pause and now. We need to clear the
// incremental collection set and then start rebuilding it afresh
// after this full GC.
- abandon_collection_set(collection_set()->inc_head());
- collection_set()->clear_incremental();
- collection_set()->stop_incremental_building();
+ abandon_collection_set(collection_set());
tear_down_region_sets(false /* free_list_only */);
collector_state()->set_gcs_are_young(true);
@@ -1379,7 +1377,6 @@
_verifier->check_bitmaps("Full GC End");
// Start a new incremental collection set for the next pause
- assert(collection_set()->head() == NULL, "must be");
collection_set()->start_incremental_building();
clear_cset_fast_test();
@@ -1724,8 +1721,6 @@
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
_in_cset_fast_test(),
- _worker_cset_start_region(NULL),
- _worker_cset_start_region_time_stamp(NULL),
_gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()),
_gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) {
@@ -1748,8 +1743,6 @@
uint n_queues = ParallelGCThreads;
_task_queues = new RefToScanQueueSet(n_queues);
- _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
- _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC);
_evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
for (uint i = 0; i < n_queues; i++) {
@@ -1758,7 +1751,6 @@
_task_queues->register_queue(i, q);
::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
}
- clear_cset_start_regions();
// Initialize the G1EvacuationFailureALot counters and flags.
NOT_PRODUCT(reset_evacuation_should_fail();)
@@ -1987,6 +1979,8 @@
_preserved_marks_set.init(ParallelGCThreads);
+ _collection_set.initialize(max_regions());
+
return JNI_OK;
}
@@ -2420,117 +2414,12 @@
_hrm.par_iterate(cl, worker_id, hrclaimer, concurrent);
}
-// Clear the cached CSet starting regions and (more importantly)
-// the time stamps. Called when we reset the GC time stamp.
-void G1CollectedHeap::clear_cset_start_regions() {
- assert(_worker_cset_start_region != NULL, "sanity");
- assert(_worker_cset_start_region_time_stamp != NULL, "sanity");
-
- for (uint i = 0; i < ParallelGCThreads; i++) {
- _worker_cset_start_region[i] = NULL;
- _worker_cset_start_region_time_stamp[i] = 0;
- }
+void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
+ _collection_set.iterate(cl);
}
-// Given the id of a worker, obtain or calculate a suitable
-// starting region for iterating over the current collection set.
-HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) {
- assert(get_gc_time_stamp() > 0, "should have been updated by now");
-
- HeapRegion* result = NULL;
- unsigned gc_time_stamp = get_gc_time_stamp();
-
- if (_worker_cset_start_region_time_stamp[worker_i] == gc_time_stamp) {
- // Cached starting region for current worker was set
- // during the current pause - so it's valid.
- // Note: the cached starting heap region may be NULL
- // (when the collection set is empty).
- result = _worker_cset_start_region[worker_i];
- assert(result == NULL || result->in_collection_set(), "sanity");
- return result;
- }
-
- // The cached entry was not valid so let's calculate
- // a suitable starting heap region for this worker.
-
- // We want the parallel threads to start their collection
- // set iteration at different collection set regions to
- // avoid contention.
- // If we have:
- // n collection set regions
- // p threads
- // Then thread t will start at region floor ((t * n) / p)
-
- result = collection_set()->head();
- uint cs_size = collection_set()->region_length();
- uint active_workers = workers()->active_workers();
-
- uint end_ind = (cs_size * worker_i) / active_workers;
- uint start_ind = 0;
-
- if (worker_i > 0 &&
- _worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) {
- // Previous workers starting region is valid
- // so let's iterate from there
- start_ind = (cs_size * (worker_i - 1)) / active_workers;
- OrderAccess::loadload();
- result = _worker_cset_start_region[worker_i - 1];
- }
-
- for (uint i = start_ind; i < end_ind; i++) {
- result = result->next_in_collection_set();
- }
-
- // Note: the calculated starting heap region may be NULL
- // (when the collection set is empty).
- assert(result == NULL || result->in_collection_set(), "sanity");
- assert(_worker_cset_start_region_time_stamp[worker_i] != gc_time_stamp,
- "should be updated only once per pause");
- _worker_cset_start_region[worker_i] = result;
- OrderAccess::storestore();
- _worker_cset_start_region_time_stamp[worker_i] = gc_time_stamp;
- return result;
-}
-
-void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
- HeapRegion* r = collection_set()->head();
- while (r != NULL) {
- HeapRegion* next = r->next_in_collection_set();
- if (cl->doHeapRegion(r)) {
- cl->incomplete();
- return;
- }
- r = next;
- }
-}
-
-void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r,
- HeapRegionClosure *cl) {
- if (r == NULL) {
- // The CSet is empty so there's nothing to do.
- return;
- }
-
- assert(r->in_collection_set(),
- "Start region must be a member of the collection set.");
- HeapRegion* cur = r;
- while (cur != NULL) {
- HeapRegion* next = cur->next_in_collection_set();
- if (cl->doHeapRegion(cur) && false) {
- cl->incomplete();
- return;
- }
- cur = next;
- }
- cur = collection_set()->head();
- while (cur != r) {
- HeapRegion* next = cur->next_in_collection_set();
- if (cl->doHeapRegion(cur) && false) {
- cl->incomplete();
- return;
- }
- cur = next;
- }
+void G1CollectedHeap::collection_set_iterate_from(HeapRegionClosure *cl, uint worker_id) {
+ _collection_set.iterate_from(cl, worker_id, workers()->active_workers());
}
HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
@@ -3090,6 +2979,18 @@
g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms);
}
+class G1PrintCollectionSetClosure : public HeapRegionClosure {
+private:
+ G1HRPrinter* _hr_printer;
+public:
+ G1PrintCollectionSetClosure(G1HRPrinter* hr_printer) : HeapRegionClosure(), _hr_printer(hr_printer) { }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ _hr_printer->cset(r);
+ return false;
+ }
+};
+
bool
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
assert_at_safepoint(true /* should_be_vm_thread */);
@@ -3268,11 +3169,8 @@
_cm->verify_no_cset_oops();
if (_hr_printer.is_active()) {
- HeapRegion* hr = collection_set()->head();
- while (hr != NULL) {
- _hr_printer.cset(hr);
- hr = hr->next_in_collection_set();
- }
+ G1PrintCollectionSetClosure cl(&_hr_printer);
+ _collection_set.iterate(&cl);
}
// Initialize the GC alloc regions.
@@ -3287,12 +3185,10 @@
post_evacuate_collection_set(evacuation_info, &per_thread_states);
const size_t* surviving_young_words = per_thread_states.surviving_young_words();
- free_collection_set(collection_set()->head(), evacuation_info, surviving_young_words);
+ free_collection_set(&_collection_set, evacuation_info, surviving_young_words);
eagerly_reclaim_humongous_regions();
- collection_set()->clear_head();
-
record_obj_copy_mem_stats();
_survivor_evac_stats.adjust_desired_plab_sz();
_old_evac_stats.adjust_desired_plab_sz();
@@ -4704,120 +4600,139 @@
workers()->run_task(&g1_par_scrub_rs_task);
}
-void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) {
- size_t pre_used = 0;
- FreeRegionList local_free_list("Local List for CSet Freeing");
-
- double young_time_ms = 0.0;
- double non_young_time_ms = 0.0;
-
- _eden.clear();
-
- G1Policy* policy = g1_policy();
-
- double start_sec = os::elapsedTime();
- bool non_young = true;
-
- HeapRegion* cur = cs_head;
- int age_bound = -1;
- size_t rs_lengths = 0;
-
- while (cur != NULL) {
- assert(!is_on_master_free_list(cur), "sanity");
- if (non_young) {
- if (cur->is_young()) {
- double end_sec = os::elapsedTime();
- double elapsed_ms = (end_sec - start_sec) * 1000.0;
- non_young_time_ms += elapsed_ms;
-
- start_sec = os::elapsedTime();
- non_young = false;
- }
+class G1FreeCollectionSetClosure : public HeapRegionClosure {
+private:
+ const size_t* _surviving_young_words;
+
+ FreeRegionList _local_free_list;
+ size_t _rs_lengths;
+ // Bytes used in successfully evacuated regions before the evacuation.
+ size_t _before_used_bytes;
+ // Bytes used in unsucessfully evacuated regions before the evacuation
+ size_t _after_used_bytes;
+
+ size_t _bytes_allocated_in_old_since_last_gc;
+
+ size_t _failure_used_words;
+ size_t _failure_waste_words;
+
+ double _young_time;
+ double _non_young_time;
+public:
+ G1FreeCollectionSetClosure(const size_t* surviving_young_words) :
+ HeapRegionClosure(),
+ _surviving_young_words(surviving_young_words),
+ _local_free_list("Local Region List for CSet Freeing"),
+ _rs_lengths(0),
+ _before_used_bytes(0),
+ _after_used_bytes(0),
+ _bytes_allocated_in_old_since_last_gc(0),
+ _failure_used_words(0),
+ _failure_waste_words(0),
+ _young_time(0.0),
+ _non_young_time(0.0) {
+ }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ double start_time = os::elapsedTime();
+
+ bool is_young = r->is_young();
+
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ assert(!g1h->is_on_master_free_list(r), "sanity");
+
+ _rs_lengths += r->rem_set()->occupied_locked();
+
+ assert(r->in_collection_set(), "Region %u should be in collection set.", r->hrm_index());
+ g1h->clear_in_cset(r);
+
+ if (is_young) {
+ int index = r->young_index_in_cset();
+ assert(index != -1, "Young index in collection set must not be -1 for region %u", r->hrm_index());
+ assert((uint) index < g1h->collection_set()->young_region_length(), "invariant");
+ size_t words_survived = _surviving_young_words[index];
+ r->record_surv_words_in_group(words_survived);
} else {
- if (!cur->is_young()) {
- double end_sec = os::elapsedTime();
- double elapsed_ms = (end_sec - start_sec) * 1000.0;
- young_time_ms += elapsed_ms;
-
- start_sec = os::elapsedTime();
- non_young = true;
- }
+ assert(r->young_index_in_cset() == -1, "Young index for old region %u in collection set must be -1", r->hrm_index());
}
- rs_lengths += cur->rem_set()->occupied_locked();
-
- HeapRegion* next = cur->next_in_collection_set();
- assert(cur->in_collection_set(), "bad CS");
- cur->set_next_in_collection_set(NULL);
- clear_in_cset(cur);
-
- if (cur->is_young()) {
- int index = cur->young_index_in_cset();
- assert(index != -1, "invariant");
- assert((uint) index < collection_set()->young_region_length(), "invariant");
- size_t words_survived = surviving_young_words[index];
- cur->record_surv_words_in_group(words_survived);
-
+ if (!r->evacuation_failed()) {
+ assert(r->not_empty(), "Region %u is an empty region in the collection set.", r->hrm_index());
+ _before_used_bytes += r->used();
+ g1h->free_region(r, &_local_free_list, false /* par */, true /* locked */);
} else {
- int index = cur->young_index_in_cset();
- assert(index == -1, "invariant");
- }
-
- assert( (cur->is_young() && cur->young_index_in_cset() > -1) ||
- (!cur->is_young() && cur->young_index_in_cset() == -1),
- "invariant" );
-
- if (!cur->evacuation_failed()) {
- MemRegion used_mr = cur->used_region();
-
- // And the region is empty.
- assert(!used_mr.is_empty(), "Should not have empty regions in a CS.");
- pre_used += cur->used();
- free_region(cur, &local_free_list, false /* par */, true /* locked */);
- } else {
- cur->uninstall_surv_rate_group();
- if (cur->is_young()) {
- cur->set_young_index_in_cset(-1);
- }
- cur->set_evacuation_failed(false);
+ r->uninstall_surv_rate_group();
+ r->set_young_index_in_cset(-1);
+ r->set_evacuation_failed(false);
// When moving a young gen region to old gen, we "allocate" that whole region
// there. This is in addition to any already evacuated objects. Notify the
// policy about that.
// Old gen regions do not cause an additional allocation: both the objects
// still in the region and the ones already moved are accounted for elsewhere.
- if (cur->is_young()) {
- policy->add_bytes_allocated_in_old_since_last_gc(HeapRegion::GrainBytes);
+ if (is_young) {
+ _bytes_allocated_in_old_since_last_gc += HeapRegion::GrainBytes;
}
// The region is now considered to be old.
- cur->set_old();
+ r->set_old();
// Do some allocation statistics accounting. Regions that failed evacuation
// are always made old, so there is no need to update anything in the young
// gen statistics, but we need to update old gen statistics.
- size_t used_words = cur->marked_bytes() / HeapWordSize;
- _old_evac_stats.add_failure_used_and_waste(used_words, HeapRegion::GrainWords - used_words);
- _old_set.add(cur);
- evacuation_info.increment_collectionset_used_after(cur->used());
+ size_t used_words = r->marked_bytes() / HeapWordSize;
+
+ _failure_used_words += used_words;
+ _failure_waste_words += HeapRegion::GrainWords - used_words;
+
+ g1h->old_set_add(r);
+ _after_used_bytes += r->used();
+ }
+
+ if (is_young) {
+ _young_time += os::elapsedTime() - start_time;
+ } else {
+ _non_young_time += os::elapsedTime() - start_time;
}
- cur = next;
+ return false;
}
- evacuation_info.set_regions_freed(local_free_list.length());
- policy->record_max_rs_lengths(rs_lengths);
+ FreeRegionList* local_free_list() { return &_local_free_list; }
+ size_t rs_lengths() const { return _rs_lengths; }
+ size_t before_used_bytes() const { return _before_used_bytes; }
+ size_t after_used_bytes() const { return _after_used_bytes; }
+
+ size_t bytes_allocated_in_old_since_last_gc() const { return _bytes_allocated_in_old_since_last_gc; }
+
+ size_t failure_used_words() const { return _failure_used_words; }
+ size_t failure_waste_words() const { return _failure_waste_words; }
+
+ double young_time() const { return _young_time; }
+ double non_young_time() const { return _non_young_time; }
+};
+
+void G1CollectedHeap::free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) {
+ _eden.clear();
+
+ G1FreeCollectionSetClosure cl(surviving_young_words);
+ collection_set_iterate(&cl);
+
+ evacuation_info.set_regions_freed(cl.local_free_list()->length());
+ evacuation_info.increment_collectionset_used_after(cl.after_used_bytes());
+
+ G1Policy* policy = g1_policy();
+
+ policy->record_max_rs_lengths(cl.rs_lengths());
policy->cset_regions_freed();
- double end_sec = os::elapsedTime();
- double elapsed_ms = (end_sec - start_sec) * 1000.0;
-
- if (non_young) {
- non_young_time_ms += elapsed_ms;
- } else {
- young_time_ms += elapsed_ms;
- }
-
- prepend_to_freelist(&local_free_list);
- decrement_summary_bytes(pre_used);
- policy->phase_times()->record_young_free_cset_time_ms(young_time_ms);
- policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms);
+ prepend_to_freelist(cl.local_free_list());
+ decrement_summary_bytes(cl.before_used_bytes());
+
+ policy->add_bytes_allocated_in_old_since_last_gc(cl.bytes_allocated_in_old_since_last_gc());
+
+ _old_evac_stats.add_failure_used_and_waste(cl.failure_used_words(), cl.failure_waste_words());
+
+ policy->phase_times()->record_young_free_cset_time_ms(cl.young_time() * 1000.0);
+ policy->phase_times()->record_non_young_free_cset_time_ms(cl.non_young_time() * 1000.0);
+
+ collection_set->clear();
}
class G1FreeHumongousRegionClosure : public HeapRegionClosure {
@@ -4960,25 +4875,22 @@
cl.humongous_free_count());
}
-// This routine is similar to the above but does not record
-// any policy statistics or update free lists; we are abandoning
-// the current incremental collection set in preparation of a
-// full collection. After the full GC we will start to build up
-// the incremental collection set again.
-// This is only called when we're doing a full collection
-// and is immediately followed by the tearing down of the young list.
-
-void G1CollectedHeap::abandon_collection_set(HeapRegion* cs_head) {
- HeapRegion* cur = cs_head;
-
- while (cur != NULL) {
- HeapRegion* next = cur->next_in_collection_set();
- assert(cur->in_collection_set(), "bad CS");
- cur->set_next_in_collection_set(NULL);
- clear_in_cset(cur);
- cur->set_young_index_in_cset(-1);
- cur = next;
+class G1AbandonCollectionSetClosure : public HeapRegionClosure {
+public:
+ virtual bool doHeapRegion(HeapRegion* r) {
+ assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index());
+ G1CollectedHeap::heap()->clear_in_cset(r);
+ r->set_young_index_in_cset(-1);
+ return false;
}
+};
+
+void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) {
+ G1AbandonCollectionSetClosure cl;
+ collection_set->iterate(&cl);
+
+ collection_set->clear();
+ collection_set->stop_incremental_building();
}
void G1CollectedHeap::set_free_regions_coming() {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -778,13 +778,13 @@
// The closure used to refine a single card.
RefineCardTableEntryClosure* _refine_cte_cl;
- // After a collection pause, make the regions in the CS into free
+ // After a collection pause, convert the regions in the collection set into free
// regions.
- void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
+ void free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
// Abandon the current collection set without recording policy
// statistics or updating free lists.
- void abandon_collection_set(HeapRegion* cs_head);
+ void abandon_collection_set(G1CollectionSet* collection_set);
// The concurrent marker (and the thread it runs in.)
G1ConcurrentMark* _cm;
@@ -930,16 +930,6 @@
// discovery.
G1CMIsAliveClosure _is_alive_closure_cm;
- // Cache used by G1CollectedHeap::start_cset_region_for_worker().
- HeapRegion** _worker_cset_start_region;
-
- // Time stamp to validate the regions recorded in the cache
- // used by G1CollectedHeap::start_cset_region_for_worker().
- // The heap region entry for a given worker is valid iff
- // the associated time stamp value matches the current value
- // of G1CollectedHeap::_gc_time_stamp.
- uint* _worker_cset_start_region_time_stamp;
-
volatile bool _free_regions_coming;
public:
@@ -1211,19 +1201,14 @@
HeapRegionClaimer* hrclaimer,
bool concurrent = false) const;
- // Clear the cached cset start regions and (more importantly)
- // the time stamps. Called when we reset the GC time stamp.
- void clear_cset_start_regions();
-
- // Given the id of a worker, obtain or calculate a suitable
- // starting region for iterating over the current collection set.
- HeapRegion* start_cset_region_for_worker(uint worker_i);
-
// Iterate over the regions (if any) in the current collection set.
void collection_set_iterate(HeapRegionClosure* blk);
- // As above but starting from region r
- void collection_set_iterate_from(HeapRegion* r, HeapRegionClosure *blk);
+ // Iterate over the regions (if any) in the current collection set. Starts the
+ // iteration over the entire collection set so that the start regions of a given
+ // worker id over the set active_workers are evenly spread across the set of
+ // collection set regions.
+ void collection_set_iterate_from(HeapRegionClosure *blk, uint worker_id);
HeapRegion* next_compaction_region(const HeapRegion* from) const;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -89,16 +89,13 @@
}
inline void G1CollectedHeap::reset_gc_time_stamp() {
+ assert_at_safepoint(true);
_gc_time_stamp = 0;
- OrderAccess::fence();
- // Clear the cached CSet starting regions and time stamps.
- // Their validity is dependent on the GC timestamp.
- clear_cset_start_regions();
}
inline void G1CollectedHeap::increment_gc_time_stamp() {
+ assert_at_safepoint(true);
++_gc_time_stamp;
- OrderAccess::fence();
}
inline void G1CollectedHeap::old_set_add(HeapRegion* hr) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -30,6 +30,7 @@
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.hpp"
+#include "logging/logStream.hpp"
#include "utilities/debug.hpp"
G1CollectorState* G1CollectionSet::collector_state() {
@@ -55,48 +56,63 @@
_eden_region_length(0),
_survivor_region_length(0),
_old_region_length(0),
-
- _head(NULL),
_bytes_used_before(0),
_recorded_rs_lengths(0),
+ _collection_set_regions(NULL),
+ _collection_set_cur_length(0),
+ _collection_set_max_length(0),
// Incremental CSet attributes
_inc_build_state(Inactive),
- _inc_head(NULL),
- _inc_tail(NULL),
_inc_bytes_used_before(0),
_inc_recorded_rs_lengths(0),
_inc_recorded_rs_lengths_diffs(0),
_inc_predicted_elapsed_time_ms(0.0),
- _inc_predicted_elapsed_time_ms_diffs(0.0),
- _inc_region_length(0) {}
+ _inc_predicted_elapsed_time_ms_diffs(0.0) {
+}
G1CollectionSet::~G1CollectionSet() {
+ if (_collection_set_regions != NULL) {
+ FREE_C_HEAP_ARRAY(uint, _collection_set_regions);
+ }
delete _cset_chooser;
}
void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
uint survivor_cset_region_length) {
+ assert_at_safepoint(true);
+
_eden_region_length = eden_cset_region_length;
_survivor_region_length = survivor_cset_region_length;
- assert(young_region_length() == _inc_region_length, "should match %u == %u", young_region_length(), _inc_region_length);
+ assert((size_t) young_region_length() == _collection_set_cur_length,
+ "Young region length %u should match collection set length " SIZE_FORMAT, young_region_length(), _collection_set_cur_length);
_old_region_length = 0;
}
+void G1CollectionSet::initialize(uint max_region_length) {
+ guarantee(_collection_set_regions == NULL, "Must only initialize once.");
+ _collection_set_max_length = max_region_length;
+ _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
+}
+
void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) {
_recorded_rs_lengths = rs_lengths;
}
// Add the heap region at the head of the non-incremental collection set
void G1CollectionSet::add_old_region(HeapRegion* hr) {
+ assert_at_safepoint(true);
+
assert(_inc_build_state == Active, "Precondition");
assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the CSet");
_g1->register_old_region_with_cset(hr);
- hr->set_next_in_collection_set(_head);
- _head = hr;
+
+ _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
+ assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size.");
+
_bytes_used_before += hr->used();
size_t rs_length = hr->rem_set()->occupied();
_recorded_rs_lengths += rs_length;
@@ -105,12 +121,10 @@
// Initialize the per-collection-set information
void G1CollectionSet::start_incremental_building() {
+ assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
assert(_inc_build_state == Inactive, "Precondition");
- _inc_head = NULL;
- _inc_tail = NULL;
_inc_bytes_used_before = 0;
- _inc_region_length = 0;
_inc_recorded_rs_lengths = 0;
_inc_recorded_rs_lengths_diffs = 0;
@@ -151,6 +165,38 @@
_inc_predicted_elapsed_time_ms_diffs = 0.0;
}
+void G1CollectionSet::clear() {
+ assert_at_safepoint(true);
+ _collection_set_cur_length = 0;
+}
+
+void G1CollectionSet::iterate(HeapRegionClosure* cl) const {
+ iterate_from(cl, 0, 1);
+}
+
+void G1CollectionSet::iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const {
+ size_t len = _collection_set_cur_length;
+ OrderAccess::loadload();
+ if (len == 0) {
+ return;
+ }
+ size_t start_pos = (worker_id * len) / total_workers;
+ size_t cur_pos = start_pos;
+
+ do {
+ HeapRegion* r = G1CollectedHeap::heap()->region_at(_collection_set_regions[cur_pos]);
+ bool result = cl->doHeapRegion(r);
+ if (result) {
+ cl->incomplete();
+ return;
+ }
+ cur_pos++;
+ if (cur_pos == len) {
+ cur_pos = 0;
+ }
+ } while (cur_pos != start_pos);
+}
+
void G1CollectionSet::update_young_region_prediction(HeapRegion* hr,
size_t new_rs_length) {
// Update the CSet information that is dependent on the new RS length
@@ -183,8 +229,16 @@
assert(hr->is_young(), "invariant");
assert(_inc_build_state == Active, "Precondition");
- hr->set_young_index_in_cset(_inc_region_length);
- _inc_region_length++;
+ size_t collection_set_length = _collection_set_cur_length;
+ assert(collection_set_length <= INT_MAX, "Collection set is too large with %d entries", (int)collection_set_length);
+ hr->set_young_index_in_cset((int)collection_set_length);
+
+ _collection_set_regions[collection_set_length] = hr->hrm_index();
+ // Concurrent readers must observe the store of the value in the array before an
+ // update to the length field.
+ OrderAccess::storestore();
+ _collection_set_cur_length++;
+ assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed.");
// This routine is used when:
// * adding survivor regions to the incremental cset at the end of an
@@ -218,59 +272,81 @@
assert(!hr->in_collection_set(), "invariant");
_g1->register_young_region_with_cset(hr);
- assert(hr->next_in_collection_set() == NULL, "invariant");
}
-// Add the region at the RHS of the incremental cset
void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
- // We should only ever be appending survivors at the end of a pause
- assert(hr->is_survivor(), "Logic");
-
- // Do the 'common' stuff
+ assert(hr->is_survivor(), "Must only add survivor regions, but is %s", hr->get_type_str());
add_young_region_common(hr);
-
- // Now add the region at the right hand side
- if (_inc_tail == NULL) {
- assert(_inc_head == NULL, "invariant");
- _inc_head = hr;
- } else {
- _inc_tail->set_next_in_collection_set(hr);
- }
- _inc_tail = hr;
}
-// Add the region to the LHS of the incremental cset
void G1CollectionSet::add_eden_region(HeapRegion* hr) {
- // Survivors should be added to the RHS at the end of a pause
- assert(hr->is_eden(), "Logic");
-
- // Do the 'common' stuff
+ assert(hr->is_eden(), "Must only add eden regions, but is %s", hr->get_type_str());
add_young_region_common(hr);
-
- // Add the region at the left hand side
- hr->set_next_in_collection_set(_inc_head);
- if (_inc_head == NULL) {
- assert(_inc_tail == NULL, "Invariant");
- _inc_tail = hr;
- }
- _inc_head = hr;
}
#ifndef PRODUCT
-void G1CollectionSet::print(HeapRegion* list_head, outputStream* st) {
- assert(list_head == inc_head() || list_head == head(), "must be");
+class G1VerifyYoungAgesClosure : public HeapRegionClosure {
+public:
+ bool _valid;
+public:
+ G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str());
+
+ SurvRateGroup* group = r->surv_rate_group();
+
+ if (group == NULL) {
+ log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
+ _valid = false;
+ }
+
+ if (r->age_in_surv_rate_group() < 0) {
+ log_error(gc, verify)("## encountered negative age in young region");
+ _valid = false;
+ }
+
+ return false;
+ }
+
+ bool valid() const { return _valid; }
+};
+bool G1CollectionSet::verify_young_ages() {
+ assert_at_safepoint(true);
+
+ G1VerifyYoungAgesClosure cl;
+ iterate(&cl);
+
+ if (!cl.valid()) {
+ LogStreamHandle(Error, gc, verify) log;
+ print(&log);
+ }
+
+ return cl.valid();
+}
+
+class G1PrintCollectionSetClosure : public HeapRegionClosure {
+ outputStream* _st;
+public:
+ G1PrintCollectionSetClosure(outputStream* st) : HeapRegionClosure(), _st(st) { }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ assert(r->in_collection_set(), "Region %u should be in collection set", r->hrm_index());
+ _st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
+ HR_FORMAT_PARAMS(r),
+ p2i(r->prev_top_at_mark_start()),
+ p2i(r->next_top_at_mark_start()),
+ r->age_in_surv_rate_group_cond());
+ return false;
+ }
+};
+
+void G1CollectionSet::print(outputStream* st) {
st->print_cr("\nCollection_set:");
- HeapRegion* csr = list_head;
- while (csr != NULL) {
- HeapRegion* next = csr->next_in_collection_set();
- assert(csr->in_collection_set(), "bad CS");
- st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
- HR_FORMAT_PARAMS(csr),
- p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()),
- csr->age_in_surv_rate_group_cond());
- csr = next;
- }
+
+ G1PrintCollectionSetClosure cl(st);
+ iterate(&cl);
}
#endif // !PRODUCT
@@ -281,7 +357,6 @@
guarantee(target_pause_time_ms > 0.0,
"target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
- guarantee(_head == NULL, "Precondition");
size_t pending_cards = _policy->pending_cards();
double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
@@ -305,7 +380,6 @@
// Clear the fields that point to the survivor list - they are all young now.
survivors->convert_to_eden();
- _head = _inc_head;
_bytes_used_before = _inc_bytes_used_before;
time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0);
@@ -422,23 +496,41 @@
}
#ifdef ASSERT
-void G1CollectionSet::verify_young_cset_indices() const {
- ResourceMark rm;
- uint* heap_region_indices = NEW_RESOURCE_ARRAY(uint, young_region_length());
- for (uint i = 0; i < young_region_length(); ++i) {
- heap_region_indices[i] = (uint)-1;
+class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure {
+private:
+ size_t _young_length;
+ int* _heap_region_indices;
+public:
+ G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) {
+ _heap_region_indices = NEW_C_HEAP_ARRAY(int, young_length, mtGC);
+ for (size_t i = 0; i < young_length; i++) {
+ _heap_region_indices[i] = -1;
+ }
+ }
+ ~G1VerifyYoungCSetIndicesClosure() {
+ FREE_C_HEAP_ARRAY(int, _heap_region_indices);
}
- for (HeapRegion* hr = _inc_head; hr != NULL; hr = hr->next_in_collection_set()) {
- const int idx = hr->young_index_in_cset();
- assert(idx > -1, "must be set for all inc cset regions");
- assert((uint)idx < young_region_length(), "young cset index too large");
+ virtual bool doHeapRegion(HeapRegion* r) {
+ const int idx = r->young_index_in_cset();
+
+ assert(idx > -1, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index());
+ assert((size_t)idx < _young_length, "Young cset index too large for region %u", r->hrm_index());
+
+ assert(_heap_region_indices[idx] == -1,
+ "Index %d used by multiple regions, first use by region %u, second by region %u",
+ idx, _heap_region_indices[idx], r->hrm_index());
- assert(heap_region_indices[idx] == (uint)-1,
- "index %d used by multiple regions, first use by %u, second by %u",
- idx, heap_region_indices[idx], hr->hrm_index());
+ _heap_region_indices[idx] = r->hrm_index();
+
+ return false;
+ }
+};
- heap_region_indices[idx] = hr->hrm_index();
- }
+void G1CollectionSet::verify_young_cset_indices() const {
+ assert_at_safepoint(true);
+
+ G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length);
+ iterate(&cl);
}
#endif
--- a/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1CollectionSet.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -47,10 +47,15 @@
uint _survivor_region_length;
uint _old_region_length;
- // The head of the list (via "next_in_collection_set()") representing the
- // current collection set. Set from the incrementally built collection
- // set at the start of the pause.
- HeapRegion* _head;
+ // The actual collection set as a set of region indices.
+ // All entries in _collection_set_regions below _collection_set_cur_length are
+ // assumed to be valid entries.
+ // We assume that at any time there is at most only one writer and (one or more)
+ // concurrent readers. This means we are good with using storestore and loadload
+ // barriers on the writer and reader respectively only.
+ uint* _collection_set_regions;
+ volatile size_t _collection_set_cur_length;
+ size_t _collection_set_max_length;
// The number of bytes in the collection set before the pause. Set from
// the incrementally built collection set at the start of an evacuation
@@ -71,12 +76,6 @@
CSetBuildType _inc_build_state;
- // The head of the incrementally built collection set.
- HeapRegion* _inc_head;
-
- // The tail of the incrementally built collection set.
- HeapRegion* _inc_tail;
-
// The number of bytes in the incrementally built collection set.
// Used to set _collection_set_bytes_used_before at the start of
// an evacuation pause.
@@ -105,8 +104,6 @@
// See the comment for _inc_recorded_rs_lengths_diffs.
double _inc_predicted_elapsed_time_ms_diffs;
- uint _inc_region_length;
-
G1CollectorState* collector_state();
G1GCPhaseTimes* phase_times();
@@ -117,6 +114,9 @@
G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy);
~G1CollectionSet();
+ // Initializes the collection set giving the maximum possible length of the collection set.
+ void initialize(uint max_region_length);
+
CollectionSetChooser* cset_chooser();
void init_region_lengths(uint eden_cset_region_length,
@@ -133,35 +133,30 @@
uint survivor_region_length() const { return _survivor_region_length; }
uint old_region_length() const { return _old_region_length; }
- // Incremental CSet Support
-
- // The head of the incrementally built collection set.
- HeapRegion* inc_head() { return _inc_head; }
-
- // The tail of the incrementally built collection set.
- HeapRegion* inc_tail() { return _inc_tail; }
+ // Incremental collection set support
// Initialize incremental collection set info.
void start_incremental_building();
- // Perform any final calculations on the incremental CSet fields
+ // Perform any final calculations on the incremental collection set fields
// before we can use them.
void finalize_incremental_building();
- void clear_incremental() {
- _inc_head = NULL;
- _inc_tail = NULL;
- _inc_region_length = 0;
- }
+ // Reset the contents of the collection set.
+ void clear();
+
+ // Iterate over the collection set, applying the given HeapRegionClosure on all of them.
+ // If may_be_aborted is true, iteration may be aborted using the return value of the
+ // called closure method.
+ void iterate(HeapRegionClosure* cl) const;
- // Stop adding regions to the incremental collection set
- void stop_incremental_building() { _inc_build_state = Inactive; }
+ // Iterate over the collection set, applying the given HeapRegionClosure on all of them,
+ // trying to optimally spread out starting position of total_workers workers given the
+ // caller's worker_id.
+ void iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const;
- // The head of the list (via "next_in_collection_set()") representing the
- // current collection set.
- HeapRegion* head() { return _head; }
-
- void clear_head() { _head = NULL; }
+ // Stop adding regions to the incremental collection set.
+ void stop_incremental_building() { _inc_build_state = Inactive; }
size_t recorded_rs_lengths() { return _recorded_rs_lengths; }
@@ -174,33 +169,32 @@
}
// Choose a new collection set. Marks the chosen regions as being
- // "in_collection_set", and links them together. The head and number of
- // the collection set are available via access methods.
+ // "in_collection_set".
double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors);
void finalize_old_part(double time_remaining_ms);
- // Add old region "hr" to the CSet.
+ // Add old region "hr" to the collection set.
void add_old_region(HeapRegion* hr);
// Update information about hr in the aggregated information for
// the incrementally built collection set.
void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length);
- // Add hr to the LHS of the incremental collection set.
+ // Add eden region to the collection set.
void add_eden_region(HeapRegion* hr);
- // Add hr to the RHS of the incremental collection set.
+ // Add survivor region to the collection set.
void add_survivor_regions(HeapRegion* hr);
#ifndef PRODUCT
- void print(HeapRegion* list_head, outputStream* st);
+ bool verify_young_ages();
+
+ void print(outputStream* st);
#endif // !PRODUCT
private:
- // Update the incremental cset information when adding a region
- // (should not be called directly).
+ // Update the incremental collection set information when adding a region.
void add_young_region_common(HeapRegion* hr);
-
};
#endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -394,37 +394,6 @@
}
}
-#ifndef PRODUCT
-bool G1DefaultPolicy::verify_young_ages() {
- bool ret = true;
-
- for (HeapRegion* curr = _collection_set->inc_head();
- curr != NULL;
- curr = curr->next_in_collection_set()) {
- guarantee(curr->is_young(), "Region must be young");
-
- SurvRateGroup* group = curr->surv_rate_group();
-
- if (group == NULL) {
- log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
- ret = false;
- }
-
- if (curr->age_in_surv_rate_group() < 0) {
- log_error(gc, verify)("## encountered negative age in young region");
- ret = false;
- }
- }
-
- if (!ret) {
- LogStreamHandle(Error, gc, verify) log;
- _collection_set->print(_collection_set->inc_head(), &log);
- }
-
- return ret;
-}
-#endif // PRODUCT
-
void G1DefaultPolicy::record_full_collection_start() {
_full_collection_start_sec = os::elapsedTime();
// Release the future to-space so that it is available for compaction into.
@@ -488,7 +457,7 @@
_short_lived_surv_rate_group->stop_adding_regions();
_survivors_age_table.clear();
- assert( verify_young_ages(), "region age verification" );
+ assert(_g1->collection_set()->verify_young_ages(), "region age verification failed");
}
void G1DefaultPolicy::record_concurrent_mark_init_end(double mark_init_elapsed_time_ms) {
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -89,10 +89,6 @@
size_t _rs_lengths_prediction;
-#ifndef PRODUCT
- bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group);
-#endif // PRODUCT
-
size_t _pending_cards;
// The amount of allocated bytes in old gen during the last mutator and the following
@@ -116,10 +112,6 @@
hr->install_surv_rate_group(_survivor_surv_rate_group);
}
-#ifndef PRODUCT
- bool verify_young_ages();
-#endif // PRODUCT
-
void record_max_rs_lengths(size_t rs_lengths) {
_max_rs_lengths = rs_lengths;
}
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -251,6 +251,5 @@
void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) {
RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer);
- HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id);
- _g1h->collection_set_iterate_from(hr, &rsfp_cl);
+ _g1h->collection_set_iterate_from(&rsfp_cl, worker_id);
}
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -580,15 +580,20 @@
}
}
-void G1HeapVerifier::verify_dirty_young_list(HeapRegion* head) {
- G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set();
- for (HeapRegion* hr = head; hr != NULL; hr = hr->next_in_collection_set()) {
- verify_dirty_region(hr);
+class G1VerifyDirtyYoungListClosure : public HeapRegionClosure {
+private:
+ G1HeapVerifier* _verifier;
+public:
+ G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : HeapRegionClosure(), _verifier(verifier) { }
+ virtual bool doHeapRegion(HeapRegion* r) {
+ _verifier->verify_dirty_region(r);
+ return false;
}
-}
+};
void G1HeapVerifier::verify_dirty_young_regions() {
- verify_dirty_young_list(_g1h->collection_set()->inc_head());
+ G1VerifyDirtyYoungListClosure cl(this);
+ _g1h->collection_set()->iterate(&cl);
}
bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap,
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -108,7 +108,6 @@
void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
- void verify_dirty_young_list(HeapRegion* head) PRODUCT_RETURN;
void verify_dirty_young_regions() PRODUCT_RETURN;
};
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -382,10 +382,8 @@
uint worker_i) {
double rs_time_start = os::elapsedTime();
- HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
-
G1ScanRSClosure cl(_scan_state, oops_in_heap_closure, heap_region_codeblobs, worker_i);
- _g1->collection_set_iterate_from(startRegion, &cl);
+ _g1->collection_set_iterate_from(&cl, worker_i);
double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) -
cl.strong_code_root_scan_time_sec();
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -154,8 +154,8 @@
}
void G1StringDedupQueue::print_statistics() {
- log_debug(gc, stringdedup)(" [Queue]");
- log_debug(gc, stringdedup)(" [Dropped: " UINTX_FORMAT "]", _queue->_dropped);
+ log_debug(gc, stringdedup)(" Queue");
+ log_debug(gc, stringdedup)(" Dropped: " UINTX_FORMAT, _queue->_dropped);
}
void G1StringDedupQueue::verify() {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,9 @@
_idle(0),
_exec(0),
_block(0),
- _start(0.0),
+ _start_concurrent(0.0),
+ _end_concurrent(0.0),
+ _start_phase(0.0),
_idle_elapsed(0.0),
_exec_elapsed(0.0),
_block_elapsed(0.0) {
@@ -69,7 +71,13 @@
_block_elapsed += stat._block_elapsed;
}
-void G1StringDedupStat::print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
+void G1StringDedupStat::print_start(const G1StringDedupStat& last_stat) {
+ log_info(gc, stringdedup)(
+ "Concurrent String Deduplication (" G1_STRDEDUP_TIME_FORMAT ")",
+ G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent));
+}
+
+void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
double total_deduped_bytes_percent = 0.0;
if (total_stat._new_bytes > 0) {
@@ -79,13 +87,16 @@
log_info(gc, stringdedup)(
"Concurrent String Deduplication "
- G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS "), avg "
- G1_STRDEDUP_PERCENT_FORMAT_NS ", " G1_STRDEDUP_TIME_FORMAT,
+ G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS ") "
+ "avg " G1_STRDEDUP_PERCENT_FORMAT_NS " "
+ "(" G1_STRDEDUP_TIME_FORMAT ", " G1_STRDEDUP_TIME_FORMAT ") " G1_STRDEDUP_TIME_FORMAT_MS,
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes),
total_deduped_bytes_percent,
- last_stat._exec_elapsed);
+ G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent),
+ G1_STRDEDUP_TIME_PARAM(last_stat._end_concurrent),
+ G1_STRDEDUP_TIME_PARAM_MS(last_stat._exec_elapsed));
}
void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) {
@@ -134,23 +145,31 @@
if (total) {
log_debug(gc, stringdedup)(
- " [Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]",
- stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed);
+ " Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
+ ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
+ ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
+ stat._exec, G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
+ stat._idle, G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
+ stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
} else {
log_debug(gc, stringdedup)(
- " [Last Exec: " G1_STRDEDUP_TIME_FORMAT ", Idle: " G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]",
- stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed);
+ " Last Exec: " G1_STRDEDUP_TIME_FORMAT_MS
+ ", Idle: " G1_STRDEDUP_TIME_FORMAT_MS
+ ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
+ G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
+ G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
+ stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
}
- log_debug(gc, stringdedup)(" [Inspected: " G1_STRDEDUP_OBJECTS_FORMAT "]", stat._inspected);
- log_debug(gc, stringdedup)(" [Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._skipped, skipped_percent);
- log_debug(gc, stringdedup)(" [Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._hashed, hashed_percent);
- log_debug(gc, stringdedup)(" [Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._known, known_percent);
- log_debug(gc, stringdedup)(" [New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "]",
+ log_debug(gc, stringdedup)(" Inspected: " G1_STRDEDUP_OBJECTS_FORMAT, stat._inspected);
+ log_debug(gc, stringdedup)(" Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._skipped, skipped_percent);
+ log_debug(gc, stringdedup)(" Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._hashed, hashed_percent);
+ log_debug(gc, stringdedup)(" Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._known, known_percent);
+ log_debug(gc, stringdedup)(" New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT,
stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes));
- log_debug(gc, stringdedup)(" [Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+ log_debug(gc, stringdedup)(" Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent);
- log_debug(gc, stringdedup)(" [Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+ log_debug(gc, stringdedup)(" Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent);
- log_debug(gc, stringdedup)(" [Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]",
+ log_debug(gc, stringdedup)(" Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent);
}
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupStat.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,11 +30,14 @@
// Macros for GC log output formating
#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12)
-#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs"
-#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%"
-#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%"
-#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s"
-#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s"
+#define G1_STRDEDUP_TIME_FORMAT "%.3fs"
+#define G1_STRDEDUP_TIME_PARAM(time) (time)
+#define G1_STRDEDUP_TIME_FORMAT_MS "%.3fms"
+#define G1_STRDEDUP_TIME_PARAM_MS(time) ((time) * MILLIUNITS)
+#define G1_STRDEDUP_PERCENT_FORMAT "%5.1f%%"
+#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1f%%"
+#define G1_STRDEDUP_BYTES_FORMAT "%8.1f%s"
+#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1f%s"
#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
//
@@ -60,7 +63,9 @@
uintx _block;
// Time spent by the deduplication thread in different phases
- double _start;
+ double _start_concurrent;
+ double _end_concurrent;
+ double _start_phase;
double _idle_elapsed;
double _exec_elapsed;
double _block_elapsed;
@@ -104,38 +109,41 @@
}
void mark_idle() {
- _start = os::elapsedTime();
+ _start_phase = os::elapsedTime();
_idle++;
}
void mark_exec() {
double now = os::elapsedTime();
- _idle_elapsed = now - _start;
- _start = now;
+ _idle_elapsed = now - _start_phase;
+ _start_phase = now;
+ _start_concurrent = now;
_exec++;
}
void mark_block() {
double now = os::elapsedTime();
- _exec_elapsed += now - _start;
- _start = now;
+ _exec_elapsed += now - _start_phase;
+ _start_phase = now;
_block++;
}
void mark_unblock() {
double now = os::elapsedTime();
- _block_elapsed += now - _start;
- _start = now;
+ _block_elapsed += now - _start_phase;
+ _start_phase = now;
}
void mark_done() {
double now = os::elapsedTime();
- _exec_elapsed += now - _start;
+ _exec_elapsed += now - _start_phase;
+ _end_concurrent = now;
}
void add(const G1StringDedupStat& stat);
- static void print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
+ static void print_start(const G1StringDedupStat& last_stat);
+ static void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
static void print_statistics(const G1StringDedupStat& stat, bool total);
};
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -196,7 +196,8 @@
}
double end = os::elapsedTime();
- log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT, count, end - start);
+ log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT_MS,
+ count, G1_STRDEDUP_TIME_PARAM_MS(end - start));
}
G1StringDedupTable* G1StringDedupTable::_table = NULL;
@@ -610,14 +611,14 @@
void G1StringDedupTable::print_statistics() {
Log(gc, stringdedup) log;
- log.debug(" [Table]");
- log.debug(" [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]",
+ log.debug(" Table");
+ log.debug(" Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS,
G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)));
- log.debug(" [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]", _table->_size, _min_size, _max_size);
- log.debug(" [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]",
+ log.debug(" Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size);
+ log.debug(" Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT,
_table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed);
- log.debug(" [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]",
+ log.debug(" Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")",
_resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0);
- log.debug(" [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]", _rehash_count, _rehash_threshold, _table->_hash_seed);
- log.debug(" [Age Threshold: " UINTX_FORMAT "]", StringDeduplicationAgeThreshold);
+ log.debug(" Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed);
+ log.debug(" Age Threshold: " UINTX_FORMAT, StringDeduplicationAgeThreshold);
}
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -103,6 +103,7 @@
SuspendibleThreadSetJoiner sts_join;
stat.mark_exec();
+ print_start(stat);
// Process the queue
for (;;) {
@@ -123,9 +124,8 @@
stat.mark_done();
- // Print statistics
total_stat.add(stat);
- print(stat, total_stat);
+ print_end(stat, total_stat);
}
G1StringDedupTable::clean_entry_cache();
@@ -136,14 +136,16 @@
G1StringDedupQueue::cancel_wait();
}
-void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
- if (log_is_enabled(Info, gc, stringdedup)) {
- G1StringDedupStat::print_summary(last_stat, total_stat);
- if (log_is_enabled(Debug, gc, stringdedup)) {
- G1StringDedupStat::print_statistics(last_stat, false);
- G1StringDedupStat::print_statistics(total_stat, true);
- G1StringDedupTable::print_statistics();
- G1StringDedupQueue::print_statistics();
- }
+void G1StringDedupThread::print_start(const G1StringDedupStat& last_stat) {
+ G1StringDedupStat::print_start(last_stat);
+}
+
+void G1StringDedupThread::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
+ G1StringDedupStat::print_end(last_stat, total_stat);
+ if (log_is_enabled(Debug, gc, stringdedup)) {
+ G1StringDedupStat::print_statistics(last_stat, false);
+ G1StringDedupStat::print_statistics(total_stat, true);
+ G1StringDedupTable::print_statistics();
+ G1StringDedupQueue::print_statistics();
}
}
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -43,7 +43,8 @@
G1StringDedupThread();
~G1StringDedupThread();
- void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
+ void print_start(const G1StringDedupStat& last_stat);
+ void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
void run_service();
void stop_service();
--- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -71,38 +71,51 @@
_monitor.notify();
}
+class G1YoungRemSetSamplingClosure : public HeapRegionClosure {
+ SuspendibleThreadSetJoiner* _sts;
+ size_t _regions_visited;
+ size_t _sampled_rs_lengths;
+public:
+ G1YoungRemSetSamplingClosure(SuspendibleThreadSetJoiner* sts) :
+ HeapRegionClosure(), _sts(sts), _regions_visited(0), _sampled_rs_lengths(0) { }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ size_t rs_length = r->rem_set()->occupied();
+ _sampled_rs_lengths += rs_length;
+
+ // Update the collection set policy information for this region
+ G1CollectedHeap::heap()->collection_set()->update_young_region_prediction(r, rs_length);
+
+ _regions_visited++;
+
+ if (_regions_visited == 10) {
+ if (_sts->should_yield()) {
+ _sts->yield();
+ // A gc may have occurred and our sampling data is stale and further
+ // traversal of the collection set is unsafe
+ return true;
+ }
+ _regions_visited = 0;
+ }
+ return false;
+ }
+
+ size_t sampled_rs_lengths() const { return _sampled_rs_lengths; }
+};
+
void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() {
SuspendibleThreadSetJoiner sts;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1Policy* g1p = g1h->g1_policy();
- G1CollectionSet* g1cs = g1h->collection_set();
+
if (g1p->adaptive_young_list_length()) {
- int regions_visited = 0;
- HeapRegion* hr = g1cs->inc_head();
- size_t sampled_rs_lengths = 0;
-
- while (hr != NULL) {
- size_t rs_length = hr->rem_set()->occupied();
- sampled_rs_lengths += rs_length;
-
- // Update the collection set policy information for this region
- g1cs->update_young_region_prediction(hr, rs_length);
-
- ++regions_visited;
+ G1YoungRemSetSamplingClosure cl(&sts);
- // we try to yield every time we visit 10 regions
- if (regions_visited == 10) {
- if (sts.should_yield()) {
- sts.yield();
- // A gc may have occurred and our sampling data is stale and further
- // traversal of the collection set is unsafe
- return;
- }
- regions_visited = 0;
- }
- assert(hr == g1cs->inc_tail() || hr->next_in_collection_set() != NULL, "next should only be null at tail of icset");
- hr = hr->next_in_collection_set();
+ G1CollectionSet* g1cs = g1h->collection_set();
+ g1cs->iterate(&cl);
+
+ if (cl.complete()) {
+ g1p->revise_young_list_target_length_if_necessary(cl.sampled_rs_lengths());
}
- g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths);
}
}
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -284,7 +284,6 @@
_hrm_index(hrm_index),
_allocation_context(AllocationContext::system()),
_humongous_start_region(NULL),
- _next_in_special_set(NULL),
_evacuation_failed(false),
_prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0),
_next(NULL), _prev(NULL),
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -261,12 +261,6 @@
// True iff an attempt to evacuate an object in the region failed.
bool _evacuation_failed;
- // A heap region may be a member one of a number of special subsets, each
- // represented as linked lists through the field below. Currently, there
- // is only one set:
- // The collection set.
- HeapRegion* _next_in_special_set;
-
// Fields used by the HeapRegionSetBase class and subclasses.
HeapRegion* _next;
HeapRegion* _prev;
@@ -476,9 +470,6 @@
inline bool in_collection_set() const;
- inline HeapRegion* next_in_collection_set() const;
- inline void set_next_in_collection_set(HeapRegion* r);
-
void set_allocation_context(AllocationContext_t context) {
_allocation_context = context;
}
@@ -744,7 +735,7 @@
// Terminates the iteration when the "doHeapRegion" method returns "true".
class HeapRegionClosure : public StackObj {
friend class HeapRegionManager;
- friend class G1CollectedHeap;
+ friend class G1CollectionSet;
bool _complete;
void incomplete() { _complete = false; }
--- a/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.inline.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -230,18 +230,4 @@
return G1CollectedHeap::heap()->is_in_cset(this);
}
-inline HeapRegion* HeapRegion::next_in_collection_set() const {
- assert(in_collection_set(), "should only invoke on member of CS.");
- assert(_next_in_special_set == NULL ||
- _next_in_special_set->in_collection_set(),
- "Malformed CS.");
- return _next_in_special_set;
-}
-
-void HeapRegion::set_next_in_collection_set(HeapRegion* r) {
- assert(in_collection_set(), "should only invoke on member of CS.");
- assert(r == NULL || r->in_collection_set(), "Malformed CS.");
- _next_in_special_set = r;
-}
-
#endif // SHARE_VM_GC_G1_HEAPREGION_INLINE_HPP
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -386,13 +386,21 @@
void GCTaskManager::add_workers(bool initializing) {
os::ThreadType worker_type = os::pgc_thread;
+ uint previous_created_workers = _created_workers;
+
_created_workers = WorkerManager::add_workers(this,
_active_workers,
- (uint) _workers,
+ _workers,
_created_workers,
worker_type,
initializing);
_active_workers = MIN2(_created_workers, _active_workers);
+
+ WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
+}
+
+const char* GCTaskManager::group_name() {
+ return "ParGC Thread";
}
void GCTaskManager::initialize() {
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -556,6 +556,8 @@
GCTaskThread* install_worker(uint worker_id);
// Add GC workers as needed.
void add_workers(bool initializing);
+ // Base name (without worker id #) of threads.
+ const char* group_name();
};
//
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -45,7 +45,7 @@
_time_stamp_index(0)
{
set_id(which);
- set_name("ParGC Thread#%d", which);
+ set_name("%s#%d", manager->group_name(), which);
}
GCTaskThread::~GCTaskThread() {
--- a/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskThread.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -55,6 +55,7 @@
return new GCTaskThread(manager, which, processor_id);
}
public:
+
static void destroy(GCTaskThread* manager) {
if (manager != NULL) {
delete manager;
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -159,6 +159,8 @@
inline static void post_allocation_setup_array(KlassHandle klass,
HeapWord* obj, int length);
+ inline static void post_allocation_setup_class(KlassHandle klass, HeapWord* obj, int size);
+
// Clears an allocated object.
inline static void init_obj(HeapWord* obj, size_t size);
@@ -300,6 +302,7 @@
inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);
inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS);
inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
+ inline static oop class_allocate(KlassHandle klass, int size, TRAPS);
inline static void post_allocation_install_obj_klass(KlassHandle klass,
oop obj);
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
#define SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
+#include "classfile/javaClasses.hpp"
#include "gc/shared/allocTracer.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
@@ -96,6 +97,22 @@
post_allocation_notify(klass, (oop)obj, size);
}
+void CollectedHeap::post_allocation_setup_class(KlassHandle klass,
+ HeapWord* obj,
+ int size) {
+ // Set oop_size field before setting the _klass field
+ // in post_allocation_setup_common() because the klass field
+ // indicates that the object is parsable by concurrent GC.
+ oop new_cls = (oop)obj;
+ assert(size > 0, "oop_size must be positive.");
+ java_lang_Class::set_oop_size(new_cls, size);
+ post_allocation_setup_common(klass, obj);
+ assert(Universe::is_bootstrapping() ||
+ !new_cls->is_array(), "must not be an array");
+ // notify jvmti and dtrace
+ post_allocation_notify(klass, new_cls, size);
+}
+
void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
HeapWord* obj,
int length) {
@@ -207,6 +224,16 @@
return (oop)obj;
}
+oop CollectedHeap::class_allocate(KlassHandle klass, int size, TRAPS) {
+ debug_only(check_for_valid_allocation_state());
+ assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
+ assert(size >= 0, "int won't convert to size_t");
+ HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
+ post_allocation_setup_class(klass, obj, size); // set oop_size
+ NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
+ return (oop)obj;
+}
+
oop CollectedHeap::array_allocate(KlassHandle klass,
int size,
int length,
--- a/hotspot/src/share/vm/gc/shared/workerManager.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/shared/workerManager.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -47,18 +47,18 @@
// threads and a failure would not be optimal but should not be fatal.
template <class WorkerType>
static uint add_workers (WorkerType* holder,
- uint active_workers,
- uint total_workers,
- uint created_workers,
- os::ThreadType worker_type,
- bool initializing) {
+ uint active_workers,
+ uint total_workers,
+ uint created_workers,
+ os::ThreadType worker_type,
+ bool initializing) {
uint start = created_workers;
uint end = MIN2(active_workers, total_workers);
for (uint worker_id = start; worker_id < end; worker_id += 1) {
WorkerThread* new_worker = holder->install_worker(worker_id);
assert(new_worker != NULL, "Failed to allocate GangWorker");
if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
- if(initializing) {
+ if (initializing) {
vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
"Cannot create worker GC thread. Out of system resources.");
}
@@ -67,11 +67,21 @@
os::start_thread(new_worker);
}
- log_trace(gc, task)("AdaptiveSizePolicy::add_workers() : "
- "active_workers: %u created_workers: %u",
- active_workers, created_workers);
+ return created_workers;
+ }
- return created_workers;
+ // Log (at trace level) a change in the number of created workers.
+ template <class WorkerType>
+ static void log_worker_creation(WorkerType* holder,
+ uint previous_created_workers,
+ uint active_workers,
+ uint created_workers,
+ bool initializing) {
+ if (previous_created_workers < created_workers) {
+ const char* initializing_msg = initializing ? "Adding initial" : "Creating additional";
+ log_trace(gc, task)("%s %s(s) previously created workers %u active workers %u total created workers %u",
+ initializing_msg, holder->group_name(), previous_created_workers, active_workers, created_workers);
+ }
}
};
#endif // SHARE_VM_GC_SHARED_WORKERMANAGER_HPP
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -66,6 +66,7 @@
} else {
worker_type = os::pgc_thread;
}
+ uint previous_created_workers = _created_workers;
_created_workers = WorkerManager::add_workers(this,
active_workers,
@@ -74,6 +75,8 @@
worker_type,
initializing);
_active_workers = MIN2(_created_workers, _active_workers);
+
+ WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
}
AbstractGangWorker* AbstractWorkGang::worker(uint i) const {
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -176,6 +176,9 @@
// Return the Ith worker.
AbstractGangWorker* worker(uint i) const;
+ // Base name (without worker id #) of threads.
+ const char* group_name() { return name(); }
+
void threads_do(ThreadClosure* tc) const;
// Create a GC worker and install it into the work gang.
--- a/hotspot/src/share/vm/interpreter/bytecodeStream.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/interpreter/bytecodeStream.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,12 +31,12 @@
// set next bytecode position
address bcp = RawBytecodeStream::bcp();
address end = method()->code_base() + end_bci();
- int l = Bytecodes::raw_special_length_at(bcp, end);
- if (l <= 0 || (_bci + l) > _end_bci) {
+ int len = Bytecodes::raw_special_length_at(bcp, end);
+ // Very large tableswitch or lookupswitch size can cause _next_bci to overflow.
+ if (len <= 0 || (_bci > _end_bci - len) || (_bci - len >= _next_bci)) {
code = Bytecodes::_illegal;
} else {
- _next_bci += l;
- assert(_bci < _next_bci, "length must be > 0");
+ _next_bci += len;
// set attributes
_is_wide = false;
// check for special (uncommon) cases
--- a/hotspot/src/share/vm/interpreter/bytecodeStream.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/interpreter/bytecodeStream.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -135,12 +135,15 @@
code = Bytecodes::code_or_bp_at(bcp);
// set next bytecode position
- int l = Bytecodes::length_for(code);
- if (l > 0 && (_bci + l) <= _end_bci) {
+ int len = Bytecodes::length_for(code);
+ if (len > 0 && (_bci <= _end_bci - len)) {
assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch
&& code != Bytecodes::_lookupswitch, "can't be special bytecode");
_is_wide = false;
- _next_bci += l;
+ _next_bci += len;
+ if (_next_bci <= _bci) { // Check for integer overflow
+ code = Bytecodes::_illegal;
+ }
_raw_code = code;
return code;
} else {
@@ -189,19 +192,23 @@
// note that we cannot advance before having the
// tty bytecode otherwise the stepping is wrong!
// (carefull: length_for(...) must be used first!)
- int l = Bytecodes::length_for(code);
- if (l == 0) l = Bytecodes::length_at(_method(), bcp);
- _next_bci += l;
- assert(_bci < _next_bci, "length must be > 0");
- // set attributes
- _is_wide = false;
- // check for special (uncommon) cases
- if (code == Bytecodes::_wide) {
- raw_code = (Bytecodes::Code)bcp[1];
- code = raw_code; // wide BCs are always Java-normal
- _is_wide = true;
+ int len = Bytecodes::length_for(code);
+ if (len == 0) len = Bytecodes::length_at(_method(), bcp);
+ if (len <= 0 || (_bci > _end_bci - len) || (_bci - len >= _next_bci)) {
+ raw_code = code = Bytecodes::_illegal;
+ } else {
+ _next_bci += len;
+ assert(_bci < _next_bci, "length must be > 0");
+ // set attributes
+ _is_wide = false;
+ // check for special (uncommon) cases
+ if (code == Bytecodes::_wide) {
+ raw_code = (Bytecodes::Code)bcp[1];
+ code = raw_code; // wide BCs are always Java-normal
+ _is_wide = true;
+ }
+ assert(Bytecodes::is_java_code(code), "sanity check");
}
- assert(Bytecodes::is_java_code(code), "sanity check");
}
_raw_code = raw_code;
_code = code;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -576,27 +576,27 @@
// compute auxiliary field attributes
TosState state = as_TosState(info.field_type());
- // We need to delay resolving put instructions on final fields
- // until we actually invoke one. This is required so we throw
- // exceptions at the correct place. If we do not resolve completely
- // in the current pass, leaving the put_code set to zero will
- // cause the next put instruction to reresolve.
- Bytecodes::Code put_code = (Bytecodes::Code)0;
-
- // We also need to delay resolving getstatic instructions until the
- // class is intitialized. This is required so that access to the static
+ // Put instructions on final fields are not resolved. This is required so we throw
+ // exceptions at the correct place (when the instruction is actually invoked).
+ // If we do not resolve an instruction in the current pass, leaving the put_code
+ // set to zero will cause the next put instruction to the same field to reresolve.
+ //
+ // Also, we need to delay resolving getstatic and putstatic instructions until the
+ // class is initialized. This is required so that access to the static
// field will call the initialization function every time until the class
// is completely initialized ala. in 2.17.5 in JVM Specification.
InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
!klass->is_initialized());
+
+ Bytecodes::Code put_code = (Bytecodes::Code)0;
+ if (is_put && !info.access_flags().is_final() && !uninitialized_static) {
+ put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
+ }
+
Bytecodes::Code get_code = (Bytecodes::Code)0;
-
if (!uninitialized_static) {
get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
- if (is_put || !info.access_flags().is_final()) {
- put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
- }
}
cp_cache_entry->set_field(
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -970,7 +970,7 @@
if (is_initialized_static_final_update || is_initialized_instance_final_update) {
ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ",
is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(),
- current_klass()->external_name(),
+ m()->name()->as_C_string(),
is_static ? "<clinit>" : "<init>");
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
}
--- a/hotspot/src/share/vm/logging/logConfiguration.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logConfiguration.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -415,17 +415,8 @@
void LogConfiguration::describe_current_configuration(outputStream* out){
out->print_cr("Log output configuration:");
for (size_t i = 0; i < _n_outputs; i++) {
- out->print("#" SIZE_FORMAT ": %s ", i, _outputs[i]->name());
- out->print_raw(_outputs[i]->config_string());
- out->print(" ");
- char delimiter[2] = {0};
- for (size_t d = 0; d < LogDecorators::Count; d++) {
- LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
- if (_outputs[i]->decorators().is_decorator(decorator)) {
- out->print("%s%s", delimiter, LogDecorators::name(decorator));
- *delimiter = ',';
- }
- }
+ out->print("#" SIZE_FORMAT ": ", i);
+ _outputs[i]->describe(out);
out->cr();
}
}
--- a/hotspot/src/share/vm/logging/logFileOutput.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logFileOutput.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -428,3 +428,13 @@
result[result_len] = '\0';
return result;
}
+
+void LogFileOutput::describe(outputStream *out) {
+ LogOutput::describe(out);
+ out->print(" ");
+
+ out->print("filecount=%u,filesize=" SIZE_FORMAT "%s", _file_count,
+ byte_size_in_proper_unit(_rotate_size),
+ proper_unit_for_byte_size(_rotate_size));
+}
+
--- a/hotspot/src/share/vm/logging/logFileOutput.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logFileOutput.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -85,6 +85,7 @@
virtual int write(const LogDecorations& decorations, const char* msg);
virtual int write(LogMessageBuffer::Iterator msg_iterator);
virtual void force_rotate();
+ virtual void describe(outputStream *out);
virtual const char* name() const {
return _name;
--- a/hotspot/src/share/vm/logging/logOutput.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logOutput.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -83,3 +83,18 @@
break;
}
}
+
+void LogOutput::describe(outputStream *out) {
+ out->print("%s ", name());
+ out->print_raw(config_string());
+ out->print(" ");
+ char delimiter[2] = {0};
+ for (size_t d = 0; d < LogDecorators::Count; d++) {
+ LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
+ if (decorators().is_decorator(decorator)) {
+ out->print("%s%s", delimiter, LogDecorators::name(decorator));
+ *delimiter = ',';
+ }
+ }
+}
+
--- a/hotspot/src/share/vm/logging/logOutput.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logOutput.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -83,6 +83,8 @@
// Do nothing by default.
}
+ virtual void describe(outputStream *out);
+
virtual const char* name() const = 0;
virtual bool initialize(const char* options, outputStream* errstream) = 0;
virtual int write(const LogDecorations& decorations, const char* msg) = 0;
--- a/hotspot/src/share/vm/logging/logPrefix.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -74,6 +74,7 @@
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, stringtable)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \
--- a/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -3106,10 +3106,6 @@
assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize");
- if (MetaspaceSize < 256*K) {
- vm_exit_during_initialization("Too small initial Metaspace size");
- }
-
MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment);
MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment);
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -60,6 +60,7 @@
bool MetaspaceShared::_check_classes_made_progress;
bool MetaspaceShared::_has_error_classes;
bool MetaspaceShared::_archive_loading_failed = false;
+bool MetaspaceShared::_remapped_readwrite = false;
address MetaspaceShared::_cds_i2i_entry_code_buffers = NULL;
size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
SharedMiscRegion MetaspaceShared::_mc;
@@ -806,6 +807,10 @@
exit(1);
}
}
+
+ // Copy the verification constraints from C_HEAP-alloced GrowableArrays to RO-alloced
+ // Arrays
+ SystemDictionaryShared::finalize_verification_constraints();
}
void MetaspaceShared::prepare_for_dumping() {
@@ -1181,6 +1186,7 @@
if (!mapinfo->remap_shared_readonly_as_readwrite()) {
return false;
}
+ _remapped_readwrite = true;
}
return true;
}
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -125,6 +125,7 @@
static bool _check_classes_made_progress;
static bool _has_error_classes;
static bool _archive_loading_failed;
+ static bool _remapped_readwrite;
static address _cds_i2i_entry_code_buffers;
static size_t _cds_i2i_entry_code_buffers_size;
@@ -205,6 +206,10 @@
// sharing is enabled. Simply returns true if sharing is not enabled
// or if the remapping has already been done by a prior call.
static bool remap_shared_readonly_as_readwrite() NOT_CDS_RETURN_(true);
+ static bool remapped_readwrite() {
+ CDS_ONLY(return _remapped_readwrite);
+ NOT_CDS(return false);
+ }
static void print_shared_spaces();
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -27,6 +27,7 @@
#include "classfile/classFileStream.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/dependencyContext.hpp"
@@ -597,6 +598,8 @@
// also sets rewritten
this_k->rewrite_class(CHECK_false);
+ } else if (this_k->is_shared()) {
+ SystemDictionaryShared::check_verification_constraints(this_k, CHECK_false);
}
// relocate jsrs and link methods after they are all rewritten
@@ -606,7 +609,12 @@
// methods have been rewritten since rewrite may
// fabricate new Method*s.
// also does loader constraint checking
- if (!this_k()->is_shared()) {
+ //
+ // initialize_vtable and initialize_itable need to be rerun for
+ // a shared class if the class is not loaded by the NULL classloader.
+ ClassLoaderData * loader_data = this_k->class_loader_data();
+ if (!(this_k->is_shared() &&
+ loader_data->is_the_null_class_loader_data())) {
ResourceMark rm(THREAD);
this_k->vtable()->initialize_vtable(true, CHECK_false);
this_k->itable()->initialize_itable(true, CHECK_false);
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,13 +50,12 @@
// Query before forming handle.
int size = instance_size(k);
KlassHandle h_k(THREAD, this);
- instanceOop i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
+
+ assert(size > 0, "total object size must be positive: %d", size);
// Since mirrors can be variable sized because of the static fields, store
// the size in the mirror itself.
- java_lang_Class::set_oop_size(i, size);
-
- return i;
+ return (instanceOop)CollectedHeap::class_allocate(h_k, size, CHECK_NULL);
}
int InstanceMirrorKlass::oop_size(oop obj) const {
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -27,6 +27,7 @@
#include "classfile/vmSymbols.hpp"
#include "gc/shared/gcLocker.hpp"
#include "logging/log.hpp"
+#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
#include "oops/instanceKlass.hpp"
@@ -42,6 +43,10 @@
return InstanceKlass::cast(_klass());
}
+bool klassVtable::is_preinitialized_vtable() {
+ return _klass->is_shared() && !MetaspaceShared::remapped_readwrite();
+}
+
// this function computes the vtable size (including the size needed for miranda
// methods) and the number of miranda methods in this class.
@@ -126,6 +131,12 @@
int klassVtable::initialize_from_super(KlassHandle super) {
if (super.is_null()) {
return 0;
+ } else if (is_preinitialized_vtable()) {
+ // A shared class' vtable is preinitialized at dump time. No need to copy
+ // methods from super class for shared class, as that was already done
+ // during archiving time. However, if Jvmti has redefined a class,
+ // copy super class's vtable in case the super class has changed.
+ return super->vtable()->length();
} else {
// copy methods from superKlass
klassVtable* superVtable = super->vtable();
@@ -152,6 +163,8 @@
KlassHandle super (THREAD, klass()->java_super());
int nofNewEntries = 0;
+ bool is_shared = _klass->is_shared();
+
if (!klass()->is_array_klass()) {
ResourceMark rm(THREAD);
log_develop_debug(vtables)("Initializing: %s", _klass->name()->as_C_string());
@@ -164,6 +177,7 @@
#endif
if (Universe::is_bootstrapping()) {
+ assert(!is_shared, "sanity");
// just clear everything
for (int i = 0; i < _length; i++) table()[i].clear();
return;
@@ -203,6 +217,7 @@
if (len > 0) {
Array<int>* def_vtable_indices = NULL;
if ((def_vtable_indices = ik()->default_vtable_indices()) == NULL) {
+ assert(!is_shared, "shared class def_vtable_indices does not exist");
def_vtable_indices = ik()->create_new_default_vtable_indices(len, CHECK);
} else {
assert(def_vtable_indices->length() == len, "reinit vtable len?");
@@ -217,7 +232,15 @@
// needs new entry
if (needs_new_entry) {
put_method_at(mh(), initialized);
- def_vtable_indices->at_put(i, initialized); //set vtable index
+ if (is_preinitialized_vtable()) {
+ // At runtime initialize_vtable is rerun for a shared class
+ // (loaded by the non-boot loader) as part of link_class_impl().
+ // The dumptime vtable index should be the same as the runtime index.
+ assert(def_vtable_indices->at(i) == initialized,
+ "dump time vtable index is different from runtime index");
+ } else {
+ def_vtable_indices->at_put(i, initialized); //set vtable index
+ }
initialized++;
}
}
@@ -378,7 +401,8 @@
}
// we need a new entry if there is no superclass
- if (klass->super() == NULL) {
+ Klass* super = klass->super();
+ if (super == NULL) {
return allocate_new;
}
@@ -407,7 +431,15 @@
Symbol* target_classname = target_klass->name();
for(int i = 0; i < super_vtable_len; i++) {
- Method* super_method = method_at(i);
+ Method* super_method;
+ if (is_preinitialized_vtable()) {
+ // If this is a shared class, the vtable is already in the final state (fully
+ // initialized). Need to look at the super's vtable.
+ klassVtable* superVtable = super->vtable();
+ super_method = superVtable->method_at(i);
+ } else {
+ super_method = method_at(i);
+ }
// Check if method name matches
if (super_method->name() == name && super_method->signature() == signature) {
@@ -475,7 +507,15 @@
target_method()->set_vtable_index(i);
} else {
if (def_vtable_indices != NULL) {
- def_vtable_indices->at_put(default_index, i);
+ if (is_preinitialized_vtable()) {
+ // At runtime initialize_vtable is rerun as part of link_class_impl()
+ // for a shared class loaded by the non-boot loader.
+ // The dumptime vtable index should be the same as the runtime index.
+ assert(def_vtable_indices->at(default_index) == i,
+ "dump time vtable index is different from runtime index");
+ } else {
+ def_vtable_indices->at_put(default_index, i);
+ }
}
assert(super_method->is_default_method() || super_method->is_overpass()
|| super_method->is_abstract(), "default override error");
@@ -490,17 +530,26 @@
}
void klassVtable::put_method_at(Method* m, int index) {
- if (log_develop_is_enabled(Trace, vtables)) {
- ResourceMark rm;
- outputStream* logst = Log(vtables)::trace_stream();
- const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : "<NULL>";
- logst->print("adding %s at index %d, flags: ", sig, index);
- if (m != NULL) {
- m->print_linkage_flags(logst);
+ if (is_preinitialized_vtable()) {
+ // At runtime initialize_vtable is rerun as part of link_class_impl()
+ // for shared class loaded by the non-boot loader to obtain the loader
+ // constraints based on the runtime classloaders' context. The dumptime
+ // method at the vtable index should be the same as the runtime method.
+ assert(table()[index].method() == m,
+ "archived method is different from the runtime method");
+ } else {
+ if (log_develop_is_enabled(Trace, vtables)) {
+ ResourceMark rm;
+ outputStream* logst = Log(vtables)::trace_stream();
+ const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : "<NULL>";
+ logst->print("adding %s at index %d, flags: ", sig, index);
+ if (m != NULL) {
+ m->print_linkage_flags(logst);
+ }
+ logst->cr();
}
- logst->cr();
+ table()[index].set(m);
}
- table()[index].set(m);
}
// Find out if a method "m" with superclass "super", loader "classloader" and
@@ -950,7 +999,15 @@
void itableMethodEntry::initialize(Method* m) {
if (m == NULL) return;
- _method = m;
+ if (MetaspaceShared::is_in_shared_space((void*)&_method) &&
+ !MetaspaceShared::remapped_readwrite()) {
+ // At runtime initialize_itable is rerun as part of link_class_impl()
+ // for a shared class loaded by the non-boot loader.
+ // The dumptime itable method entry should be the same as the runtime entry.
+ assert(_method == m, "sanity");
+ } else {
+ _method = m;
+ }
}
klassItable::klassItable(instanceKlassHandle klass) {
@@ -1054,7 +1111,11 @@
logst->cr();
}
if (!m->has_vtable_index()) {
- assert(m->vtable_index() == Method::pending_itable_index, "set by initialize_vtable");
+ // A shared method could have an initialized itable_index that
+ // is < 0.
+ assert(m->vtable_index() == Method::pending_itable_index ||
+ m->is_shared(),
+ "set by initialize_vtable");
m->set_itable_index(ime_num);
// Progress to next itable entry
ime_num++;
@@ -1248,7 +1309,6 @@
}
#endif // INCLUDE_JVMTI
-
// Setup
class InterfaceVisiterClosure : public StackObj {
public:
--- a/hotspot/src/share/vm/oops/klassVtable.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/klassVtable.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -153,6 +153,19 @@
Array<Klass*>* local_interfaces);
void verify_against(outputStream* st, klassVtable* vt, int index);
inline InstanceKlass* ik() const;
+ // When loading a class from CDS archive at run time, and no class redefintion
+ // has happened, it is expected that the class's itable/vtables are
+ // laid out exactly the same way as they had been during dump time.
+ // Therefore, in klassVtable::initialize_[iv]table, we do not layout the
+ // tables again. Instead, we only rerun the process to create/check
+ // the class loader constraints. In non-product builds, we add asserts to
+ // guarantee that the table's layout would be the same as at dump time.
+ //
+ // If JVMTI redefines any class, the read-only shared memory are remapped
+ // as read-write. A shared class' vtable/itable are re-initialized and
+ // might have different layout due to class redefinition of the shared class
+ // or its super types.
+ bool is_preinitialized_vtable();
};
--- a/hotspot/src/share/vm/oops/method.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -313,6 +313,33 @@
unlink_method();
}
+void Method::set_vtable_index(int index) {
+ if (is_shared() && !MetaspaceShared::remapped_readwrite()) {
+ // At runtime initialize_vtable is rerun as part of link_class_impl()
+ // for a shared class loaded by the non-boot loader to obtain the loader
+ // constraints based on the runtime classloaders' context.
+ return; // don't write into the shared class
+ } else {
+ _vtable_index = index;
+ }
+}
+
+void Method::set_itable_index(int index) {
+ if (is_shared() && !MetaspaceShared::remapped_readwrite()) {
+ // At runtime initialize_itable is rerun as part of link_class_impl()
+ // for a shared class loaded by the non-boot loader to obtain the loader
+ // constraints based on the runtime classloaders' context. The dumptime
+ // itable index should be the same as the runtime index.
+ assert(_vtable_index == itable_index_max - index,
+ "archived itable index is different from runtime index");
+ return; // don’t write into the shared class
+ } else {
+ _vtable_index = itable_index_max - index;
+ }
+ assert(valid_itable_index(), "");
+}
+
+
bool Method::was_executed_more_than(int n) {
// Invocation counter is reset when the Method* is compiled.
--- a/hotspot/src/share/vm/oops/method.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/method.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -470,12 +470,12 @@
DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; })
bool has_vtable_index() const { return _vtable_index >= 0; }
int vtable_index() const { return _vtable_index; }
- void set_vtable_index(int index) { _vtable_index = index; }
+ void set_vtable_index(int index);
DEBUG_ONLY(bool valid_itable_index() const { return _vtable_index <= pending_itable_index; })
bool has_itable_index() const { return _vtable_index <= itable_index_max; }
int itable_index() const { assert(valid_itable_index(), "");
return itable_index_max - _vtable_index; }
- void set_itable_index(int index) { _vtable_index = itable_index_max - index; assert(valid_itable_index(), ""); }
+ void set_itable_index(int index);
// interpreter entry
address interpreter_entry() const { return _i2i_entry; }
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -258,8 +258,8 @@
}
}
- assert(s % MinObjAlignment == 0, "alignment check");
- assert(s > 0, "Bad size calculated");
+ assert(s % MinObjAlignment == 0, "Oop size is not properly aligned: %d", s);
+ assert(s > 0, "Oop size must be greater than zero, not %d", s);
return s;
}
--- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -2405,8 +2405,13 @@
Compile::AliasType* alias_type = C->alias_type(adr_type);
assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here");
- assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM ||
- alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown");
+ // Only field, array element or unknown locations are supported.
+ if (alias_type->adr_type() != TypeRawPtr::BOTTOM &&
+ alias_type->adr_type() != TypeOopPtr::BOTTOM &&
+ alias_type->basic_type() == T_ILLEGAL) {
+ return false;
+ }
+
bool mismatched = false;
BasicType bt = alias_type->basic_type();
if (bt != T_ILLEGAL) {
@@ -2782,12 +2787,6 @@
ShouldNotReachHere();
}
- // Null check receiver.
- receiver = null_check(receiver);
- if (stopped()) {
- return true;
- }
-
// Build field offset expression.
// We currently rely on the cookies produced by Unsafe.xxxFieldOffset
// to be plain byte offsets, which are also the same as those accepted
@@ -2799,8 +2798,6 @@
const TypePtr *adr_type = _gvn.type(adr)->isa_ptr();
Compile::AliasType* alias_type = C->alias_type(adr_type);
- assert(alias_type->adr_type() == TypeRawPtr::BOTTOM || alias_type->adr_type() == TypeOopPtr::BOTTOM ||
- alias_type->basic_type() != T_ILLEGAL, "field, array element or unknown");
BasicType bt = alias_type->basic_type();
if (bt != T_ILLEGAL &&
((bt == T_OBJECT || bt == T_ARRAY) != (type == T_OBJECT))) {
@@ -2832,6 +2829,12 @@
ShouldNotReachHere();
}
+ // Null check receiver.
+ receiver = null_check(receiver);
+ if (stopped()) {
+ return true;
+ }
+
int alias_idx = C->get_alias_index(adr_type);
// Memory-model-wise, a LoadStore acts like a little synchronized
--- a/hotspot/src/share/vm/prims/jvmti.xml Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/prims/jvmti.xml Wed Jul 27 13:33:55 2016 +0000
@@ -6509,6 +6509,59 @@
<errors>
</errors>
</function>
+
+ <function id="GetNamedModule" num="40" since="9">
+ <synopsis>Get Named Module</synopsis>
+ <description>
+ Return the <code>java.lang.reflect.Module</code> object for a named
+ module defined to a class loader that contains a given package.
+ The module is returned via <code>module_ptr</code>.
+ <p/>
+ If a named module is defined to the class loader and it
+ contains the package then that named module is returned,
+ otherwise <code>NULL</code> is returned.
+ <p/>
+ </description>
+ <origin>new</origin>
+ <capabilities>
+ </capabilities>
+ <parameters>
+ <param id="class_loader">
+ <ptrtype>
+ <jobject/>
+ <nullok>the bootstrap loader is assumed</nullok>
+ </ptrtype>
+ <description>
+ A class loader.
+ If the <code>class_loader</code> is not <code>NULL</code>
+ or a subclass of <code>java.lang.ClassLoader</code>
+ this function returns
+ <errorlink id="JVMTI_ERROR_ILLEGAL_ARGUMENT"></errorlink>.
+ </description>
+ </param>
+ <param id="package_name">
+ <inbuf><char/></inbuf>
+ <description>
+ The name of the package, encoded as a
+ <internallink id="mUTF">modified UTF-8</internallink> string.
+ The package name is in internal form (JVMS 4.2.1);
+ identifiers are separated by forward slashes rather than periods.
+ </description>
+ </param>
+ <param id="module_ptr">
+ <outptr><jobject/></outptr>
+ <description>
+ On return, points to a <code>java.lang.reflect.Module</code> object
+ or points to <code>NULL</code>.
+ </description>
+ </param>
+ </parameters>
+ <errors>
+ <error id="JVMTI_ERROR_ILLEGAL_ARGUMENT">
+ If class loader is not <code>NULL</code> and is not a class loader object.
+ </error>
+ </errors>
+ </function>
</category>
<category id="class" label="Class">
@@ -12462,6 +12515,14 @@
<code>new_class_data</code> has been set, it becomes the
<code>class_data</code> for the next agent.
<p/>
+ When handling a class load in the live phase, then the
+ <functionlink id="GetNamedModule"></functionlink>
+ function can be used to map class loader and a package name to a module.
+ When a class is being redefined or retransformed then
+ <code>class_being_redefined</code> is non <code>NULL</code> and so
+ the JNI <code>GetModule</code> function can also be used
+ to obtain the Module.
+ <p/>
The order that this event is sent to each environment differs
from other events.
This event is sent to environments in the following order:
@@ -14427,20 +14488,15 @@
<change date="19 June 2013" version="1.2.3">
Added support for statically linked agents.
</change>
- <change date="20 January 2016" version="9.0.0">
+ <change date="5 July 2016" version="9.0.0">
Support for modules:
- The majorversion is 9 now
- The ClassFileLoadHook events are not sent during the primordial phase anymore.
- Add new function GetAllModules
- </change>
- <change date="17 February 2016" version="9.0.0">
- Support for modules:
- Add new capability can_generate_early_vmstart
- Allow CompiledMethodLoad events at start phase
- </change>
- <change date="14 April 2016" version="9.0.0">
- Support for modules:
- Add new capability can_generate_early_class_hook_events
+ - Add new function GetNamedModule
</change>
</changehistory>
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderExt.hpp"
+#include "classfile/modules.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodeStream.hpp"
@@ -201,6 +202,28 @@
} /* end GetAllModules */
+// class_loader - NULL is a valid value, must be pre-checked
+// package_name - pre-checked for NULL
+// module_ptr - pre-checked for NULL
+jvmtiError
+JvmtiEnv::GetNamedModule(jobject class_loader, const char* package_name, jobject* module_ptr) {
+ JavaThread* THREAD = JavaThread::current(); // pass to macros
+ ResourceMark rm(THREAD);
+
+ Handle h_loader (THREAD, JNIHandles::resolve(class_loader));
+ // Check that loader is a subclass of java.lang.ClassLoader.
+ if (h_loader.not_null() && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
+ }
+ jobject module = Modules::get_named_module(h_loader, package_name, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return JVMTI_ERROR_INTERNAL; // unexpected exception
+ }
+ *module_ptr = module;
+ return JVMTI_ERROR_NONE;
+} /* end GetNamedModule */
+
//
// Class functions
//
--- a/hotspot/src/share/vm/runtime/objectMonitor.cpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp Wed Jul 27 13:33:55 2016 +0000
@@ -131,8 +131,6 @@
static int Knob_QMode = 0; // EntryList-cxq policy - queue discipline
static volatile int InitDone = 0;
-#define TrySpin TrySpin_VaryDuration
-
// -----------------------------------------------------------------------------
// Theory of operations -- Monitors lists, thread residency, etc:
//
@@ -1848,13 +1846,8 @@
// hysteresis control to damp the transition rate between spinning and
// not spinning.
-intptr_t ObjectMonitor::SpinCallbackArgument = 0;
-int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL;
-
// Spinning: Fixed frequency (100%), vary duration
-
-
-int ObjectMonitor::TrySpin_VaryDuration(Thread * Self) {
+int ObjectMonitor::TrySpin(Thread * Self) {
// Dumb, brutal spin. Good for comparative measurements against adaptive spinning.
int ctr = Knob_FixedSpin;
if (ctr != 0) {
@@ -1948,11 +1941,6 @@
goto Abort; // abrupt spin egress
}
if (Knob_UsePause & 1) SpinPause();
-
- int (*scb)(intptr_t,int) = SpinCallbackFunction;
- if (hits > 50 && scb != NULL) {
- int abend = (*scb)(SpinCallbackArgument, 0);
- }
}
if (Knob_UsePause & 2) SpinPause();
--- a/hotspot/src/share/vm/runtime/objectMonitor.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/runtime/objectMonitor.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -161,9 +161,6 @@
Thread * volatile _Responsible;
volatile int _Spinner; // for exit->spinner handoff optimization
- volatile int _SpinFreq; // Spin 1-out-of-N attempts: success rate
- volatile int _SpinClock;
- volatile intptr_t _SpinState; // MCS/CLH list of spinners
volatile int _SpinDuration;
volatile jint _count; // reference count to prevent reclamation/deflation
@@ -238,10 +235,6 @@
static int cxq_offset_in_bytes() { return offset_of(ObjectMonitor, _cxq); }
static int succ_offset_in_bytes() { return offset_of(ObjectMonitor, _succ); }
static int EntryList_offset_in_bytes() { return offset_of(ObjectMonitor, _EntryList); }
- static int FreeNext_offset_in_bytes() { return offset_of(ObjectMonitor, FreeNext); }
- static int WaitSet_offset_in_bytes() { return offset_of(ObjectMonitor, _WaitSet); }
- static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible); }
- static int Spinner_offset_in_bytes() { return offset_of(ObjectMonitor, _Spinner); }
// ObjectMonitor references can be ORed with markOopDesc::monitor_value
// as part of the ObjectMonitor tagging mechanism. When we combine an
@@ -257,11 +250,6 @@
#define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \
((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value)
- // Eventually we'll make provisions for multiple callbacks, but
- // now one will suffice.
- static int (*SpinCallbackFunction)(intptr_t, int);
- static intptr_t SpinCallbackArgument;
-
markOop header() const;
void set_header(markOop hdr);
@@ -312,8 +300,6 @@
_cxq = NULL;
_WaitSet = NULL;
_recursions = 0;
- _SpinFreq = 0;
- _SpinClock = 0;
}
public:
@@ -353,9 +339,7 @@
void UnlinkAfterAcquire(Thread * Self, ObjectWaiter * SelfNode);
int TryLock(Thread * Self);
int NotRunnable(Thread * Self, Thread * Owner);
- int TrySpin_Fixed(Thread * Self);
- int TrySpin_VaryFrequency(Thread * Self);
- int TrySpin_VaryDuration(Thread * Self);
+ int TrySpin(Thread * Self);
void ExitEpilog(Thread * Self, ObjectWaiter * Wakee);
bool ExitSuspendEquivalent(JavaThread * Self);
void post_monitor_wait_event(EventJavaMonitorWait * event,
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -144,8 +144,6 @@
static void verify() PRODUCT_RETURN;
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
- static void RegisterSpinCallback(int(*)(intptr_t, int), intptr_t);
-
private:
enum { _BLOCKSIZE = 128 };
// global list of blocks of monitors
--- a/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/compiler/ciReplay/TestVM_no_comp_level.sh Wed Jul 27 13:33:55 2016 +0000
@@ -29,6 +29,7 @@
## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level
## @author igor.ignatyev@oracle.com
## @requires vm.flightRecorder != true
+## @ignore 8157984
## @run shell TestVM_no_comp_level.sh
##
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Wed Jul 27 13:33:55 2016 +0000
@@ -25,6 +25,7 @@
* @test
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
* @library ../../../../../
+ * @ignore 8161550
* @modules java.base/jdk.internal.reflect
* jdk.vm.ci/jdk.vm.ci.meta
* jdk.vm.ci/jdk.vm.ci.runtime
--- a/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Wed Jul 27 13:33:55 2016 +0000
@@ -28,6 +28,7 @@
* @library /testlibrary /test/lib /
* @modules java.base/jdk.internal.misc
* java.management
+ * @ignore 8157984
* @build TestRangeCheckSmearing
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* jdk.test.lib.Platform
--- a/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/compiler/tiered/NonTieredLevelsTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -26,6 +26,7 @@
* @library /testlibrary /test/lib /
* @modules java.base/jdk.internal.misc
* @modules java.management
+ * @ignore 8157984
* @build NonTieredLevelsTest
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/unsafe/OpaqueAccesses.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8155781
+ * @modules java.base/jdk.internal.misc
+ *
+ * @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
+ * -XX:-TieredCompilation -Xbatch
+ * -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
+ * compiler.unsafe.OpaqueAccesses
+ */
+package compiler.unsafe;
+
+import jdk.internal.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+public class OpaqueAccesses {
+ private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+ private static final Object INSTANCE = new OpaqueAccesses();
+
+ private static final Object[] ARRAY = new Object[10];
+
+ private static final long F_OFFSET;
+ private static final long E_OFFSET;
+
+ static {
+ try {
+ Field field = OpaqueAccesses.class.getDeclaredField("f");
+ F_OFFSET = UNSAFE.objectFieldOffset(field);
+
+ E_OFFSET = UNSAFE.arrayBaseOffset(ARRAY.getClass());
+ } catch (NoSuchFieldException e) {
+ throw new Error(e);
+ }
+ }
+
+ private Object f = new Object();
+
+ static Object testFixedOffsetField(Object o) {
+ return UNSAFE.getObject(o, F_OFFSET);
+ }
+
+ static int testFixedOffsetHeader0(Object o) {
+ return UNSAFE.getInt(o, 0);
+ }
+
+ static int testFixedOffsetHeader4(Object o) {
+ return UNSAFE.getInt(o, 4);
+ }
+
+ static Object testFixedBase(long off) {
+ return UNSAFE.getObject(INSTANCE, off);
+ }
+
+ static Object testOpaque(Object o, long off) {
+ return UNSAFE.getObject(o, off);
+ }
+
+ static int testFixedOffsetHeaderArray0(Object[] arr) {
+ return UNSAFE.getInt(arr, 0);
+ }
+
+ static int testFixedOffsetHeaderArray4(Object[] arr) {
+ return UNSAFE.getInt(arr, 4);
+ }
+
+ static Object testFixedOffsetArray(Object[] arr) {
+ return UNSAFE.getObject(arr, E_OFFSET);
+ }
+
+ static Object testFixedBaseArray(long off) {
+ return UNSAFE.getObject(ARRAY, off);
+ }
+
+ static Object testOpaqueArray(Object[] o, long off) {
+ return UNSAFE.getObject(o, off);
+ }
+
+ static final long ADDR = UNSAFE.allocateMemory(10);
+ static boolean flag;
+
+ static int testMixedAccess() {
+ flag = !flag;
+ Object o = (flag ? INSTANCE : null);
+ long off = (flag ? F_OFFSET : ADDR);
+ return UNSAFE.getInt(o, off);
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20_000; i++) {
+ // Instance
+ testFixedOffsetField(INSTANCE);
+ testFixedOffsetHeader0(INSTANCE);
+ testFixedOffsetHeader4(INSTANCE);
+ testFixedBase(F_OFFSET);
+ testOpaque(INSTANCE, F_OFFSET);
+ testMixedAccess();
+
+ // Array
+ testFixedOffsetHeaderArray0(ARRAY);
+ testFixedOffsetHeaderArray4(ARRAY);
+ testFixedOffsetArray(ARRAY);
+ testFixedBaseArray(E_OFFSET);
+ testOpaqueArray(ARRAY, E_OFFSET);
+ }
+ System.out.println("TEST PASSED");
+ }
+}
--- a/hotspot/test/gc/TestSmallHeap.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/gc/TestSmallHeap.java Wed Jul 27 13:33:55 2016 +0000
@@ -27,6 +27,7 @@
* @requires vm.gc=="null"
* @summary Verify that starting the VM with a small heap works
* @library /testlibrary /test/lib /test/lib/share/classes
+ * @ignore 8161552
* @modules java.base/jdk.internal.misc
* @modules java.management/sun.management
* @build TestSmallHeap
--- a/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/gc/arguments/TestParallelHeapSizeFlags.java Wed Jul 27 13:33:55 2016 +0000
@@ -29,6 +29,7 @@
* parallel collectors.
* @requires vm.gc=="null"
* @library /testlibrary /test/lib
+ * @ignore 8161552
* @modules java.base/jdk.internal.misc
* java.management
* @build TestParallelHeapSizeFlags TestMaxHeapSizeTools
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/ergonomics/TestInitialGCThreadLogging.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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 TestInitialGCThreadLogging
+ * @bug 8157240
+ * @summary Check trace logging of initial GC threads.
+ * @requires vm.gc=="null"
+ * @key gc
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestInitialGCThreadLogging {
+ public static void main(String[] args) throws Exception {
+
+ testInitialGCThreadLogging("UseConcMarkSweepGC", "GC Thread");
+
+ testInitialGCThreadLogging("UseG1GC", "GC Thread");
+
+ testInitialGCThreadLogging("UseParallelGC", "ParGC Thread");
+ }
+
+ private static void verifyDynamicNumberOfGCThreads(OutputAnalyzer output, String threadName) {
+ output.shouldHaveExitValue(0); // test should run succesfully
+ output.shouldContain(threadName);
+ }
+
+ private static void testInitialGCThreadLogging(String gcFlag, String threadName) throws Exception {
+ // UseDynamicNumberOfGCThreads and TraceDynamicGCThreads enabled
+ String[] baseArgs = {"-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", "-version"};
+
+ // Base test with gc and +UseDynamicNumberOfGCThreads:
+ ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder(baseArgs);
+ verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()), threadName);
+ }
+}
--- a/hotspot/test/gc/g1/TestStringSymbolTableStats.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/gc/g1/TestStringSymbolTableStats.java Wed Jul 27 13:33:55 2016 +0000
@@ -46,7 +46,7 @@
System.out.println("Output:\n" + output.getOutput());
- output.shouldContain("Cleaned string and symbol table");
+ output.shouldMatch("GC\\(\\d+\\) Cleaned string and symbol table");
output.shouldHaveExitValue(0);
}
--- a/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,11 +24,11 @@
import java.util.ArrayList;
/* @test TestMetaspaceInitialization
- * @bug 8042933
+ * @bug 8024945
* @summary Tests to initialize metaspace with a very low MetaspaceSize
* @modules java.base/jdk.internal.misc
* @library /testlibrary
- * @run main/othervm -XX:MetaspaceSize=2m TestMetaspaceInitialization
+ * @run main/othervm -XX:MetaspaceSize=0 TestMetaspaceInitialization
*/
public class TestMetaspaceInitialization {
private class Internal {
--- a/hotspot/test/gc/metaspace/TestMetaspaceSizeFlags.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/gc/metaspace/TestMetaspaceSizeFlags.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,9 +47,6 @@
// 8024650: MaxMetaspaceSize was adjusted instead of MetaspaceSize.
testMaxMetaspaceSizeLTMetaspaceSize(MAX_ALIGNMENT, MAX_ALIGNMENT * 2);
testMaxMetaspaceSizeGTMetaspaceSize(MAX_ALIGNMENT * 2, MAX_ALIGNMENT);
- testTooSmallInitialMetaspace(0, 0);
- testTooSmallInitialMetaspace(0, MAX_ALIGNMENT);
- testTooSmallInitialMetaspace(MAX_ALIGNMENT, 0);
}
private static void testMaxMetaspaceSizeEQMetaspaceSize(long maxMetaspaceSize, long metaspaceSize) throws Exception {
@@ -73,11 +70,6 @@
Asserts.assertEQ(mf.metaspaceSize, metaspaceSize);
}
- private static void testTooSmallInitialMetaspace(long maxMetaspaceSize, long metaspaceSize) throws Exception {
- OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
- output.shouldContain("Too small initial Metaspace size");
- }
-
private static MetaspaceFlags runAndGetValue(long maxMetaspaceSize, long metaspaceSize) throws Exception {
OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
output.shouldNotMatch("Error occurred during initialization of VM\n.*");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutField.jasm Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class TestPutField
+version 53:0
+{
+
+final Field test_field:"I";
+
+
+public Method <init>:"()V"
+ stack 2 locals 1
+{
+ aload_0;
+ dup;
+ invokespecial Method java/lang/Object.<init>:"()V";
+ bipush 13;
+ putfield Field test_field:"I";
+ return;
+}
+
+public Method aMethod:"()I"
+ stack 2 locals 2
+{
+ aload_0;
+ getfield Field test_field:"I";
+ istore_1;
+ aload_0;
+ bipush 14;
+ putfield Field test_field:"I";
+ iload_1;
+ ireturn;
+}
+
+
+public static Method test:"()V"
+ stack 2 locals 2
+{
+ new class TestPutField;
+ astore_0;
+ aload_0;
+ invokespecial Method <init>:"()V";
+ getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
+ astore_1;
+ aload_1;
+ aload_0;
+ invokevirtual Method aMethod:"()I";
+ invokevirtual Method java/io/PrintStream.println:"(I)V";
+ aload_1;
+ aload_0;
+ getfield Field test_field:"I";
+ invokevirtual Method java/io/PrintStream.println:"(I)V";
+ return;
+}
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutMain.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8160527
+ * @summary The VM does not always perform checks added by 8157181 when updating final instance fields
+ * @library /testlibrary
+ * @compile TestPutField.jasm
+ * @compile TestPutStatic.jasm
+ * @compile TestPutMain.java
+ * @run main/othervm TestPutMain
+ */
+
+import jdk.test.lib.Asserts;
+
+public class TestPutMain {
+ public static void main(String[] args) {
+ boolean exception = false;
+ try {
+ TestPutField.test();
+ } catch (java.lang.IllegalAccessError e) {
+ exception = true;
+ }
+
+ Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final instance field was not thrown.");
+
+ exception = false;
+ try {
+ TestPutStatic.test();
+ } catch (java.lang.IllegalAccessError e) {
+ exception = true;
+ }
+
+ Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final static field was not thrown.");
+
+ System.out.println("PASSED: Expected IllegalAccessError was thrown.");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/Final/TestPutStatic.jasm Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+public class TestPutStatic
+version 53:0
+{
+
+final static Field test_field:"I";
+
+
+public static Method <clinit>:"()V"
+ stack 2 locals 1
+{
+ bipush 13;
+ putstatic Field test_field:"I";
+ return;
+}
+
+public static Method aMethod:"()I"
+ stack 1 locals 1
+{
+ getstatic Field test_field:"I";
+ istore_0;
+ bipush 14;
+ putstatic Field test_field:"I";
+ iload_0;
+ ireturn;
+}
+
+
+public static Method test:"()V"
+ stack 2 locals 1
+{
+ getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
+ astore_0;
+ aload_0;
+ invokestatic Method aMethod:"()I";
+ invokevirtual Method java/io/PrintStream.println:"(I)V";
+ aload_0;
+ getstatic Field test_field:"I";
+ invokevirtual Method java/io/PrintStream.println:"(I)V";
+ return;
+}
+
+}
--- a/hotspot/test/runtime/SharedArchiveFile/SASymbolTableTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/runtime/SharedArchiveFile/SASymbolTableTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -24,6 +24,9 @@
/*
* @test SASymbolTableTest
* @summary Walk symbol table using SA, with and without CDS.
+ * Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
+ * it on that platform:
+ * @requires os.family != "mac"
* @library /testlibrary
* @modules java.base/jdk.internal.misc
* jdk.hotspot.agent/sun.jvm.hotspot.oops
--- a/hotspot/test/runtime/Unsafe/GetUnsafe.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/runtime/Unsafe/GetUnsafe.java Wed Jul 27 13:33:55 2016 +0000
@@ -26,6 +26,7 @@
* @summary Verifies that getUnsafe() actually throws SecurityException when unsafeAccess is prohibited.
* @library /testlibrary
* @modules java.base/jdk.internal.misc
+ * @ignore 8161947
* @run main GetUnsafe
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/GetNamedModule/MyPackage/GetNamedModuleTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package MyPackage;
+
+/**
+ * @test
+ * @summary Verifies the JVMTI GetNamedModule API
+ * @compile GetNamedModuleTest.java
+ * @run main/othervm/native -agentlib:GetNamedModuleTest MyPackage.GetNamedModuleTest
+ */
+
+import java.io.PrintStream;
+
+public class GetNamedModuleTest {
+
+ static {
+ try {
+ System.loadLibrary("GetNamedModuleTest");
+ } catch (UnsatisfiedLinkError ule) {
+ System.err.println("Could not load GetNamedModuleTest library");
+ System.err.println("java.library.path: "
+ + System.getProperty("java.library.path"));
+ throw ule;
+ }
+ }
+
+ native static int check();
+
+ public static void main(String args[]) {
+ int status = check();
+ if (status != 0) {
+ throw new RuntimeException("Non-zero status returned from the agent: " + status);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/jvmti/GetNamedModule/libGetNamedModuleTest.c Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.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
+
+#define TranslateError(err) "JVMTI error"
+
+#define PASSED 0
+#define FAILED 2
+
+static const char *EXC_CNAME = "java/lang/Exception";
+static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
+
+static jvmtiEnv *jvmti = NULL;
+static jint result = PASSED;
+static jboolean printdump = JNI_FALSE;
+
+static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
+
+JNIEXPORT
+jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+ return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+ return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT
+jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+ return JNI_VERSION_1_8;
+}
+
+static
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+ jint res;
+
+ if (options != NULL && strcmp(options, "printdump") == 0) {
+ printdump = JNI_TRUE;
+ }
+
+ res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
+ JVMTI_VERSION_9);
+ if (res != JNI_OK || jvmti == NULL) {
+ printf(" Error: wrong result of a valid call to GetEnv!\n");
+ return JNI_ERR;
+ }
+
+ return JNI_OK;
+}
+
+static
+jint throw_exc(JNIEnv *env, char *msg) {
+ jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
+
+ if (exc_class == NULL) {
+ printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
+ return -1;
+ }
+ return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
+}
+
+static
+jobject get_class_loader(jclass cls) {
+ jvmtiError err = JVMTI_ERROR_NONE;
+ jobject loader = NULL;
+
+ if (printdump == JNI_TRUE) {
+ printf(">>> getting class loader ...\n");
+ }
+ err = (*jvmti)->GetClassLoader(jvmti, cls, &loader);
+ if (err != JVMTI_ERROR_NONE) {
+ printf(" Error in GetClassLoader: %s (%d)\n", TranslateError(err), err);
+ }
+ return loader;
+}
+
+static
+jclass jlrM(JNIEnv *env) {
+ jclass cls = NULL;
+
+ cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
+ if (cls == NULL) {
+ printf(" Error in JNI FindClass: %s\n", MOD_CNAME);
+ }
+ return cls;
+}
+
+jmethodID
+get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
+ jmethodID method = NULL;
+
+ method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
+ if (method == NULL) {
+ printf(" Error in JNI GetMethodID %s with signature %s", name, sig);
+ }
+ return method;
+}
+
+static
+jobject get_module_loader(JNIEnv *env, jobject module) {
+ static jmethodID cl_method = NULL;
+ jobject loader = NULL;
+
+ if (cl_method == NULL) {
+ cl_method = get_method(env, jlrM(env), "getClassLoader", "()Ljava/lang/ClassLoader;");
+ }
+ loader = (jobject)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), cl_method);
+ return loader;
+}
+
+static
+const char* get_module_name(JNIEnv *env, jobject module) {
+ static jmethodID method = NULL;
+ jobject loader = NULL;
+ jstring jstr = NULL;
+ const char *name = NULL;
+ const char *nstr = NULL;
+
+ if (method == NULL) {
+ method = get_method(env, jlrM(env), "getName", "()Ljava/lang/String;");
+ }
+ jstr = (jstring)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), method);
+ if (jstr != NULL) {
+ name = JNI_ENV_PTR(env)->GetStringUTFChars(JNI_ENV_ARG(env, jstr), NULL);
+ }
+ loader = get_module_loader(env, module);
+ nstr = (name == NULL) ? "<UNNAMED>" : name;
+ printf(" loader: %p, module: %p, name: %s\n", loader, module, nstr);
+ return name;
+}
+
+static
+jvmtiError get_module(JNIEnv *env,
+ jobject loader,
+ const char* pkg_name,
+ jobject* module_ptr,
+ const char** mod_name_ptr) {
+ jvmtiError err = JVMTI_ERROR_NONE;
+ const char* name = (pkg_name == NULL) ? "<NULL>" : pkg_name;
+
+ printf(">>> getting module by loader %p and package \"%s\"\n", loader, name);
+ *mod_name_ptr = NULL;
+ err = (*jvmti)->GetNamedModule(jvmti, loader, pkg_name, module_ptr);
+ if (err != JVMTI_ERROR_NONE) {
+ printf(" Error in GetNamedModule for package \"%s\": %s (%d)\n",
+ pkg_name, TranslateError(err), err);
+ return err;
+ }
+ printf(" returned module: %p\n", *module_ptr);
+ if (*module_ptr == NULL) { // named module was not found
+ return err;
+ }
+ *mod_name_ptr = get_module_name(env, *module_ptr);
+ return err;
+}
+
+static
+jint get_all_modules(JNIEnv *env) {
+ jvmtiError err;
+ jint cnt = -1;
+ jint idx = 0;
+ jobject* modules;
+
+ printf(">>> Inspecting modules with GetAllModules\n");
+ err = (*jvmti)->GetAllModules(jvmti, &cnt, &modules);
+ if (err != JVMTI_ERROR_NONE) {
+ printf("Error in GetAllModules: %d\n", err);
+ return -1;
+ }
+ for (idx = 0; idx < cnt; ++idx) {
+ get_module_name(env, modules[idx]);
+ }
+ return cnt;
+}
+
+static
+jint check_bad_loader(JNIEnv *env, jobject loader) {
+ jvmtiError err = JVMTI_ERROR_NONE;
+ jobject module = NULL;
+ const char* mod_name = NULL;
+
+ err = get_module(env, loader, "", &module, &mod_name);
+ if (err != JVMTI_ERROR_ILLEGAL_ARGUMENT) {
+ return FAILED;
+ }
+ printf(" got expected JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader\n");
+ return PASSED;
+}
+
+static
+jint check_system_loader(JNIEnv *env, jobject loader) {
+ jvmtiError err = JVMTI_ERROR_NONE;
+ jobject module = NULL;
+ const char* exp_name = NULL;
+ const char* mod_name = NULL;
+
+ // NULL pointer for package name
+ err = get_module(env, loader, NULL, &module, &mod_name);
+ if (err != JVMTI_ERROR_NULL_POINTER) {
+ throw_exc(env, "check #SN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
+ return FAILED;
+ }
+
+ // NULL pointer for module_ptr
+ err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
+ if (err != JVMTI_ERROR_NULL_POINTER) {
+ throw_exc(env, "check #SN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
+ return FAILED;
+ }
+
+ // Unnamed/default package ""
+ err = get_module(env, loader, "", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #S1: failed to return JVMTI_ERROR_NONE for default package");
+ return FAILED;
+ }
+ if (module != NULL || mod_name != NULL) {
+ throw_exc(env, "check #S2: failed to return NULL-module for default package");
+ return FAILED;
+ }
+
+ // Test package: MyPackage
+ err = get_module(env, loader, "MyPackage", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #S3: failed to return JVMTI_ERROR_NONE for MyPackage");
+ return FAILED;
+ }
+ if (module != NULL || mod_name != NULL) {
+ throw_exc(env, "check #S4: failed to return NULL-module for MyPackage");
+ return FAILED;
+ }
+
+ // Package: com/sun/jdi
+ exp_name = "jdk.jdi";
+ err = get_module(env, loader, "com/sun/jdi", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #S5: failed to return JVMTI_ERROR_NONE for test package");
+ return FAILED;
+ }
+ if (module == NULL || mod_name == NULL) {
+ throw_exc(env, "check #S6: failed to return named module for com/sun/jdi package");
+ return FAILED;
+ }
+ if (strcmp(mod_name, exp_name) != 0) {
+ printf("check #S7: failed to return right module, expected: %s, returned: %s\n",
+ exp_name, mod_name);
+ throw_exc(env, "check #S7: failed to return jdk.jdi module for com/sun/jdi package");
+ return FAILED;
+ }
+
+ // Non-existing package: "bad/package/name"
+ err = get_module(env, loader, "bad/package/name", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #S8: failed to return JVMTI_ERROR_NONE for bad package");
+ return FAILED;
+ }
+ if (module != NULL || mod_name != NULL) {
+ throw_exc(env, "check #S9: failed to return NULL-module for bad package");
+ return FAILED;
+ }
+ return PASSED;
+}
+
+static
+jint check_bootstrap_loader(JNIEnv *env, jobject loader) {
+ jvmtiError err = JVMTI_ERROR_NONE;
+ jobject module = NULL;
+ const char* exp_name = NULL;
+ const char* mod_name = NULL;
+
+ // NULL pointer for package name
+ err = get_module(env, loader, NULL, &module, &mod_name);
+ if (err != JVMTI_ERROR_NULL_POINTER) {
+ throw_exc(env, "check #BN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
+ return FAILED;
+ }
+
+ // NULL pointer for module_ptr
+ err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
+ if (err != JVMTI_ERROR_NULL_POINTER) {
+ throw_exc(env, "check #BN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
+ return FAILED;
+ }
+
+ // Unnamed/default package ""
+ err = get_module(env, loader, "", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #B1: failed to return JVMTI_ERROR_NONE for default package");
+ return FAILED;
+ }
+ if (module != NULL || mod_name != NULL) {
+ throw_exc(env, "check #B2: failed to return NULL-module for default package");
+ return FAILED;
+ }
+
+ // Normal package from java.base module: "java/lang"
+ exp_name = "java.base";
+ err = get_module(env, loader, "java/lang", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #B3: failed to return JVMTI_ERROR_NONE for java/lang package");
+ return FAILED;
+ }
+ if (module == NULL || mod_name == NULL) {
+ throw_exc(env, "check #B4: failed to return named module for java/lang package");
+ return FAILED;
+ }
+ if (strcmp(exp_name, mod_name) != 0) {
+ printf("check #B5: failed to return right module, expected: %s, returned: %s\n",
+ exp_name, mod_name);
+ throw_exc(env, "check #B5: failed to return expected module for java/lang package");
+ return FAILED;
+ }
+
+ // Non-existing package: "bad/package/name"
+ err = get_module(env, loader, "bad/package/name", &module, &mod_name);
+ if (err != JVMTI_ERROR_NONE) {
+ throw_exc(env, "check #B6: failed to return JVMTI_ERROR_NONE for bad package");
+ return FAILED;
+ }
+ if (module != NULL || mod_name != NULL) {
+ throw_exc(env, "check #B7: failed to return NULL-module for bad package");
+ return FAILED;
+ }
+ return PASSED;
+}
+
+JNIEXPORT jint JNICALL
+Java_MyPackage_GetNamedModuleTest_check(JNIEnv *env, jclass cls) {
+ jobject loader = NULL;
+
+ if (jvmti == NULL) {
+ throw_exc(env, "JVMTI client was not properly loaded!\n");
+ return FAILED;
+ }
+
+ get_all_modules(env);
+
+ printf("\n*** Check for bad ClassLoader ***\n\n");
+ result = check_bad_loader(env, (jobject)cls);
+ if (result != PASSED) {
+ throw_exc(env, "check #L1: failed to return JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader");
+ return result;
+ }
+
+ loader = get_class_loader(cls);
+ if (loader == NULL) {
+ throw_exc(env, "check #L2: failed to return non-NULL loader for valid test class");
+ return FAILED;
+ }
+
+ printf("\n*** Checks for System ClassLoader ***\n\n");
+ result = check_system_loader(env, loader);
+ if (result != PASSED) {
+ return result;
+ }
+
+ printf("\n*** Checks for Bootstrap ClassLoader ***\n\n");
+ result = check_bootstrap_loader(env, NULL);
+
+ return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/hotspot/test/serviceability/sa/TestClassLoaderStats.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java Wed Jul 27 13:33:55 2016 +0000
@@ -32,6 +32,9 @@
/*
* @test
+ * @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
+ * quarantine it on that platform:
+ * @requires os.family != "mac"
* @modules java.base/jdk.internal.misc
* @library /test/lib/share/classes
* @library /testlibrary
--- a/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jul 27 13:33:55 2016 +0000
@@ -32,6 +32,9 @@
/*
* @test
+ * @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
+ * quarantine it on that platform:
+ * @requires os.family != "mac"
* @modules java.base/jdk.internal.misc
* @library /test/lib/share/classes
* @library /testlibrary
--- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -43,6 +43,9 @@
* @bug 6313383
* @key regression
* @summary Regression test for hprof export issue due to large heaps (>2G)
+ * Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
+ * it on that platform:
+ * @requires os.family != "mac"
* @library /testlibrary
* @modules java.base/jdk.internal.misc
* java.compiler
--- a/jaxp/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -370,3 +370,4 @@
493eb91ec32a6dea7604cfbd86c10045ad9af15b jdk-9+125
15722f71281f034bc696d8b96136da2ef34da44f jdk-9+126
bdc3c0b737efbf899709eb3121ce760dcfb51151 jdk-9+127
+8a7681a9d70640ac7fbf05c28f53c1d51d8d00a1 jdk-9+128
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/XalanConstants.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/XalanConstants.java Wed Jul 27 13:33:55 2016 +0000
@@ -80,6 +80,14 @@
*/
public static final String JDK_GENERAL_ENTITY_SIZE_LIMIT =
ORACLE_JAXP_PROPERTY_PREFIX + "maxGeneralEntitySizeLimit";
+
+ /**
+ * JDK node count limit in entities that limits the total number of nodes
+ * in all of entity references.
+ */
+ public static final String JDK_ENTITY_REPLACEMENT_LIMIT =
+ ORACLE_JAXP_PROPERTY_PREFIX + "entityReplacementLimit";
+
/**
* JDK maximum parameter entity size limit
*/
@@ -136,6 +144,13 @@
* JDK maximum general entity size limit
*/
public static final String SP_GENERAL_ENTITY_SIZE_LIMIT = "jdk.xml.maxGeneralEntitySizeLimit";
+
+ /**
+ * JDK node count limit in entities that limits the total number of nodes
+ * in all of entity references.
+ */
+ public static final String SP_ENTITY_REPLACEMENT_LIMIT = "jdk.xml.entityReplacementLimit";
+
/**
* JDK maximum parameter entity size limit
*/
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/utils/XMLSecurityManager.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -82,7 +82,9 @@
MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit", XalanConstants.JDK_MAX_ELEMENT_DEPTH,
XalanConstants.SP_MAX_ELEMENT_DEPTH, 0, 0),
MAX_NAME_LIMIT("MaxXMLNameLimit", XalanConstants.JDK_XML_NAME_LIMIT,
- XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000);
+ XalanConstants.SP_XML_NAME_LIMIT, 1000, 1000),
+ ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit", XalanConstants.JDK_ENTITY_REPLACEMENT_LIMIT,
+ XalanConstants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000);
final String key;
final String apiProperty;
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,15 +1,15 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright 2001-2004 The Apache Software Foundation.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -98,6 +98,10 @@
public static final int ACC_STATIC
= com.sun.org.apache.bcel.internal.Constants.ACC_STATIC;
+ public static final String MODULE_SIG
+ = "Ljava/lang/reflect/Module;";
+ public static final String CLASS_SIG
+ = "Ljava/lang/Class;";
public static final String STRING_SIG
= "Ljava/lang/String;";
public static final String STRING_BUFFER_SIG
@@ -246,8 +250,12 @@
= "com.sun.org.apache.xalan.internal.xsltc.DOM";
public static final String DOM_IMPL
= "com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl";
- public static final String SAX_IMPL
+ public static final String SAX_IMPL
= "com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl";
+ public static final String CLASS_CLASS
+ = "java.lang.Class";
+ public static final String MODULE_CLASS
+ = "java.lang.reflect.Module";
public static final String STRING_CLASS
= "java.lang.String";
public static final String OBJECT_CLASS
@@ -293,7 +301,7 @@
= "()D";
public static final String DOM_PNAME
- = "dom";
+ = "dom";
public static final String NODE_PNAME
= "node";
public static final String TRANSLET_OUTPUT_PNAME
@@ -335,6 +343,19 @@
= "setStartNode";
public static final String RESET
= "reset";
+ public static final String GET_MODULE
+ = "getModule";
+ public static final String FOR_NAME
+ = "forName";
+ public static final String ADD_READS
+ = "addReads";
+
+ public static final String GET_MODULE_SIG
+ = "()" + MODULE_SIG;
+ public static final String FOR_NAME_SIG
+ = "(" + STRING_SIG + ")" + CLASS_SIG;
+ public static final String ADD_READS_SIG
+ = "(" + MODULE_SIG + ")" + MODULE_SIG;
public static final String ATTR_SET_SIG
= "(" + DOM_INTF_SIG + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + "I)V";
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -17,9 +17,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
- * $Id: FunctionCall.java,v 1.2.4.1 2005/09/12 10:31:32 pvedula Exp $
- */
package com.sun.org.apache.xalan.internal.xsltc.compiler;
@@ -32,6 +29,7 @@
import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
+import com.sun.org.apache.bcel.internal.generic.LDC;
import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
import com.sun.org.apache.bcel.internal.generic.NEW;
import com.sun.org.apache.bcel.internal.generic.PUSH;
@@ -792,6 +790,11 @@
final String clazz =
_chosenConstructor.getDeclaringClass().getName();
+
+ // Generate call to Module.addReads:
+ // <TransletClass>.class.getModule().addReads(
+ generateAddReads(classGen, methodGen, clazz);
+
Class[] paramTypes = _chosenConstructor.getParameterTypes();
LocalVariableGen[] paramTemp = new LocalVariableGen[n];
@@ -855,6 +858,12 @@
final String clazz = _chosenMethod.getDeclaringClass().getName();
Class[] paramTypes = _chosenMethod.getParameterTypes();
+
+ // Generate call to Module.addReads:
+ // <TransletClass>.class.getModule().addReads(
+ // Class.forName(<clazz>).getModule());
+ generateAddReads(classGen, methodGen, clazz);
+
// Push "this" if it is an instance method
if (_thisArgument != null) {
_thisArgument.translate(classGen, methodGen);
@@ -896,6 +905,41 @@
}
}
+ private void generateAddReads(ClassGenerator classGen, MethodGenerator methodGen,
+ String clazz) {
+ final ConstantPoolGen cpg = classGen.getConstantPool();
+ final InstructionList il = methodGen.getInstructionList();
+
+ // Generate call to Module.addReads:
+ // <TransletClass>.class.getModule().addReads(
+ // Class.forName(<clazz>).getModule());
+ // Class.forName may throw ClassNotFoundException.
+ // This is OK as it will caught higher up the stack in
+ // TransformerImpl.transform() and wrapped into a
+ // TransformerException.
+ methodGen.markChunkStart();
+
+ int index = cpg.addMethodref(CLASS_CLASS,
+ GET_MODULE,
+ GET_MODULE_SIG);
+ int index2 = cpg.addMethodref(CLASS_CLASS,
+ FOR_NAME,
+ FOR_NAME_SIG);
+ il.append(new LDC(cpg.addString(classGen.getClassName())));
+ il.append(new INVOKESTATIC(index2));
+ il.append(new INVOKEVIRTUAL(index));
+ il.append(new LDC(cpg.addString(clazz)));
+ il.append(new INVOKESTATIC(index2));
+ il.append(new INVOKEVIRTUAL(index));
+ index = cpg.addMethodref(MODULE_CLASS,
+ ADD_READS,
+ ADD_READS_SIG);
+ il.append(new INVOKEVIRTUAL(index));
+ il.append(InstructionConstants.POP);
+
+ methodGen.markChunkEnd();
+ }
+
@Override
public String toString() {
return "funcall(" + _fname + ", " + _arguments + ')';
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -58,7 +58,6 @@
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.URIResolver;
-import jdk.internal.module.Modules;
/**
* @author Morten Jorgensen
@@ -486,10 +485,6 @@
thisModule.addExports(p, m);
});
- // For now, the module reads all unnnamed modules. This will be changed once
- // the XSLT compiler is updated to generate code to invoke addReads.
- Modules.addReadsAllUnnamed(m);
-
// java.xml needs to instanitate the translet class
thisModule.addReads(m);
@@ -513,7 +508,7 @@
}
catch (ClassFormatError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
- throw new TransformerConfigurationException(err.toString());
+ throw new TransformerConfigurationException(err.toString(), e);
}
catch (LinkageError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/Constants.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -239,6 +239,14 @@
*/
public static final String JDK_GENERAL_ENTITY_SIZE_LIMIT =
ORACLE_JAXP_PROPERTY_PREFIX + "maxGeneralEntitySizeLimit";
+
+ /**
+ * JDK node count limit in entities that limits the total number of nodes
+ * in all of entity references.
+ */
+ public static final String JDK_ENTITY_REPLACEMENT_LIMIT =
+ ORACLE_JAXP_PROPERTY_PREFIX + "entityReplacementLimit";
+
/**
* JDK maximum parameter entity size limit
*/
@@ -292,6 +300,13 @@
* JDK maximum general entity size limit
*/
public static final String SP_GENERAL_ENTITY_SIZE_LIMIT = "jdk.xml.maxGeneralEntitySizeLimit";
+
+ /**
+ * JDK node count limit in entities that limits the total number of nodes
+ * in all of entity references.
+ */
+ public static final String SP_ENTITY_REPLACEMENT_LIMIT = "jdk.xml.entityReplacementLimit";
+
/**
* JDK maximum parameter entity size limit
*/
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DTDScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,62 +1,21 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2004 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.apache.org. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.sun.org.apache.xerces.internal.impl;
@@ -146,7 +105,7 @@
protected boolean scanPubidLiteral(XMLString literal)
throws IOException, XNIException
{
- int quote = fEntityScanner.scanChar();
+ int quote = fEntityScanner.scanChar(null);
if (quote != '\'' && quote != '"') {
reportFatalError("QuoteRequiredInPublicID", null);
return false;
@@ -157,7 +116,7 @@
boolean skipSpace = true;
boolean dataok = true;
while (true) {
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
// REVISIT: it could really only be \n or 0x20; all else is normalized, no? - neilg
if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
if (!skipSpace) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11DocumentScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,62 +1,21 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2004 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, International
- * Business Machines, Inc., http://www.apache.org. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.sun.org.apache.xerces.internal.impl;
@@ -134,7 +93,7 @@
// happens when there is the character reference
// but scanContent doesn't do entity expansions...
// is this *really* necessary??? - NG
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
content.append((char)c);
c = -1;
}
@@ -143,7 +102,7 @@
} */
if (c == ']') {
- content.append((char)fEntityScanner.scanChar());
+ content.append((char)fEntityScanner.scanChar(null));
// remember where we are in case we get an endEntity before we
// could flush the buffer out - this happens when we're parsing an
// entity which ends with a ]
@@ -152,12 +111,12 @@
// We work on a single character basis to handle cases such as:
// ']]]>' which we might otherwise miss.
//
- if (fEntityScanner.skipChar(']')) {
+ if (fEntityScanner.skipChar(']', null)) {
content.append(']');
- while (fEntityScanner.skipChar(']')) {
+ while (fEntityScanner.skipChar(']', null)) {
content.append(']');
}
- if (fEntityScanner.skipChar('>')) {
+ if (fEntityScanner.skipChar('>', null)) {
reportFatalError("CDEndInContent", null);
}
}
@@ -184,6 +143,7 @@
* @param checkEntities true if undeclared entities should be reported as VC violation,
* false if undeclared entities should be reported as WFC violation.
* @param eleName The name of element to which this attribute belongs.
+ * @param isNSURI The flag indicating whether the content is a namespace URI
*
* @return true if the non-normalized and normalized value are the same
*
@@ -193,7 +153,7 @@
protected boolean scanAttributeValue(XMLString value,
XMLString nonNormalizedValue,
String atName,
- boolean checkEntities,String eleName)
+ boolean checkEntities,String eleName, boolean isNSURI)
throws IOException, XNIException
{
// quote
@@ -202,10 +162,10 @@
reportFatalError("OpenQuoteExpected", new Object[]{eleName,atName});
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.ATTRIBUTE);
int entityDepth = fEntityDepth;
- int c = fEntityScanner.scanLiteral(quote, value);
+ int c = fEntityScanner.scanLiteral(quote, value, isNSURI);
if (DEBUG_ATTR_NORMALIZATION) {
System.out.println("** scanLiteral -> \""
+ value.toString() + "\"");
@@ -215,7 +175,7 @@
if (c == quote && (fromIndex = isUnchangedByNormalization(value)) == -1) {
/** Both the non-normalized and normalized attribute values are equal. **/
nonNormalizedValue.setValues(value);
- int cquote = fEntityScanner.scanChar();
+ int cquote = fEntityScanner.scanChar(NameType.ATTRIBUTE);
if (cquote != quote) {
reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName});
}
@@ -238,11 +198,11 @@
+ fStringBuffer.toString() + "\"");
}
if (c == '&') {
- fEntityScanner.skipChar('&');
+ fEntityScanner.skipChar('&', NameType.REFERENCE);
if (entityDepth == fEntityDepth) {
fStringBuffer2.append('&');
}
- if (fEntityScanner.skipChar('#')) {
+ if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
if (entityDepth == fEntityDepth) {
fStringBuffer2.append('#');
}
@@ -256,59 +216,22 @@
}
}
else {
- String entityName = fEntityScanner.scanName();
+ String entityName = fEntityScanner.scanName(NameType.REFERENCE);
if (entityName == null) {
reportFatalError("NameRequiredInReference", null);
}
else if (entityDepth == fEntityDepth) {
fStringBuffer2.append(entityName);
}
- if (!fEntityScanner.skipChar(';')) {
+ if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInReference",
new Object []{entityName});
}
else if (entityDepth == fEntityDepth) {
fStringBuffer2.append(';');
}
- if (entityName == fAmpSymbol) {
- fStringBuffer.append('&');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value5: \""
- + fStringBuffer.toString()
- + "\"");
- }
- }
- else if (entityName == fAposSymbol) {
- fStringBuffer.append('\'');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value7: \""
- + fStringBuffer.toString()
- + "\"");
- }
- }
- else if (entityName == fLtSymbol) {
- fStringBuffer.append('<');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value9: \""
- + fStringBuffer.toString()
- + "\"");
- }
- }
- else if (entityName == fGtSymbol) {
- fStringBuffer.append('>');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** valueB: \""
- + fStringBuffer.toString()
- + "\"");
- }
- }
- else if (entityName == fQuotSymbol) {
- fStringBuffer.append('"');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** valueD: \""
- + fStringBuffer.toString()
- + "\"");
- }
+ if (resolveCharacter(entityName, fStringBuffer)) {
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
}
else {
if (fEntityManager.isExternalEntity(entityName)) {
@@ -339,13 +262,13 @@
else if (c == '<') {
reportFatalError("LessthanInAttValue",
new Object[] { eleName, atName });
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
if (entityDepth == fEntityDepth) {
fStringBuffer2.append((char)c);
}
}
else if (c == '%' || c == ']') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append((char)c);
if (entityDepth == fEntityDepth) {
fStringBuffer2.append((char)c);
@@ -359,7 +282,7 @@
// XML11EntityScanner. Not sure why
// this check was originally necessary. - NG
else if (c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append(' ');
if (entityDepth == fEntityDepth) {
fStringBuffer2.append('\n');
@@ -382,12 +305,12 @@
else if (c != -1 && isInvalidLiteral(c)) {
reportFatalError("InvalidCharInAttValue",
new Object[] {eleName, atName, Integer.toString(c, 16)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
if (entityDepth == fEntityDepth) {
fStringBuffer2.append((char)c);
}
}
- c = fEntityScanner.scanLiteral(quote, value);
+ c = fEntityScanner.scanLiteral(quote, value, isNSURI);
if (entityDepth == fEntityDepth) {
fStringBuffer2.append(value);
}
@@ -404,7 +327,7 @@
nonNormalizedValue.setValues(fStringBuffer2);
// quote
- int cquote = fEntityScanner.scanChar();
+ int cquote = fEntityScanner.scanChar(null);
if (cquote != quote) {
reportFatalError("CloseQuoteExpected", new Object[]{eleName,atName});
}
@@ -439,7 +362,7 @@
protected boolean scanPubidLiteral(XMLString literal)
throws IOException, XNIException
{
- int quote = fEntityScanner.scanChar();
+ int quote = fEntityScanner.scanChar(null);
if (quote != '\'' && quote != '"') {
reportFatalError("QuoteRequiredInPublicID", null);
return false;
@@ -450,7 +373,7 @@
boolean skipSpace = true;
boolean dataok = true;
while (true) {
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
// REVISIT: none of these except \n and 0x20 should make it past the entity scanner
if (c == ' ' || c == '\n' || c == '\r' || c == 0x85 || c == 0x2028) {
if (!skipSpace) {
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11EntityScanner.java Wed Jul 27 13:33:55 2016 +0000
@@ -21,6 +21,7 @@
package com.sun.org.apache.xerces.internal.impl;
+import com.sun.org.apache.xerces.internal.impl.XMLScanner.NameType;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.XML11Char;
import com.sun.org.apache.xerces.internal.util.XMLChar;
@@ -92,7 +93,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanChar() throws IOException {
+ protected int scanChar(NameType nt) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -100,6 +101,7 @@
}
// scan character
+ int offset = fCurrentEntity.position;
int c = fCurrentEntity.ch[fCurrentEntity.position++];
boolean external = false;
if (c == '\n' ||
@@ -110,6 +112,7 @@
invokeListeners(1);
fCurrentEntity.ch[0] = (char)c;
load(1, false, false);
+ offset = 0;
}
if (c == '\r' && external) {
int cc = fCurrentEntity.ch[fCurrentEntity.position++];
@@ -122,6 +125,9 @@
// return character that was scanned
fCurrentEntity.columnNumber++;
+ if (!detectingVersion) {
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
+ }
return c;
} // scanChar():int
@@ -141,7 +147,7 @@
* @see com.sun.org.apache.xerces.internal.util.SymbolTable
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
*/
- public String scanNmtoken() throws IOException {
+ protected String scanNmtoken() throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
load(0, true, true);
@@ -248,6 +254,8 @@
* <strong>Note:</strong> The string returned must be a symbol. The
* SymbolTable can be used for this purpose.
*
+ * @param nt The type of the name (element or attribute)
+ *
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*
@@ -255,7 +263,7 @@
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
*/
- public String scanName() throws IOException {
+ protected String scanName(NameType nt) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
load(0, true, true);
@@ -310,23 +318,11 @@
return null;
}
+ int length = 0;
do {
ch = fCurrentEntity.ch[fCurrentEntity.position];
if (XML11Char.isXML11Name(ch)) {
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
offset = 0;
if (load(length, false, false)) {
break;
@@ -334,20 +330,7 @@
}
}
else if (XML11Char.isXML11NameHighSurrogate(ch)) {
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
offset = 0;
if (load(length, false, false)) {
--fCurrentEntity.position;
@@ -361,20 +344,7 @@
--fCurrentEntity.position;
break;
}
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
offset = 0;
if (load(length, false, false)) {
break;
@@ -387,12 +357,14 @@
}
while (true);
- int length = fCurrentEntity.position - offset;
+ length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length;
// return name
String symbol = null;
if (length > 0) {
+ checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
+ checkEntityLimit(nt, fCurrentEntity, offset, length);
symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
}
return symbol;
@@ -415,7 +387,7 @@
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCName
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NCNameStart
*/
- public String scanNCName() throws IOException {
+ protected String scanNCName() throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -571,6 +543,7 @@
* this purpose.
*
* @param qname The qualified name structure to fill.
+ * @param nt The type of the name (element or attribute)
*
* @return Returns true if a qualified name appeared immediately on
* the input and was scanned, false otherwise.
@@ -582,7 +555,7 @@
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Name
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11NameStart
*/
- public boolean scanQName(QName qname) throws IOException {
+ protected boolean scanQName(QName qname, XMLScanner.NameType nt) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -602,6 +575,7 @@
fCurrentEntity.columnNumber++;
String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 1);
qname.setValues(null, name, name, null);
+ checkEntityLimit(nt, fCurrentEntity, 0, 1);
return true;
}
}
@@ -632,6 +606,7 @@
fCurrentEntity.columnNumber += 2;
String name = fSymbolTable.addSymbol(fCurrentEntity.ch, 0, 2);
qname.setValues(null, name, name, null);
+ checkEntityLimit(nt, fCurrentEntity, 0, 2);
return true;
}
}
@@ -641,6 +616,7 @@
}
int index = -1;
+ int length = 0;
boolean sawIncompleteSurrogatePair = false;
do {
ch = fCurrentEntity.ch[fCurrentEntity.position];
@@ -653,22 +629,7 @@
//check prefix before further read
checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, index - offset);
}
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- //check localpart before loading more data
- checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length - index - 1);
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
if (index != -1) {
index = index - offset;
}
@@ -679,20 +640,7 @@
}
}
else if (XML11Char.isXML11NameHighSurrogate(ch)) {
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
if (index != -1) {
index = index - offset;
}
@@ -711,20 +659,7 @@
--fCurrentEntity.position;
break;
}
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.ch.length) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.ch.length << 1];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- }
- else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
if (index != -1) {
index = index - offset;
}
@@ -740,7 +675,7 @@
}
while (true);
- int length = fCurrentEntity.position - offset;
+ length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length;
if (length > 0) {
@@ -776,6 +711,7 @@
checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
}
qname.setValues(prefix, localpart, rawname, null);
+ checkEntityLimit(nt, fCurrentEntity, offset, length);
return true;
}
return false;
@@ -808,7 +744,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanContent(XMLString content) throws IOException {
+ protected int scanContent(XMLString content) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -826,6 +762,7 @@
int offset = fCurrentEntity.position;
int c = fCurrentEntity.ch[offset];
int newlines = 0;
+ boolean counted = false;
boolean external = fCurrentEntity.isExternal();
if (c == '\n' || ((c == '\r' || c == 0x85 || c == 0x2028) && external)) {
do {
@@ -835,11 +772,13 @@
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
if (fCurrentEntity.position == fCurrentEntity.count) {
+ checkEntityLimit(null, fCurrentEntity, offset, newlines);
offset = 0;
fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
fCurrentEntity.position = newlines;
fCurrentEntity.startPosition = newlines;
if (load(newlines, false, true)) {
+ counted = true;
break;
}
}
@@ -858,11 +797,13 @@
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
if (fCurrentEntity.position == fCurrentEntity.count) {
+ checkEntityLimit(null, fCurrentEntity, offset, newlines);
offset = 0;
fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
fCurrentEntity.position = newlines;
fCurrentEntity.startPosition = newlines;
if (load(newlines, false, true)) {
+ counted = true;
break;
}
}
@@ -877,6 +818,7 @@
}
int length = fCurrentEntity.position - offset;
if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+ checkEntityLimit(null, fCurrentEntity, offset, length);
content.setValues(fCurrentEntity.ch, offset, length);
return -1;
}
@@ -904,8 +846,8 @@
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
- if (fCurrentEntity.isGE) {
- checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+ if (!counted) {
+ checkEntityLimit(null, fCurrentEntity, offset, length);
}
content.setValues(fCurrentEntity.ch, offset, length);
@@ -945,6 +887,7 @@
* @param quote The quote character that signifies the end of the
* attribute value data.
* @param content The content structure to fill.
+ * @param isNSURI a flag indicating whether the content is a Namespace URI
*
* @return Returns the next character on the input, if known. This
* value may be -1 but this does <em>note</em> designate
@@ -953,7 +896,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanLiteral(int quote, XMLString content)
+ protected int scanLiteral(int quote, XMLString content, boolean isNSURI)
throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1051,8 +994,10 @@
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
- if (fCurrentEntity.isGE) {
- checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+
+ checkEntityLimit(null, fCurrentEntity, offset, length);
+ if (isNSURI) {
+ checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
}
content.setValues(fCurrentEntity.ch, offset, length);
@@ -1103,7 +1048,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean scanData(String delimiter, XMLStringBuffer buffer)
+ protected boolean scanData(String delimiter, XMLStringBuffer buffer)
throws IOException {
boolean done = false;
@@ -1135,6 +1080,7 @@
if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) {
// something must be wrong with the input: e.g., file ends an unterminated comment
int length = fCurrentEntity.count - fCurrentEntity.position;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, fCurrentEntity.position, length);
buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
fCurrentEntity.columnNumber += fCurrentEntity.count;
fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
@@ -1199,6 +1145,7 @@
}
int length = fCurrentEntity.position - offset;
if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
buffer.append(fCurrentEntity.ch, offset, length);
return true;
}
@@ -1237,6 +1184,7 @@
fCurrentEntity.position--;
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
buffer.append(fCurrentEntity.ch, offset, length);
return true;
}
@@ -1274,6 +1222,7 @@
fCurrentEntity.position--;
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
buffer.append(fCurrentEntity.ch, offset, length);
return true;
}
@@ -1281,6 +1230,7 @@
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
if (done) {
length -= delimLen;
}
@@ -1305,7 +1255,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean skipChar(int c) throws IOException {
+ protected boolean skipChar(int c, NameType nt) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1313,6 +1263,7 @@
}
// skip character
+ int offset = fCurrentEntity.position;
int cc = fCurrentEntity.ch[fCurrentEntity.position];
if (cc == c) {
fCurrentEntity.position++;
@@ -1323,12 +1274,14 @@
else {
fCurrentEntity.columnNumber++;
}
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
return true;
}
else if (c == '\n' && ((cc == 0x2028 || cc == 0x85) && fCurrentEntity.isExternal())) {
fCurrentEntity.position++;
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
return true;
}
else if (c == '\n' && (cc == '\r' ) && fCurrentEntity.isExternal()) {
@@ -1344,6 +1297,7 @@
}
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
return true;
}
@@ -1366,7 +1320,7 @@
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
* @see com.sun.org.apache.xerces.internal.util.XML11Char#isXML11Space
*/
- public boolean skipSpaces() throws IOException {
+ protected boolean skipSpaces() throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1386,7 +1340,7 @@
// skip spaces
int c = fCurrentEntity.ch[fCurrentEntity.position];
-
+ int offset = fCurrentEntity.position - 1;
// External -- Match: S + 0x85 + 0x2028, and perform end of line normalization
if (fCurrentEntity.isExternal()) {
if (XML11Char.isXML11Space(c)) {
@@ -1422,6 +1376,11 @@
else {
fCurrentEntity.columnNumber++;
}
+
+ //If this is a general entity, spaces within a start element should be counted
+ checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+ offset = fCurrentEntity.position;
+
// load more characters, if needed
if (!entityChanged)
fCurrentEntity.position++;
@@ -1462,6 +1421,11 @@
else {
fCurrentEntity.columnNumber++;
}
+
+ //If this is a general entity, spaces within a start element should be counted
+ checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+ offset = fCurrentEntity.position;
+
// load more characters, if needed
if (!entityChanged)
fCurrentEntity.position++;
@@ -1495,7 +1459,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean skipString(String s) throws IOException {
+ protected boolean skipString(String s) throws IOException {
// load more characters, if needed
if (fCurrentEntity.position == fCurrentEntity.count) {
@@ -1504,6 +1468,7 @@
// skip string
final int length = s.length();
+ final int beforeSkip = fCurrentEntity.position ;
for (int i = 0; i < length; i++) {
char c = fCurrentEntity.ch[fCurrentEntity.position++];
if (c != s.charAt(i)) {
@@ -1523,6 +1488,9 @@
}
}
fCurrentEntity.columnNumber += length;
+ if (!detectingVersion) {
+ checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+ }
return true;
} // skipString(String):boolean
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11NSDocumentScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XML11NSDocumentScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
@@ -135,7 +135,7 @@
if (DEBUG_START_END_ELEMENT)
System.out.println(">>> scanStartElementNS()");
// Note: namespace processing is on by default
- fEntityScanner.scanQName(fElementQName);
+ fEntityScanner.scanQName(fElementQName, NameType.ATTRIBUTE);
// REVISIT - [Q] Why do we need this local variable? -- mrglavas
String rawname = fElementQName.rawname;
if (fBindNamespaces) {
@@ -173,11 +173,11 @@
// end tag?
int c = fEntityScanner.peekChar();
if (c == '>') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
break;
} else if (c == '/') {
- fEntityScanner.scanChar();
- if (!fEntityScanner.skipChar('>')) {
+ fEntityScanner.scanChar(null);
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError(
"ElementUnterminated",
new Object[] { rawname });
@@ -345,7 +345,7 @@
protected void scanStartElementName ()
throws IOException, XNIException {
// Note: namespace processing is on by default
- fEntityScanner.scanQName(fElementQName);
+ fEntityScanner.scanQName(fElementQName, NameType.ATTRIBUTE);
// Must skip spaces here because the DTD scanner
// would consume them at the end of the external subset.
fSawSpace = fEntityScanner.skipSpaces();
@@ -395,11 +395,11 @@
// end tag?
int c = fEntityScanner.peekChar();
if (c == '>') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
break;
} else if (c == '/') {
- fEntityScanner.scanChar();
- if (!fEntityScanner.skipChar('>')) {
+ fEntityScanner.scanChar(null);
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError(
"ElementUnterminated",
new Object[] { rawname });
@@ -571,11 +571,11 @@
System.out.println(">>> scanAttribute()");
// name
- fEntityScanner.scanQName(fAttributeQName);
+ fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTE);
// equals
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('=')) {
+ if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
reportFatalError(
"EqRequiredInAttribute",
new Object[] {
@@ -614,13 +614,20 @@
//REVISIT: one more case needs to be included: external PE and standalone is no
boolean isVC = fHasExternalDTD && !fStandalone;
- // REVISIT: it seems that this function should not take attributes, and length
- scanAttributeValue(
- this.fTempString,
- fTempString2,
- fAttributeQName.rawname,
- isVC,
- fCurrentElement.rawname);
+ /**
+ * Determine whether this is a namespace declaration that will be subject
+ * to the name limit check in the scanAttributeValue operation.
+ * Namespace declaration format: xmlns="..." or xmlns:prefix="..."
+ * Note that prefix:xmlns="..." isn't a namespace.
+ */
+ String localpart = fAttributeQName.localpart;
+ String prefix = fAttributeQName.prefix != null
+ ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+ boolean isNSDecl = fBindNamespaces & (prefix == XMLSymbols.PREFIX_XMLNS ||
+ prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS);
+
+ scanAttributeValue(this.fTempString, fTempString2, fAttributeQName.rawname,
+ isVC, fCurrentElement.rawname, isNSDecl);
String value = fTempString.toString();
attributes.setValue(attrIndex, value);
attributes.setNonNormalizedValue(attrIndex, fTempString2.toString());
@@ -628,17 +635,7 @@
// record namespace declarations if any.
if (fBindNamespaces) {
-
- String localpart = fAttributeQName.localpart;
- String prefix =
- fAttributeQName.prefix != null
- ? fAttributeQName.prefix
- : XMLSymbols.EMPTY_STRING;
- // when it's of form xmlns="..." or xmlns:prefix="...",
- // it's a namespace declaration. but prefix:xmlns="..." isn't.
- if (prefix == XMLSymbols.PREFIX_XMLNS
- || prefix == XMLSymbols.EMPTY_STRING
- && localpart == XMLSymbols.PREFIX_XMLNS) {
+ if (isNSDecl) {
if (value.length() > fXMLNameLimit) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
"MaxXMLNameLimit",
@@ -758,7 +755,7 @@
// end
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
reportFatalError(
"ETagUnterminated",
new Object[] { endElementName.rawname });
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDTDScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -21,10 +21,7 @@
package com.sun.org.apache.xerces.internal.impl;
-import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
-import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
-import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
import com.sun.org.apache.xerces.internal.util.XMLChar;
@@ -367,6 +364,7 @@
// we're done, set starting state for external subset
setScannerState(SCANNER_STATE_TEXT_DECL);
// we're done scanning DTD.
+ fLimitAnalyzer.reset(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT);
fLimitAnalyzer.reset(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT);
return false;
}
@@ -399,7 +397,7 @@
if (isInvalidLiteral(c)) {
reportFatalError("InvalidCharInDTD",
new Object[] { Integer.toHexString(c) });
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
}
}
@@ -767,7 +765,7 @@
fStringBuffer.clear();
fStringBuffer.append("xml");
while (isValidNameChar(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
+ fStringBuffer.append((char)fEntityScanner.scanChar(null));
}
String target =
fSymbolTable.addSymbol(fStringBuffer.ch,
@@ -867,7 +865,7 @@
}
// element name
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
if (name == null) {
reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL",
null);
@@ -900,7 +898,7 @@
}
}
else {
- if (!fEntityScanner.skipChar('(')) {
+ if (!fEntityScanner.skipChar('(', null)) {
reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
new Object[]{name});
}
@@ -930,7 +928,7 @@
fReportEntity = false;
skipSeparator(false, !scanningInternalSubset());
// end
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("ElementDeclUnterminated", new Object[]{name});
}
fReportEntity = true;
@@ -967,7 +965,7 @@
fDTDContentModelHandler.pcdata(null);
}
skipSeparator(false, !scanningInternalSubset());
- while (fEntityScanner.skipChar('|')) {
+ while (fEntityScanner.skipChar('|', null)) {
fStringBuffer.append('|');
// call handler
if (fDTDContentModelHandler != null) {
@@ -976,7 +974,7 @@
}
skipSeparator(false, !scanningInternalSubset());
- childName = fEntityScanner.scanName();
+ childName = fEntityScanner.scanName(NameType.ENTITY);
if (childName == null) {
reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
new Object[]{elName});
@@ -1005,7 +1003,7 @@
reportFatalError("MixedContentUnterminated",
new Object[]{elName});
}
- else if (fEntityScanner.skipChar(')')){
+ else if (fEntityScanner.skipChar(')', null)){
fStringBuffer.append(')');
// call handler
if (fDTDContentModelHandler != null) {
@@ -1043,7 +1041,7 @@
int currentOp = 0;
int c;
while (true) {
- if (fEntityScanner.skipChar('(')) {
+ if (fEntityScanner.skipChar('(', null)) {
fMarkUpDepth++;
fStringBuffer.append('(');
// call handler
@@ -1057,7 +1055,7 @@
continue;
}
skipSeparator(false, !scanningInternalSubset());
- String childName = fEntityScanner.scanName();
+ String childName = fEntityScanner.scanName(NameType.ELEMENTSTART);
if (childName == null) {
reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
new Object[]{elName});
@@ -1084,7 +1082,7 @@
}
fDTDContentModelHandler.occurrence(oc, null);
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append((char)c);
}
while (true) {
@@ -1097,7 +1095,7 @@
fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
null);
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append(',');
break;
}
@@ -1108,7 +1106,7 @@
fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE,
null);
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append('|');
break;
}
@@ -1154,7 +1152,7 @@
}
else {
// no occurrence specified
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fStringBuffer.append(')');
}
fMarkUpDepth--;
@@ -1186,7 +1184,7 @@
}
// element name
- String elName = fEntityScanner.scanName();
+ String elName = fEntityScanner.scanName(NameType.ELEMENTSTART);
if (elName == null) {
reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL",
null);
@@ -1200,7 +1198,7 @@
// spaces
if (!skipSeparator(true, !scanningInternalSubset())) {
// no space, is it the end yet?
- if (fEntityScanner.skipChar('>')) {
+ if (fEntityScanner.skipChar('>', null)) {
// yes, stop here
// call handler
if (fDTDHandler != null) {
@@ -1216,8 +1214,8 @@
}
// definitions
- while (!fEntityScanner.skipChar('>')) {
- String name = fEntityScanner.scanName();
+ while (!fEntityScanner.skipChar('>', null)) {
+ String name = fEntityScanner.scanName(NameType.ATTRIBUTE);
if (name == null) {
reportFatalError("AttNameRequiredInAttDef",
new Object[]{elName});
@@ -1353,7 +1351,7 @@
new Object[]{elName, atName});
}
// open paren
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
if (c != '(') {
reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
new Object[]{elName, atName});
@@ -1361,7 +1359,7 @@
fMarkUpDepth++;
do {
skipSeparator(false, !scanningInternalSubset());
- String aName = fEntityScanner.scanName();
+ String aName = fEntityScanner.scanName(NameType.ATTRIBUTE);
if (aName == null) {
reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
new Object[]{elName, atName});
@@ -1369,7 +1367,7 @@
ensureEnumerationSize(fEnumerationCount + 1);
fEnumeration[fEnumerationCount++] = aName;
skipSeparator(false, !scanningInternalSubset());
- c = fEntityScanner.scanChar();
+ c = fEntityScanner.scanChar(null);
} while (c == '|');
if (c != ')') {
reportFatalError("NotationTypeUnterminated",
@@ -1380,7 +1378,7 @@
else { // Enumeration
type = "ENUMERATION";
// open paren
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
if (c != '(') {
// "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
reportFatalError("AttTypeRequiredInAttDef",
@@ -1397,7 +1395,7 @@
ensureEnumerationSize(fEnumerationCount + 1);
fEnumeration[fEnumerationCount++] = token;
skipSeparator(false, !scanningInternalSubset());
- c = fEntityScanner.scanChar();
+ c = fEntityScanner.scanChar(null);
} while (c == '|');
if (c != ')') {
reportFatalError("EnumerationUnterminated",
@@ -1447,7 +1445,7 @@
// AttValue
boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ;
scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName,
- fAttributes, 0, isVC, elName);
+ fAttributes, 0, isVC, elName, false);
}
return defaultType;
@@ -1475,7 +1473,7 @@
boolean sawPERef = false;
fReportEntity = false;
if (fEntityScanner.skipSpaces()) {
- if (!fEntityScanner.skipChar('%')) {
+ if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) {
isPEDecl = false; // <!ENTITY x "x">
}
else if (skipSeparator(true, !scanningInternalSubset())) {
@@ -1496,7 +1494,7 @@
sawPERef = true;
}
}
- else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) {
+ else if (scanningInternalSubset() || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
// <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
null);
@@ -1513,11 +1511,11 @@
}
if (sawPERef) {
while (true) {
- String peName = fEntityScanner.scanName();
+ String peName = fEntityScanner.scanName(NameType.REFERENCE);
if (peName == null) {
reportFatalError("NameRequiredInPEReference", null);
}
- else if (!fEntityScanner.skipChar(';')) {
+ else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInPEReference",
new Object[]{peName});
}
@@ -1525,20 +1523,20 @@
startPE(peName, false);
}
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
+ if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
break;
if (!isPEDecl) {
if (skipSeparator(true, !scanningInternalSubset())) {
isPEDecl = true;
break;
}
- isPEDecl = fEntityScanner.skipChar('%');
+ isPEDecl = fEntityScanner.skipChar('%', NameType.REFERENCE);
}
}
}
// name
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ENTITY);
if (name == null) {
reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null);
}
@@ -1573,7 +1571,7 @@
reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
new Object[]{name});
}
- notation = fEntityScanner.scanName();
+ notation = fEntityScanner.scanName(NameType.NOTATION);
if (notation == null) {
reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
new Object[]{name});
@@ -1595,7 +1593,7 @@
skipSeparator(false, !scanningInternalSubset());
// end
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("EntityDeclUnterminated", new Object[]{name});
}
fMarkUpDepth--;
@@ -1650,7 +1648,7 @@
protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value,
XMLString nonNormalizedValue)
throws IOException, XNIException {
- int quote = fEntityScanner.scanChar();
+ int quote = fEntityScanner.scanChar(null);
if (quote != '\'' && quote != '"') {
reportFatalError("OpenQuoteMissingInDecl", null);
}
@@ -1665,23 +1663,24 @@
}
fLimitAnalyzer.startEntity(entityName);
- if (fEntityScanner.scanLiteral(quote, fString) != quote) {
+ if (fEntityScanner.scanLiteral(quote, fString, false) != quote) {
fStringBuffer.clear();
fStringBuffer2.clear();
+ int offset;
do {
- checkEntityLimit(isPEDecl, entityName, fString.length + countChar);
countChar = 0;
+ offset = fStringBuffer.length;
fStringBuffer.append(fString);
fStringBuffer2.append(fString);
- if (fEntityScanner.skipChar('&')) {
- if (fEntityScanner.skipChar('#')) {
+ if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
+ if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
fStringBuffer2.append("&#");
scanCharReferenceValue(fStringBuffer, fStringBuffer2);
}
else {
fStringBuffer.append('&');
fStringBuffer2.append('&');
- String eName = fEntityScanner.scanName();
+ String eName = fEntityScanner.scanName(NameType.REFERENCE);
if (eName == null) {
reportFatalError("NameRequiredInReference",
null);
@@ -1690,7 +1689,7 @@
fStringBuffer.append(eName);
fStringBuffer2.append(eName);
}
- if (!fEntityScanner.skipChar(';')) {
+ if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInReference",
new Object[]{eName});
}
@@ -1700,15 +1699,15 @@
}
}
}
- else if (fEntityScanner.skipChar('%')) {
+ else if (fEntityScanner.skipChar('%', NameType.REFERENCE)) {
while (true) {
fStringBuffer2.append('%');
- String peName = fEntityScanner.scanName();
+ String peName = fEntityScanner.scanName(NameType.REFERENCE);
if (peName == null) {
reportFatalError("NameRequiredInPEReference",
null);
}
- else if (!fEntityScanner.skipChar(';')) {
+ else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInPEReference",
new Object[]{peName});
}
@@ -1725,20 +1724,20 @@
// REVISIT: This will make returning the non-
// normalized value harder. -Ac
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
+ if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
break;
}
}
else {
- countChar++;
int c = fEntityScanner.peekChar();
if (XMLChar.isHighSurrogate(c)) {
+ countChar++;
scanSurrogates(fStringBuffer2);
}
else if (isInvalidLiteral(c)) {
reportFatalError("InvalidCharInLiteral",
new Object[]{Integer.toHexString(c)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
// if it's not the delimiting quote or if it is but from a
// different entity than the one this literal started from,
@@ -1746,10 +1745,12 @@
else if (c != quote || entityDepth != fEntityDepth) {
fStringBuffer.append((char)c);
fStringBuffer2.append((char)c);
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
}
- } while (fEntityScanner.scanLiteral(quote, fString) != quote);
+ checkEntityLimit(isPEDecl, entityName, fStringBuffer.length - offset + countChar);
+ } while (fEntityScanner.scanLiteral(quote, fString, false) != quote);
+ checkEntityLimit(isPEDecl, entityName, fString.length);
fStringBuffer.append(fString);
fStringBuffer2.append(fString);
literal = fStringBuffer;
@@ -1760,10 +1761,14 @@
value.setValues(literal);
nonNormalizedValue.setValues(literal2);
if (fLimitAnalyzer != null) {
- fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
+ if (isPEDecl) {
+ fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName);
+ } else {
+ fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName);
+ }
}
- if (!fEntityScanner.skipChar(quote)) {
+ if (!fEntityScanner.skipChar(quote, null)) {
reportFatalError("CloseQuoteMissingInDecl", null);
}
} // scanEntityValue(XMLString,XMLString):void
@@ -1788,7 +1793,7 @@
}
// notation name
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.NOTATION);
if (name == null) {
reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL",
null);
@@ -1815,7 +1820,7 @@
skipSeparator(false, !scanningInternalSubset());
// end
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("NotationDeclUnterminated", new Object[]{name});
}
fMarkUpDepth--;
@@ -1863,7 +1868,7 @@
XMLErrorReporter.SEVERITY_ERROR);
}
// call handler
- if (!fEntityScanner.skipChar('[')) {
+ if (!fEntityScanner.skipChar('[', null)) {
reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
}
@@ -1888,7 +1893,7 @@
fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE,
null);
}
- if (!fEntityScanner.skipChar('[')) {
+ if (!fEntityScanner.skipChar('[', null)) {
reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
}
fReportEntity = true;
@@ -1897,7 +1902,7 @@
fIgnoreConditionalBuffer.clear();
}
while (true) {
- if (fEntityScanner.skipChar('<')) {
+ if (fEntityScanner.skipChar('<', null)) {
if (fDTDHandler != null) {
fIgnoreConditionalBuffer.append('<');
}
@@ -1905,8 +1910,8 @@
// These tests are split so that we handle cases like
// '<<![' and '<!<![' which we might otherwise miss.
//
- if (fEntityScanner.skipChar('!')) {
- if(fEntityScanner.skipChar('[')) {
+ if (fEntityScanner.skipChar('!', null)) {
+ if(fEntityScanner.skipChar('[', null)) {
if (fDTDHandler != null) {
fIgnoreConditionalBuffer.append("![");
}
@@ -1918,24 +1923,24 @@
}
}
}
- else if (fEntityScanner.skipChar(']')) {
+ else if (fEntityScanner.skipChar(']', null)) {
if (fDTDHandler != null) {
fIgnoreConditionalBuffer.append(']');
}
//
// The same thing goes for ']<![' and '<]]>', etc.
//
- if (fEntityScanner.skipChar(']')) {
+ if (fEntityScanner.skipChar(']', null)) {
if (fDTDHandler != null) {
fIgnoreConditionalBuffer.append(']');
}
- while (fEntityScanner.skipChar(']')) {
+ while (fEntityScanner.skipChar(']', null)) {
/* empty loop body */
if (fDTDHandler != null) {
fIgnoreConditionalBuffer.append(']');
}
}
- if (fEntityScanner.skipChar('>')) {
+ if (fEntityScanner.skipChar('>', null)) {
if (fIncludeSectDepth-- == initialDepth) {
fMarkUpDepth--;
// call handler
@@ -1953,7 +1958,7 @@
}
}
else {
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
reportFatalError("IgnoreSectUnterminated", null);
return;
@@ -1990,16 +1995,16 @@
//System.out.println("scanDecls"+fScannerState);
while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
again = complete;
- if (fEntityScanner.skipChar('<')) {
+ if (fEntityScanner.skipChar('<', null)) {
fMarkUpDepth++;
- if (fEntityScanner.skipChar('?')) {
+ if (fEntityScanner.skipChar('?', null)) {
fStringBuffer.clear();
scanPI(fStringBuffer);
fMarkUpDepth--; // we're done with this decl
}
- else if (fEntityScanner.skipChar('!')) {
- if (fEntityScanner.skipChar('-')) {
- if (!fEntityScanner.skipChar('-')) {
+ else if (fEntityScanner.skipChar('!', null)) {
+ if (fEntityScanner.skipChar('-', null)) {
+ if (!fEntityScanner.skipChar('-', null)) {
reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
null);
} else {
@@ -2018,7 +2023,7 @@
else if (fEntityScanner.skipString("NOTATION")) {
scanNotationDecl();
}
- else if (fEntityScanner.skipChar('[') &&
+ else if (fEntityScanner.skipChar('[', null) &&
!scanningInternalSubset()) {
scanConditionalSect(fPEDepth);
}
@@ -2033,10 +2038,10 @@
reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
}
}
- else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) {
+ else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']', null)) {
// end of conditional section?
- if (!fEntityScanner.skipChar(']')
- || !fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar(']', null)
+ || !fEntityScanner.skipChar('>', null)) {
reportFatalError("IncludeSectUnterminated", null);
}
// call handler
@@ -2083,21 +2088,21 @@
throws IOException, XNIException {
int depth = fPEDepth;
boolean sawSpace = fEntityScanner.skipSpaces();
- if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
+ if (!lookForPERefs || !fEntityScanner.skipChar('%', NameType.REFERENCE)) {
return !spaceRequired || sawSpace || (depth != fPEDepth);
}
while (true) {
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ENTITY);
if (name == null) {
reportFatalError("NameRequiredInPEReference", null);
}
- else if (!fEntityScanner.skipChar(';')) {
+ else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInPEReference",
new Object[]{name});
}
startPE(name, false);
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('%'))
+ if (!fEntityScanner.skipChar('%', NameType.REFERENCE))
return true;
}
}
@@ -2181,56 +2186,6 @@
fSecurityManager = fEntityManager.fSecurityManager;
}
- /**
- * Add the count of the content buffer and check if the accumulated
- * value exceeds the limit
- * @param isPEDecl a flag to indicate whether the entity is parameter
- * @param entityName entity name
- * @param buffer content buffer
- */
- private void checkEntityLimit(boolean isPEDecl, String entityName, XMLString buffer) {
- checkEntityLimit(isPEDecl, entityName, buffer.length);
- }
-
- /**
- * Add the count and check limit
- * @param isPEDecl a flag to indicate whether the entity is parameter
- * @param entityName entity name
- * @param len length of the buffer
- */
- private void checkEntityLimit(boolean isPEDecl, String entityName, int len) {
- if (fLimitAnalyzer == null) {
- fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
- }
- if (isPEDecl) {
- fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, "%" + entityName, len);
- if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
- fSecurityManager.debugPrint(fLimitAnalyzer);
- reportFatalError("MaxEntitySizeLimit", new Object[]{"%" + entityName,
- fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
- fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
- fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)});
- }
- } else {
- fLimitAnalyzer.addValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName, len);
- if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
- fSecurityManager.debugPrint(fLimitAnalyzer);
- reportFatalError("MaxEntitySizeLimit", new Object[]{entityName,
- fLimitAnalyzer.getValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
- fSecurityManager.getLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
- fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT)});
- }
- }
- if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
- fSecurityManager.debugPrint(fLimitAnalyzer);
- reportFatalError("TotalEntitySizeLimit",
- new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
- fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
- fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)});
- }
-
- }
-
public DTDGrammar getGrammar(){
return nvGrammarInfo;
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -21,14 +21,6 @@
package com.sun.org.apache.xerces.internal.impl;
-import com.sun.xml.internal.stream.XMLBufferListener;
-import com.sun.xml.internal.stream.XMLEntityStorage;
-import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
-
-import java.io.EOFException;
-import java.io.IOException;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.events.XMLEvent;
import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
import com.sun.org.apache.xerces.internal.util.XMLAttributesIteratorImpl;
@@ -47,13 +39,18 @@
import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
import com.sun.org.apache.xerces.internal.xni.Augmentations;
-import com.sun.org.apache.xerces.internal.impl.Constants;
-import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler;
import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager.Limit;
import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
+import com.sun.xml.internal.stream.XMLBufferListener;
+import com.sun.xml.internal.stream.XMLEntityStorage;
+import com.sun.xml.internal.stream.dtd.DTDGrammarUtil;
+import java.io.EOFException;
+import java.io.IOException;
+import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.events.XMLEvent;
/**
*
@@ -454,6 +451,7 @@
//fDocumentHandler.startElement(getElementQName(),fAttributes,null);
break;
case XMLStreamConstants.CHARACTERS :
+ fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
fDocumentHandler.characters(getCharacterData(),null);
break;
case XMLStreamConstants.SPACE:
@@ -462,13 +460,15 @@
//fDocumentHandler.ignorableWhitespace(getCharacterData(), null);
break;
case XMLStreamConstants.ENTITY_REFERENCE :
+ fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
//entity reference callback are given in startEntity
break;
case XMLStreamConstants.PROCESSING_INSTRUCTION :
+ fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
fDocumentHandler.processingInstruction(getPITarget(),getPIData(),null);
break;
case XMLStreamConstants.COMMENT :
- //System.out.println(" in COMMENT of the XMLNSDocumentScannerImpl");
+ fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
fDocumentHandler.comment(getCharacterData(),null);
break;
case XMLStreamConstants.DTD :
@@ -477,6 +477,7 @@
//therefore we don't need to take care of anything here. So Just break;
break;
case XMLStreamConstants.CDATA:
+ fEntityScanner.checkNodeCount(fEntityScanner.fCurrentEntity);
fDocumentHandler.startCDATA(null);
//xxx: check if CDATA values comes from getCharacterData() function
fDocumentHandler.characters(getCharacterData(),null);
@@ -1273,9 +1274,9 @@
fElementQName = fElementStack.nextElement();
// name
if (fNamespaces) {
- fEntityScanner.scanQName(fElementQName);
+ fEntityScanner.scanQName(fElementQName, NameType.ELEMENTSTART);
} else {
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
fElementQName.setValues(null, name, name, null);
}
@@ -1376,11 +1377,11 @@
// end tag?
final int c = fEntityScanner.peekChar();
if (c == '>') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
return true;
} else if (c == '/') {
- fEntityScanner.scanChar();
- if (!fEntityScanner.skipChar('>')) {
+ fEntityScanner.scanChar(null);
+ if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
reportFatalError("ElementUnterminated",
new Object[]{fElementQName.rawname});
}
@@ -1518,15 +1519,15 @@
// name
if (fNamespaces) {
- fEntityScanner.scanQName(fAttributeQName);
+ fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTENAME);
} else {
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ATTRIBUTENAME);
fAttributeQName.setValues(null, name, name, null);
}
// equals
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('=')) {
+ if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
reportFatalError("EqRequiredInAttribute",
new Object[] {fCurrentElement.rawname, fAttributeQName.rawname});
}
@@ -1544,9 +1545,8 @@
//can safely add the attribute later..
XMLString tmpStr = getString();
- scanAttributeValue(tmpStr, fTempString2,
- fAttributeQName.rawname, attributes,
- attIndex, isVC, fCurrentElement.rawname);
+ scanAttributeValue(tmpStr, fTempString2, fAttributeQName.rawname, attributes,
+ attIndex, isVC, fCurrentElement.rawname, false);
// content
int oldLen = attributes.getLength();
@@ -1594,13 +1594,13 @@
if (c == '\r') {
// happens when there is the character reference
//xxx: We know the next chracter.. we should just skip it and add ']' directlry
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
content.append((char)c);
c = -1;
} else if (c == ']') {
//fStringBuffer.clear();
//xxx: We know the next chracter.. we should just skip it and add ']' directlry
- content.append((char)fEntityScanner.scanChar());
+ content.append((char)fEntityScanner.scanChar(null));
// remember where we are in case we get an endEntity before we
// could flush the buffer out - this happens when we're parsing an
// entity which ends with a ]
@@ -1609,12 +1609,12 @@
// We work on a single character basis to handle cases such as:
// ']]]>' which we might otherwise miss.
//
- if (fEntityScanner.skipChar(']')) {
+ if (fEntityScanner.skipChar(']', null)) {
content.append(']');
- while (fEntityScanner.skipChar(']')) {
+ while (fEntityScanner.skipChar(']', null)) {
content.append(']');
}
- if (fEntityScanner.skipChar('>')) {
+ if (fEntityScanner.skipChar('>', null)) {
reportFatalError("CDEndInContent", null);
}
}
@@ -1689,7 +1689,7 @@
} else {
reportFatalError("InvalidCharInCDSect",
new Object[]{Integer.toString(c,16)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
}
//by this time we have also read surrogate contents if any...
@@ -1751,7 +1751,7 @@
// end
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', NameType.ELEMENTEND)) {
reportFatalError("ETagUnterminated",
new Object[]{rawname});
}
@@ -1841,12 +1841,12 @@
* notification.
*/
protected void scanEntityReference(XMLStringBuffer content) throws IOException, XNIException {
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.REFERENCE);
if (name == null) {
reportFatalError("NameRequiredInReference", null);
return;
}
- if (!fEntityScanner.skipChar(';')) {
+ if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInReference", new Object []{name});
}
if (fEntityStore.isUnparsedEntity(name)) {
@@ -1943,6 +1943,7 @@
*/
private void handleCharacter(char c, String entity, XMLStringBuffer content) throws XNIException {
foundBuiltInRefs = true;
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
content.append(c);
if (fDocumentHandler != null) {
fSingleChar[0] = c;
@@ -2608,13 +2609,13 @@
switch(ch){
case '?' :{
setScannerState(SCANNER_STATE_PI);
- fEntityScanner.skipChar(ch);
+ fEntityScanner.skipChar(ch, null);
break;
}
case '!' :{
- fEntityScanner.skipChar(ch);
- if (fEntityScanner.skipChar('-')) {
- if (!fEntityScanner.skipChar('-')) {
+ fEntityScanner.skipChar(ch, null);
+ if (fEntityScanner.skipChar('-', null)) {
+ if (!fEntityScanner.skipChar('-', NameType.COMMENT)) {
reportFatalError("InvalidCommentStart",
null);
}
@@ -2629,7 +2630,7 @@
}
case '/' :{
setScannerState(SCANNER_STATE_END_ELEMENT_TAG);
- fEntityScanner.skipChar(ch);
+ fEntityScanner.skipChar(ch, NameType.ELEMENTEND);
break;
}
default :{
@@ -2641,9 +2642,9 @@
}//startOfMarkup
private void startOfContent() throws IOException {
- if (fEntityScanner.skipChar('<')) {
+ if (fEntityScanner.skipChar('<', null)) {
setScannerState(SCANNER_STATE_START_OF_MARKUP);
- } else if (fEntityScanner.skipChar('&')) {
+ } else if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
} else {
//element content is there..
@@ -2716,10 +2717,10 @@
case SCANNER_STATE_CONTENT: {
final int ch = fEntityScanner.peekChar();
if (ch == '<') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
setScannerState(SCANNER_STATE_START_OF_MARKUP);
} else if (ch == '&') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
setScannerState(SCANNER_STATE_REFERENCE) ; //XMLEvent.ENTITY_REFERENCE ); //SCANNER_STATE_REFERENCE
break;
} else {
@@ -2819,9 +2820,9 @@
if(DEBUG){
System.out.println("fTempString = " + fTempString);
}
- if(fEntityScanner.skipChar('<')){
+ if(fEntityScanner.skipChar('<', null)){
//check if we have reached end of element
- if(fEntityScanner.skipChar('/')){
+ if(fEntityScanner.skipChar('/', NameType.ELEMENTEND)){
//increase the mark up depth
fMarkupDepth++;
fLastSectionWasCharacterData = false;
@@ -2871,7 +2872,7 @@
}
// happens when there is the character reference
//xxx: We know the next chracter.. we should just skip it and add ']' directlry
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
fUsebuffer = true;
fContentBuffer.append((char)c);
c = -1 ;
@@ -2879,7 +2880,7 @@
//fStringBuffer.clear();
//xxx: We know the next chracter.. we should just skip it and add ']' directlry
fUsebuffer = true;
- fContentBuffer.append((char)fEntityScanner.scanChar());
+ fContentBuffer.append((char)fEntityScanner.scanChar(null));
// remember where we are in case we get an endEntity before we
// could flush the buffer out - this happens when we're parsing an
// entity which ends with a ]
@@ -2888,12 +2889,12 @@
// We work on a single character basis to handle cases such as:
// ']]]>' which we might otherwise miss.
//
- if (fEntityScanner.skipChar(']')) {
+ if (fEntityScanner.skipChar(']', null)) {
fContentBuffer.append(']');
- while (fEntityScanner.skipChar(']')) {
+ while (fEntityScanner.skipChar(']', null)) {
fContentBuffer.append(']');
}
- if (fEntityScanner.skipChar('>')) {
+ if (fEntityScanner.skipChar('>', null)) {
reportFatalError("CDEndInContent", null);
}
}
@@ -2906,12 +2907,12 @@
// we need not to grow the buffer only when isCoalesce() is not true;
if (c == '<') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
setScannerState(SCANNER_STATE_START_OF_MARKUP);
break;
}//xxx what should be the behavior if entity reference is present in the content ?
else if (c == '&') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
setScannerState(SCANNER_STATE_REFERENCE);
break;
}///xxx since this part is also characters, it should be merged...
@@ -2924,7 +2925,7 @@
reportFatalError("InvalidCharInContent",
new Object[] {
Integer.toString(c, 16)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
break;
}
@@ -3050,7 +3051,7 @@
}
fUsebuffer = true ;
//take care of character reference
- if (fEntityScanner.skipChar('#')) {
+ if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
scanCharReferenceValue(fContentBuffer, null);
fMarkupDepth--;
if(!fIsCoalesce){
@@ -3106,11 +3107,11 @@
if (fNamespaces) {
while (isValidNCName(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
+ fStringBuffer.append((char)fEntityScanner.scanChar(null));
}
} else {
while (isValidNameChar(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
+ fStringBuffer.append((char)fEntityScanner.scanChar(null));
}
}
String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -631,7 +631,7 @@
}
// root element name
- fDoctypeName = fEntityScanner.scanName();
+ fDoctypeName = fEntityScanner.scanName(NameType.DOCTYPE);
if (fDoctypeName == null) {
reportFatalError("MSG_ROOT_ELEMENT_TYPE_REQUIRED", null);
}
@@ -671,10 +671,10 @@
// is there an internal subset?
boolean internalSubset = true;
- if (!fEntityScanner.skipChar('[')) {
+ if (!fEntityScanner.skipChar('[', null)) {
internalSubset = false;
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
}
fMarkupDepth--;
@@ -753,7 +753,7 @@
fStringBuffer.clear();
fStringBuffer.append("xml");
while (XMLChar.isName(fEntityScanner.peekChar())) {
- fStringBuffer.append((char)fEntityScanner.scanChar());
+ fStringBuffer.append((char)fEntityScanner.scanChar(null));
}
String target = fSymbolTable.addSymbol(fStringBuffer.ch, fStringBuffer.offset, fStringBuffer.length);
//this function should fill the data.. and set the fEvent object to this event.
@@ -831,9 +831,9 @@
switch (fScannerState) {
case SCANNER_STATE_PROLOG: {
fEntityScanner.skipSpaces();
- if (fEntityScanner.skipChar('<')) {
+ if (fEntityScanner.skipChar('<', null)) {
setScannerState(SCANNER_STATE_START_OF_MARKUP);
- } else if (fEntityScanner.skipChar('&')) {
+ } else if (fEntityScanner.skipChar('&', NameType.REFERENCE)) {
setScannerState(SCANNER_STATE_REFERENCE);
} else {
setScannerState(SCANNER_STATE_CONTENT);
@@ -849,9 +849,9 @@
setDriver(fContentDriver);
//from now onwards this would be handled by fContentDriver,in the same next() call
return fContentDriver.next();
- } else if (fEntityScanner.skipChar('!')) {
- if (fEntityScanner.skipChar('-')) {
- if (!fEntityScanner.skipChar('-')) {
+ } else if (fEntityScanner.skipChar('!', null)) {
+ if (fEntityScanner.skipChar('-', null)) {
+ if (!fEntityScanner.skipChar('-', null)) {
reportFatalError("InvalidCommentStart",
null);
}
@@ -871,7 +871,7 @@
reportFatalError("MarkupNotRecognizedInProlog",
null);
}
- } else if (fEntityScanner.skipChar('?')) {
+ } else if (fEntityScanner.skipChar('?', null)) {
setScannerState(SCANNER_STATE_PI);
} else {
reportFatalError("MarkupNotRecognizedInProlog",
@@ -991,7 +991,7 @@
case SCANNER_STATE_CONTENT: {
reportFatalError("ContentIllegalInProlog", null);
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
case SCANNER_STATE_REFERENCE: {
reportFatalError("ReferenceIllegalInProlog", null);
@@ -1105,11 +1105,11 @@
fReadingDTD=false;
if (!moreToScan) {
// end doctype declaration
- if (!fEntityScanner.skipChar(']')) {
+ if (!fEntityScanner.skipChar(']', null)) {
reportFatalError("DoctypedeclNotClosed", new Object[]{fDoctypeName});
}
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("DoctypedeclUnterminated", new Object[]{fDoctypeName});
}
fMarkupDepth--;
@@ -1373,7 +1373,7 @@
if(fScannerState == SCANNER_STATE_TERMINATED ){
return XMLEvent.END_DOCUMENT ;
}
- if (fEntityScanner.skipChar('<')) {
+ if (fEntityScanner.skipChar('<', null)) {
setScannerState(SCANNER_STATE_START_OF_MARKUP);
} else {
setScannerState(SCANNER_STATE_CONTENT);
@@ -1382,11 +1382,11 @@
}
case SCANNER_STATE_START_OF_MARKUP: {
fMarkupDepth++;
- if (fEntityScanner.skipChar('?')) {
+ if (fEntityScanner.skipChar('?', null)) {
setScannerState(SCANNER_STATE_PI);
- } else if (fEntityScanner.skipChar('!')) {
+ } else if (fEntityScanner.skipChar('!', null)) {
setScannerState(SCANNER_STATE_COMMENT);
- } else if (fEntityScanner.skipChar('/')) {
+ } else if (fEntityScanner.skipChar('/', null)) {
reportFatalError("MarkupNotRecognizedInMisc",
null);
} else if (isValidNameStartChar(fEntityScanner.peekChar()) ||
@@ -1429,7 +1429,7 @@
} else{
reportFatalError("ContentIllegalInTrailingMisc",
null);
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
setScannerState(SCANNER_STATE_TRAILING_MISC);
return XMLEvent.CHARACTERS;
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java Wed Jul 27 13:33:55 2016 +0000
@@ -2066,6 +2066,7 @@
// system id has to be a valid URI
if (strict) {
+
try {
// if it's already an absolute one, return it
new URI(systemId);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityScanner.java Wed Jul 27 13:33:55 2016 +0000
@@ -21,6 +21,7 @@
package com.sun.org.apache.xerces.internal.impl;
+import com.sun.org.apache.xerces.internal.impl.XMLScanner.NameType;
import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader;
import com.sun.org.apache.xerces.internal.impl.io.UCSReader;
import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader;
@@ -144,6 +145,9 @@
// so that XMLStreamReader.getVersion() can find that out.
protected boolean xmlVersionSetExplicitly = false;
+ // indicates that the operation is for detecting XML version
+ boolean detectingVersion = false;
+
//
// Constructors
//
@@ -530,10 +534,12 @@
* <p>
* <strong>Note:</strong> The character is consumed.
*
+ * @param nt The type of the name (element or attribute)
+ *
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanChar() throws IOException {
+ protected int scanChar(NameType nt) throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanChar: ");
print();
@@ -546,6 +552,7 @@
}
// scan character
+ int offset = fCurrentEntity.position;
int c = fCurrentEntity.ch[fCurrentEntity.position++];
if (c == '\n' || (c == '\r' && isExternal)) {
fCurrentEntity.lineNumber++;
@@ -554,6 +561,7 @@
invokeListeners(1);
fCurrentEntity.ch[0] = (char)c;
load(1, false, false);
+ offset = 0;
}
if (c == '\r' && isExternal) {
if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') {
@@ -570,6 +578,9 @@
System.out.println(" -> '"+(char)c+"'");
}
fCurrentEntity.columnNumber++;
+ if (!detectingVersion) {
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
+ }
return c;
} // scanChar():int
@@ -589,7 +600,7 @@
* @see com.sun.org.apache.xerces.internal.util.SymbolTable
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
*/
- public String scanNmtoken() throws IOException {
+ protected String scanNmtoken() throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanNmtoken: ");
print();
@@ -661,6 +672,8 @@
* <strong>Note:</strong> The string returned must be a symbol. The
* SymbolTable can be used for this purpose.
*
+ * @param nt The type of the name (element or attribute)
+ *
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*
@@ -668,7 +681,7 @@
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isNameStart
*/
- public String scanName() throws IOException {
+ protected String scanName(NameType nt) throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanName: ");
print();
@@ -682,6 +695,7 @@
// scan name
int offset = fCurrentEntity.position;
+ int length;
if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) {
if (++fCurrentEntity.position == fCurrentEntity.count) {
invokeListeners(1);
@@ -709,20 +723,7 @@
vc = XMLChar.isName(c);
}
if(!vc)break;
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- invokeListeners(length);
- if (length == fCurrentEntity.fBufferSize) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.fBufferSize * 2];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- fCurrentEntity.fBufferSize *= 2;
- } else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, offset)) > 0) {
offset = 0;
if (load(length, false, false)) {
break;
@@ -730,12 +731,14 @@
}
}
}
- int length = fCurrentEntity.position - offset;
+ length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length;
// return name
String symbol;
if (length > 0) {
+ checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
+ checkEntityLimit(nt, fCurrentEntity, offset, length);
symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length);
} else
symbol = null;
@@ -759,6 +762,7 @@
* this purpose.
*
* @param qname The qualified name structure to fill.
+ * @param nt The type of the name (element or attribute)
*
* @return Returns true if a qualified name appeared immediately on
* the input and was scanned, false otherwise.
@@ -770,7 +774,7 @@
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isName
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isNameStart
*/
- public boolean scanQName(QName qname) throws IOException {
+ protected boolean scanQName(QName qname, NameType nt) throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanQName, "+qname+": ");
print();
@@ -806,11 +810,13 @@
print();
System.out.println(" -> true");
}
+ checkEntityLimit(nt, fCurrentEntity, 0, 1);
return true;
}
}
int index = -1;
boolean vc = false;
+ int length;
while ( true){
//XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) ;
@@ -829,22 +835,7 @@
//check prefix before further read
checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, index - offset);
}
- if (++fCurrentEntity.position == fCurrentEntity.count) {
- int length = fCurrentEntity.position - offset;
- //check localpart before loading more data
- checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length - index - 1);
- invokeListeners(length);
- if (length == fCurrentEntity.fBufferSize) {
- // bad luck we have to resize our buffer
- char[] tmp = new char[fCurrentEntity.fBufferSize * 2];
- System.arraycopy(fCurrentEntity.ch, offset,
- tmp, 0, length);
- fCurrentEntity.ch = tmp;
- fCurrentEntity.fBufferSize *= 2;
- } else {
- System.arraycopy(fCurrentEntity.ch, offset,
- fCurrentEntity.ch, 0, length);
- }
+ if ((length = checkBeforeLoad(fCurrentEntity, offset, index)) > 0) {
if (index != -1) {
index = index - offset;
}
@@ -854,7 +845,7 @@
}
}
}
- int length = fCurrentEntity.position - offset;
+ length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length;
if (length > 0) {
String prefix = null;
@@ -885,6 +876,7 @@
print();
System.out.println(" -> true");
}
+ checkEntityLimit(nt, fCurrentEntity, offset, length);
return true;
}
}
@@ -900,22 +892,104 @@
} // scanQName(QName):boolean
/**
+ * Checks whether the end of the entity buffer has been reached. If yes,
+ * checks against the limit and buffer size before loading more characters.
+ *
+ * @param entity the current entity
+ * @param offset the offset from which the current read was started
+ * @param nameOffset the offset from which the current name starts
+ * @return the length of characters scanned before the end of the buffer,
+ * zero if there is more to be read in the buffer
+ */
+ protected int checkBeforeLoad(Entity.ScannedEntity entity, int offset,
+ int nameOffset) throws IOException {
+ int length = 0;
+ if (++entity.position == entity.count) {
+ length = entity.position - offset;
+ int nameLength = length;
+ if (nameOffset != -1) {
+ nameOffset = nameOffset - offset;
+ nameLength = length - nameOffset;
+ } else {
+ nameOffset = offset;
+ }
+ //check limit before loading more data
+ checkLimit(Limit.MAX_NAME_LIMIT, entity, nameOffset, nameLength);
+ invokeListeners(length);
+ if (length == entity.ch.length) {
+ // bad luck we have to resize our buffer
+ char[] tmp = new char[entity.fBufferSize * 2];
+ System.arraycopy(entity.ch, offset, tmp, 0, length);
+ entity.ch = tmp;
+ entity.fBufferSize *= 2;
+ }
+ else {
+ System.arraycopy(entity.ch, offset, entity.ch, 0, length);
+ }
+ }
+ return length;
+ }
+
+ /**
+ * If the current entity is an Entity reference, check the accumulated size
+ * against the limit.
+ *
+ * @param nt type of name (element, attribute or entity)
+ * @param entity The current entity
+ * @param offset The index of the first byte
+ * @param length The length of the entity scanned
+ */
+ protected void checkEntityLimit(NameType nt, ScannedEntity entity, int offset, int length) {
+ if (entity == null || !entity.isGE) {
+ return;
+ }
+
+ if (nt != NameType.REFERENCE) {
+ checkLimit(Limit.GENERAL_ENTITY_SIZE_LIMIT, entity, offset, length);
+ }
+ if (nt == NameType.ELEMENTSTART || nt == NameType.ATTRIBUTENAME) {
+ checkNodeCount(entity);
+ }
+ }
+
+ /**
+ * If the current entity is an Entity reference, counts the total nodes in
+ * the entity and checks the accumulated value against the limit.
+ *
+ * @param entity The current entity
+ */
+ protected void checkNodeCount(ScannedEntity entity) {
+ if (entity != null && entity.isGE) {
+ checkLimit(Limit.ENTITY_REPLACEMENT_LIMIT, entity, 0, 1);
+ }
+ }
+
+ /**
* Checks whether the value of the specified Limit exceeds its limit
*
- * @param limit The Limit to be checked.
- * @param entity The current entity.
+ * @param limit The Limit to be checked
+ * @param entity The current entity
* @param offset The index of the first byte
- * @param length The length of the entity scanned.
+ * @param length The length of the entity scanned
*/
protected void checkLimit(Limit limit, ScannedEntity entity, int offset, int length) {
- fLimitAnalyzer.addValue(limit, null, length);
+ fLimitAnalyzer.addValue(limit, entity.name, length);
if (fSecurityManager.isOverLimit(limit, fLimitAnalyzer)) {
fSecurityManager.debugPrint(fLimitAnalyzer);
+ Object[] e = (limit == Limit.ENTITY_REPLACEMENT_LIMIT) ?
+ new Object[]{fLimitAnalyzer.getValue(limit),
+ fSecurityManager.getLimit(limit), fSecurityManager.getStateLiteral(limit)} :
+ new Object[]{entity.name, fLimitAnalyzer.getValue(limit),
+ fSecurityManager.getLimit(limit), fSecurityManager.getStateLiteral(limit)};
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, limit.key(),
- new Object[]{new String(entity.ch, offset, length),
- fLimitAnalyzer.getTotalValue(limit),
- fSecurityManager.getLimit(limit),
- fSecurityManager.getStateLiteral(limit)},
+ e, XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ }
+ if (fSecurityManager.isOverLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+ fSecurityManager.debugPrint(fLimitAnalyzer);
+ fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, "TotalEntitySizeLimit",
+ new Object[]{fLimitAnalyzer.getTotalValue(Limit.TOTAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getStateLiteral(Limit.TOTAL_ENTITY_SIZE_LIMIT)},
XMLErrorReporter.SEVERITY_FATAL_ERROR);
}
}
@@ -942,7 +1016,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanContent(XMLString content) throws IOException {
+ protected int scanContent(XMLString content) throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanContent: ");
print();
@@ -963,6 +1037,7 @@
int offset = fCurrentEntity.position;
int c = fCurrentEntity.ch[offset];
int newlines = 0;
+ boolean counted = false;
if (c == '\n' || (c == '\r' && isExternal)) {
if (DEBUG_BUFFER) {
System.out.print("[newline, "+offset+", "+fCurrentEntity.position+": ");
@@ -976,9 +1051,11 @@
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
if (fCurrentEntity.position == fCurrentEntity.count) {
+ checkEntityLimit(null, fCurrentEntity, offset, newlines);
offset = 0;
fCurrentEntity.position = newlines;
if (load(newlines, false, true)) {
+ counted = true;
break;
}
}
@@ -995,9 +1072,11 @@
fCurrentEntity.lineNumber++;
fCurrentEntity.columnNumber = 1;
if (fCurrentEntity.position == fCurrentEntity.count) {
+ checkEntityLimit(null, fCurrentEntity, offset, newlines);
offset = 0;
fCurrentEntity.position = newlines;
if (load(newlines, false, true)) {
+ counted = true;
break;
}
}
@@ -1011,6 +1090,7 @@
}
int length = fCurrentEntity.position - offset;
if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+ checkEntityLimit(null, fCurrentEntity, offset, length);
//CHANGED: dont replace the value.. append to the buffer. This gives control to the callee
//on buffering the data..
content.setValues(fCurrentEntity.ch, offset, length);
@@ -1038,8 +1118,8 @@
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
- if (fCurrentEntity.isGE) {
- checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+ if (!counted) {
+ checkEntityLimit(null, fCurrentEntity, offset, length);
}
//CHANGED: dont replace the value.. append to the buffer. This gives control to the callee
@@ -1086,6 +1166,7 @@
* @param quote The quote character that signifies the end of the
* attribute value data.
* @param content The content structure to fill.
+ * @param isNSURI a flag indicating whether the content is a Namespace URI
*
* @return Returns the next character on the input, if known. This
* value may be -1 but this does <em>note</em> designate
@@ -1094,7 +1175,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public int scanLiteral(int quote, XMLString content)
+ protected int scanLiteral(int quote, XMLString content, boolean isNSURI)
throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(scanLiteral, '"+(char)quote+"': ");
@@ -1205,8 +1286,10 @@
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
- if (fCurrentEntity.isGE) {
- checkLimit(Limit.TOTAL_ENTITY_SIZE_LIMIT, fCurrentEntity, offset, length);
+
+ checkEntityLimit(null, fCurrentEntity, offset, length);
+ if (isNSURI) {
+ checkLimit(Limit.MAX_NAME_LIMIT, fCurrentEntity, offset, length);
}
content.setValues(fCurrentEntity.ch, offset, length);
@@ -1273,7 +1356,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean scanData(String delimiter, XMLStringBuffer buffer)
+ protected boolean scanData(String delimiter, XMLStringBuffer buffer)
throws IOException {
boolean done = false;
@@ -1311,6 +1394,7 @@
if (fCurrentEntity.position > fCurrentEntity.count - delimLen) {
// something must be wrong with the input: e.g., file ends in an unterminated comment
int length = fCurrentEntity.count - fCurrentEntity.position;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, fCurrentEntity.position, length);
buffer.append (fCurrentEntity.ch, fCurrentEntity.position, length);
fCurrentEntity.columnNumber += fCurrentEntity.count;
fCurrentEntity.baseCharOffset += (fCurrentEntity.position - fCurrentEntity.startPosition);
@@ -1373,6 +1457,7 @@
}
int length = fCurrentEntity.position - offset;
if (fCurrentEntity.position == fCurrentEntity.count - 1) {
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
buffer.append(fCurrentEntity.ch, offset, length);
if (DEBUG_BUFFER) {
System.out.print("]newline, "+offset+", "+fCurrentEntity.position+": ");
@@ -1416,12 +1501,14 @@
fCurrentEntity.position--;
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
buffer.append(fCurrentEntity.ch, offset, length);
return true;
}
}
int length = fCurrentEntity.position - offset;
fCurrentEntity.columnNumber += length - newlines;
+ checkEntityLimit(NameType.COMMENT, fCurrentEntity, offset, length);
if (done) {
length -= delimLen;
}
@@ -1445,13 +1532,14 @@
* the specified character.
*
* @param c The character to skip.
+ * @param nt The type of the name (element or attribute)
*
* @return Returns true if the character was skipped.
*
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean skipChar(int c) throws IOException {
+ protected boolean skipChar(int c, NameType nt) throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(skipChar, '"+(char)c+"': ");
print();
@@ -1464,6 +1552,7 @@
}
// skip character
+ int offset = fCurrentEntity.position;
int cc = fCurrentEntity.ch[fCurrentEntity.position];
if (cc == c) {
fCurrentEntity.position++;
@@ -1478,6 +1567,7 @@
print();
System.out.println(" -> true");
}
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
return true;
} else if (c == '\n' && cc == '\r' && isExternal) {
// handle newlines
@@ -1497,6 +1587,7 @@
print();
System.out.println(" -> true");
}
+ checkEntityLimit(nt, fCurrentEntity, offset, fCurrentEntity.position - offset);
return true;
}
@@ -1526,7 +1617,7 @@
*
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
*/
- public boolean skipSpaces() throws IOException {
+ protected boolean skipSpaces() throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(skipSpaces: ");
print();
@@ -1550,6 +1641,7 @@
// skip spaces
int c = fCurrentEntity.ch[fCurrentEntity.position];
+ int offset = fCurrentEntity.position - 1;
if (XMLChar.isSpace(c)) {
do {
boolean entityChanged = false;
@@ -1579,6 +1671,11 @@
} else {
fCurrentEntity.columnNumber++;
}
+
+ //If this is a general entity, spaces within a start element should be counted
+ checkEntityLimit(null, fCurrentEntity, offset, fCurrentEntity.position - offset);
+ offset = fCurrentEntity.position;
+
// load more characters, if needed
if (!entityChanged){
fCurrentEntity.position++;
@@ -1620,7 +1717,7 @@
/**
- * @param legnth This function checks that following number of characters are available.
+ * @param length This function checks that following number of characters are available.
* to the underlying buffer.
* @return This function returns true if capacity asked is available.
*/
@@ -1629,9 +1726,9 @@
}
/**
- * @param legnth This function checks that following number of characters are available.
+ * @param length This function checks that following number of characters are available.
* to the underlying buffer.
- * @param if the underlying function should change the entity
+ * @param changeEntity a flag to indicate that the underlying function should change the entity
* @return This function returns true if capacity asked is available.
*
*/
@@ -1694,7 +1791,7 @@
* @throws IOException Thrown if i/o error occurs.
* @throws EOFException Thrown on end of file.
*/
- public boolean skipString(String s) throws IOException {
+ protected boolean skipString(String s) throws IOException {
final int length = s.length();
@@ -1714,6 +1811,9 @@
if(afterSkip-- == beforeSkip){
fCurrentEntity.position = fCurrentEntity.position + length ;
fCurrentEntity.columnNumber += length;
+ if (!detectingVersion) {
+ checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+ }
return true;
}
}
@@ -1722,7 +1822,7 @@
return false;
} // skipString(String):boolean
- public boolean skipString(char [] s) throws IOException {
+ protected boolean skipString(char [] s) throws IOException {
final int length = s.length;
//first make sure that required capacity is avaible
@@ -1741,6 +1841,9 @@
}
fCurrentEntity.position = fCurrentEntity.position + length ;
fCurrentEntity.columnNumber += length;
+ if (!detectingVersion) {
+ checkEntityLimit(null, fCurrentEntity, beforeSkip, length);
+ }
return true;
}
@@ -2138,7 +2241,7 @@
*
* @see com.sun.org.apache.xerces.internal.util.XMLChar#isSpace
*/
- public final boolean skipDeclSpaces() throws IOException {
+ protected final boolean skipDeclSpaces() throws IOException {
if (DEBUG_BUFFER) {
System.out.print("(skipDeclSpaces: ");
//XMLEntityManager.print(fCurrentEntity);
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLNSDocumentScannerImpl.java Wed Jul 27 13:33:55 2016 +0000
@@ -189,9 +189,9 @@
// There are two variables,fNamespaces and fBindNamespaces
//StAX uses XMLNSDocumentScannerImpl so this distinction needs to be maintained
if (fNamespaces) {
- fEntityScanner.scanQName(fElementQName);
+ fEntityScanner.scanQName(fElementQName, NameType.ELEMENTSTART);
} else {
- String name = fEntityScanner.scanName();
+ String name = fEntityScanner.scanName(NameType.ELEMENTSTART);
fElementQName.setValues(null, name, name, null);
}
@@ -404,11 +404,11 @@
if (DEBUG_START_END_ELEMENT) System.out.println(this.getClass().toString() +">>> scanAttribute()");
// name
- fEntityScanner.scanQName(fAttributeQName);
+ fEntityScanner.scanQName(fAttributeQName, NameType.ATTRIBUTE);
// equals
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('=')) {
+ if (!fEntityScanner.skipChar('=', NameType.ATTRIBUTE)) {
reportFatalError("EqRequiredInAttribute",
new Object[]{fCurrentElement.rawname,fAttributeQName.rawname});
}
@@ -430,23 +430,28 @@
//since scanAttributeValue doesn't use attIndex parameter therefore we
//can safely add the attribute later..
XMLString tmpStr = getString();
- scanAttributeValue(tmpStr, fTempString2,
- fAttributeQName.rawname, attributes,
- attrIndex, isVC, fCurrentElement.rawname);
+
+ /**
+ * Determine whether this is a namespace declaration that will be subject
+ * to the name limit check in the scanAttributeValue operation.
+ * Namespace declaration format: xmlns="..." or xmlns:prefix="..."
+ * Note that prefix:xmlns="..." isn't a namespace.
+ */
+ String localpart = fAttributeQName.localpart;
+ String prefix = fAttributeQName.prefix != null
+ ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
+ boolean isNSDecl = fBindNamespaces & (prefix == XMLSymbols.PREFIX_XMLNS ||
+ prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS);
+
+ scanAttributeValue(tmpStr, fTempString2, fAttributeQName.rawname, attributes,
+ attrIndex, isVC, fCurrentElement.rawname, isNSDecl);
String value = null;
//fTempString.toString();
// record namespace declarations if any.
if (fBindNamespaces) {
-
- String localpart = fAttributeQName.localpart;
- String prefix = fAttributeQName.prefix != null
- ? fAttributeQName.prefix : XMLSymbols.EMPTY_STRING;
- // when it's of form xmlns="..." or xmlns:prefix="...",
- // it's a namespace declaration. but prefix:xmlns="..." isn't.
- if (prefix == XMLSymbols.PREFIX_XMLNS ||
- prefix == XMLSymbols.EMPTY_STRING && localpart == XMLSymbols.PREFIX_XMLNS) {
+ if (isNSDecl) {
//check the length of URI
if (tmpStr.length > fXMLNameLimit) {
fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLScanner.java Wed Jul 27 13:33:55 2016 +0000
@@ -114,6 +114,30 @@
/** Debug attribute normalization. */
protected static final boolean DEBUG_ATTR_NORMALIZATION = false;
+ /**
+ * Type of names
+ */
+ public static enum NameType {
+ ATTRIBUTE("attribute"),
+ ATTRIBUTENAME("attribute name"),
+ COMMENT("comment"),
+ DOCTYPE("doctype"),
+ ELEMENTSTART("startelement"),
+ ELEMENTEND("endelement"),
+ ENTITY("entity"),
+ NOTATION("notation"),
+ PI("pi"),
+ REFERENCE("reference");
+
+ final String literal;
+ NameType(String literal) {
+ this.literal = literal;
+ }
+
+ String literal() {
+ return literal;
+ }
+ }
//xxx: setting the default value as false, as we dont need to calculate this value
//we should have a feature when set to true computes this value
@@ -144,7 +168,7 @@
protected boolean fNotifyCharRefs = false;
/** Internal parser-settings feature */
- protected boolean fParserSettings = true;
+ protected boolean fParserSettings = true;
// properties
@@ -173,13 +197,13 @@
/** event type */
protected XMLEvent fEvent ;
- /** Entity scanner, this alwasy works on last entity that was opened. */
+ /** Entity scanner, this always works on last entity that was opened. */
protected XMLEntityScanner fEntityScanner = null;
/** Entity depth. */
protected int fEntityDepth;
- /** Literal value of the last character refence scanned. */
+ /** Literal value of the last character reference scanned. */
protected String fCharRefLiteral = null;
/** Scanning attribute. */
@@ -547,10 +571,10 @@
}
// end
- if (!fEntityScanner.skipChar('?')) {
+ if (!fEntityScanner.skipChar('?', null)) {
reportFatalError("XMLDeclUnterminated", null);
}
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', null)) {
reportFatalError("XMLDeclUnterminated", null);
}
@@ -577,7 +601,7 @@
* <strong>Note:</strong> This method uses fStringBuffer2, anything in it
* at the time of calling is lost.
*/
- public String scanPseudoAttribute(boolean scanningTextDecl,
+ protected String scanPseudoAttribute(boolean scanningTextDecl,
XMLString value)
throws IOException, XNIException {
@@ -588,7 +612,7 @@
reportFatalError("PseudoAttrNameExpected", null);
}
fEntityScanner.skipSpaces();
- if (!fEntityScanner.skipChar('=')) {
+ if (!fEntityScanner.skipChar('=', null)) {
reportFatalError(scanningTextDecl ? "EqRequiredInTextDecl"
: "EqRequiredInXMLDecl", new Object[]{name});
}
@@ -598,15 +622,15 @@
reportFatalError(scanningTextDecl ? "QuoteRequiredInTextDecl"
: "QuoteRequiredInXMLDecl" , new Object[]{name});
}
- fEntityScanner.scanChar();
- int c = fEntityScanner.scanLiteral(quote, value);
+ fEntityScanner.scanChar(NameType.ATTRIBUTE);
+ int c = fEntityScanner.scanLiteral(quote, value, false);
if (c != quote) {
fStringBuffer2.clear();
do {
fStringBuffer2.append(value);
if (c != -1) {
if (c == '&' || c == '%' || c == '<' || c == ']') {
- fStringBuffer2.append((char)fEntityScanner.scanChar());
+ fStringBuffer2.append((char)fEntityScanner.scanChar(NameType.ATTRIBUTE));
} else if (XMLChar.isHighSurrogate(c)) {
scanSurrogates(fStringBuffer2);
} else if (isInvalidLiteral(c)) {
@@ -614,15 +638,15 @@
? "InvalidCharInTextDecl" : "InvalidCharInXMLDecl";
reportFatalError(key,
new Object[] {Integer.toString(c, 16)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
}
- c = fEntityScanner.scanLiteral(quote, value);
+ c = fEntityScanner.scanLiteral(quote, value, false);
} while (c != quote);
fStringBuffer2.append(value);
value.setValues(fStringBuffer2);
}
- if (!fEntityScanner.skipChar(quote)) {
+ if (!fEntityScanner.skipChar(quote, null)) {
reportFatalError(scanningTextDecl ? "CloseQuoteMissingInTextDecl"
: "CloseQuoteMissingInXMLDecl",
new Object[]{name});
@@ -680,7 +704,7 @@
// target
fReportEntity = false;
- String target = fEntityScanner.scanName();
+ String target = fEntityScanner.scanName(NameType.PI);
if (target == null) {
reportFatalError("PITargetRequired", null);
}
@@ -745,7 +769,7 @@
} else if (isInvalidLiteral(c)) {
reportFatalError("InvalidCharInPI",
new Object[]{Integer.toHexString(c)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
}
}
} while (fEntityScanner.scanData("?>", data));
@@ -786,11 +810,11 @@
else if (isInvalidLiteral(c)) {
reportFatalError("InvalidCharInComment",
new Object[] { Integer.toHexString(c) });
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.COMMENT);
}
}
}
- if (!fEntityScanner.skipChar('>')) {
+ if (!fEntityScanner.skipChar('>', NameType.COMMENT)) {
reportFatalError("DashDashInComment", null);
}
@@ -811,15 +835,14 @@
* @param checkEntities true if undeclared entities should be reported as VC violation,
* false if undeclared entities should be reported as WFC violation.
* @param eleName The name of element to which this attribute belongs.
+ * @param isNSURI a flag indicating whether the content is a Namespace URI
*
* <strong>Note:</strong> This method uses fStringBuffer2, anything in it
* at the time of calling is lost.
**/
- protected void scanAttributeValue(XMLString value,
- XMLString nonNormalizedValue,
- String atName,
- XMLAttributes attributes, int attrIndex,
- boolean checkEntities, String eleName)
+ protected void scanAttributeValue(XMLString value, XMLString nonNormalizedValue,
+ String atName, XMLAttributes attributes, int attrIndex, boolean checkEntities,
+ String eleName, boolean isNSURI)
throws IOException, XNIException {
XMLStringBuffer stringBuffer = null;
// quote
@@ -828,10 +851,10 @@
reportFatalError("OpenQuoteExpected", new Object[]{eleName, atName});
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.ATTRIBUTE);
int entityDepth = fEntityDepth;
- int c = fEntityScanner.scanLiteral(quote, value);
+ int c = fEntityScanner.scanLiteral(quote, value, isNSURI);
if (DEBUG_ATTR_NORMALIZATION) {
System.out.println("** scanLiteral -> \""
+ value.toString() + "\"");
@@ -857,11 +880,11 @@
+ stringBuffer.toString() + "\"");
}
if (c == '&') {
- fEntityScanner.skipChar('&');
+ fEntityScanner.skipChar('&', NameType.REFERENCE);
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
fStringBuffer2.append('&');
}
- if (fEntityScanner.skipChar('#')) {
+ if (fEntityScanner.skipChar('#', NameType.REFERENCE)) {
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue ) {
fStringBuffer2.append('#');
}
@@ -879,53 +902,20 @@
}
}
} else {
- String entityName = fEntityScanner.scanName();
+ String entityName = fEntityScanner.scanName(NameType.ENTITY);
if (entityName == null) {
reportFatalError("NameRequiredInReference", null);
} else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append(entityName);
}
- if (!fEntityScanner.skipChar(';')) {
+ if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInReference",
new Object []{entityName});
} else if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append(';');
}
- if (entityName == fAmpSymbol) {
- stringBuffer.append('&');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value5: \""
- + stringBuffer.toString()
- + "\"");
- }
- } else if (entityName == fAposSymbol) {
- stringBuffer.append('\'');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value7: \""
- + stringBuffer.toString()
- + "\"");
- }
- } else if (entityName == fLtSymbol) {
- stringBuffer.append('<');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** value9: \""
- + stringBuffer.toString()
- + "\"");
- }
- } else if (entityName == fGtSymbol) {
- stringBuffer.append('>');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** valueB: \""
- + stringBuffer.toString()
- + "\"");
- }
- } else if (entityName == fQuotSymbol) {
- stringBuffer.append('"');
- if (DEBUG_ATTR_NORMALIZATION) {
- System.out.println("** valueD: \""
- + stringBuffer.toString()
- + "\"");
- }
+ if (resolveCharacter(entityName, stringBuffer)) {
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
} else {
if (fEntityStore.isExternalEntity(entityName)) {
reportFatalError("ReferenceToExternalEntity",
@@ -952,12 +942,12 @@
} else if (c == '<') {
reportFatalError("LessthanInAttValue",
new Object[] { eleName, atName });
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append((char)c);
}
} else if (c == '%' || c == ']') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
stringBuffer.append((char)c);
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append((char)c);
@@ -967,7 +957,7 @@
+ stringBuffer.toString() + "\"");
}
} else if (c == '\n' || c == '\r') {
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
stringBuffer.append(' ');
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append('\n');
@@ -988,12 +978,12 @@
} else if (c != -1 && isInvalidLiteral(c)) {
reportFatalError("InvalidCharInAttValue",
new Object[] {eleName, atName, Integer.toString(c, 16)});
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append((char)c);
}
}
- c = fEntityScanner.scanLiteral(quote, value);
+ c = fEntityScanner.scanLiteral(quote, value, isNSURI);
if (entityDepth == fEntityDepth && fNeedNonNormalizedValue) {
fStringBuffer2.append(value);
}
@@ -1014,7 +1004,7 @@
nonNormalizedValue.setValues(fStringBuffer2);
// quote
- int cquote = fEntityScanner.scanChar();
+ int cquote = fEntityScanner.scanChar(NameType.ATTRIBUTE);
if (cquote != quote) {
reportFatalError("CloseQuoteExpected", new Object[]{eleName, atName});
}
@@ -1022,6 +1012,39 @@
/**
+ * Resolves character entity references.
+ * @param entityName the name of the entity
+ * @param stringBuffer the current XMLStringBuffer to append the character to.
+ * @return true if resolved, false otherwise
+ */
+ protected boolean resolveCharacter(String entityName, XMLStringBuffer stringBuffer) {
+ /**
+ * entityNames (symbols) are interned. The equals method would do the same,
+ * but I'm leaving it as comparisons by references are common in the impl
+ * and it made it explicit to others who read this code.
+ */
+ if (entityName == fAmpSymbol) {
+ stringBuffer.append('&');
+ return true;
+ } else if (entityName == fAposSymbol) {
+ stringBuffer.append('\'');
+ return true;
+ } else if (entityName == fLtSymbol) {
+ stringBuffer.append('<');
+ return true;
+ } else if (entityName == fGtSymbol) {
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
+ stringBuffer.append('>');
+ return true;
+ } else if (entityName == fQuotSymbol) {
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, 1);
+ stringBuffer.append('"');
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Scans External ID and return the public and system IDs.
*
* @param identifiers An array of size 2 to return the system id,
@@ -1064,25 +1087,25 @@
}
reportFatalError("QuoteRequiredInSystemID", null);
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
XMLString ident = fString;
- if (fEntityScanner.scanLiteral(quote, ident) != quote) {
+ if (fEntityScanner.scanLiteral(quote, ident, false) != quote) {
fStringBuffer.clear();
do {
fStringBuffer.append(ident);
int c = fEntityScanner.peekChar();
if (XMLChar.isMarkup(c) || c == ']') {
- fStringBuffer.append((char)fEntityScanner.scanChar());
+ fStringBuffer.append((char)fEntityScanner.scanChar(null));
} else if (c != -1 && isInvalidLiteral(c)) {
reportFatalError("InvalidCharInSystemID",
new Object[] {Integer.toString(c, 16)});
}
- } while (fEntityScanner.scanLiteral(quote, ident) != quote);
+ } while (fEntityScanner.scanLiteral(quote, ident, false) != quote);
fStringBuffer.append(ident);
ident = fStringBuffer;
}
systemId = ident.toString();
- if (!fEntityScanner.skipChar(quote)) {
+ if (!fEntityScanner.skipChar(quote, null)) {
reportFatalError("SystemIDUnterminated", null);
}
}
@@ -1114,7 +1137,7 @@
*/
protected boolean scanPubidLiteral(XMLString literal)
throws IOException, XNIException {
- int quote = fEntityScanner.scanChar();
+ int quote = fEntityScanner.scanChar(null);
if (quote != '\'' && quote != '"') {
reportFatalError("QuoteRequiredInPublicID", null);
return false;
@@ -1125,7 +1148,7 @@
boolean skipSpace = true;
boolean dataok = true;
while (true) {
- int c = fEntityScanner.scanChar();
+ int c = fEntityScanner.scanChar(null);
if (c == ' ' || c == '\n' || c == '\r') {
if (!skipSpace) {
// take the first whitespace as a space and skip the others
@@ -1241,9 +1264,10 @@
*/
protected int scanCharReferenceValue(XMLStringBuffer buf, XMLStringBuffer buf2)
throws IOException, XNIException {
+ int initLen = buf.length;
// scan hexadecimal value
boolean hex = false;
- if (fEntityScanner.skipChar('x')) {
+ if (fEntityScanner.skipChar('x', NameType.REFERENCE)) {
if (buf2 != null) { buf2.append('x'); }
hex = true;
fStringBuffer3.clear();
@@ -1255,7 +1279,7 @@
(c >= 'A' && c <= 'F');
if (digit) {
if (buf2 != null) { buf2.append((char)c); }
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
fStringBuffer3.append((char)c);
do {
@@ -1265,7 +1289,7 @@
(c >= 'A' && c <= 'F');
if (digit) {
if (buf2 != null) { buf2.append((char)c); }
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
fStringBuffer3.append((char)c);
}
} while (digit);
@@ -1283,7 +1307,7 @@
digit = c >= '0' && c <= '9';
if (digit) {
if (buf2 != null) { buf2.append((char)c); }
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
fStringBuffer3.append((char)c);
do {
@@ -1291,7 +1315,7 @@
digit = c >= '0' && c <= '9';
if (digit) {
if (buf2 != null) { buf2.append((char)c); }
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(NameType.REFERENCE);
fStringBuffer3.append((char)c);
}
} while (digit);
@@ -1301,7 +1325,7 @@
}
// end
- if (!fEntityScanner.skipChar(';')) {
+ if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) {
reportFatalError("SemicolonRequiredInCharRef", null);
}
if (buf2 != null) { buf2.append(';'); }
@@ -1347,6 +1371,9 @@
}
}
+ if (fEntityScanner.fCurrentEntity.isGE) {
+ checkEntityLimit(false, fEntityScanner.fCurrentEntity.name, buf.length - initLen);
+ }
return value;
}
// returns true if the given character is not
@@ -1408,14 +1435,14 @@
protected boolean scanSurrogates(XMLStringBuffer buf)
throws IOException, XNIException {
- int high = fEntityScanner.scanChar();
+ int high = fEntityScanner.scanChar(null);
int low = fEntityScanner.peekChar();
if (!XMLChar.isLowSurrogate(low)) {
reportFatalError("InvalidCharInContent",
new Object[] {Integer.toString(high, 16)});
return false;
}
- fEntityScanner.scanChar();
+ fEntityScanner.scanChar(null);
// convert surrogates to supplemental character
int c = XMLChar.supplemental((char)high, (char)low);
@@ -1478,5 +1505,52 @@
}
}
+ /**
+ * Add the count of the content buffer and check if the accumulated
+ * value exceeds the limit
+ * @param isPEDecl a flag to indicate whether the entity is parameter
+ * @param entityName entity name
+ * @param buffer content buffer
+ */
+ void checkEntityLimit(boolean isPEDecl, String entityName, XMLString buffer) {
+ checkEntityLimit(isPEDecl, entityName, buffer.length);
+ }
+ /**
+ * Add the count and check limit
+ * @param isPEDecl a flag to indicate whether the entity is parameter
+ * @param entityName entity name
+ * @param len length of the buffer
+ */
+ void checkEntityLimit(boolean isPEDecl, String entityName, int len) {
+ if (fLimitAnalyzer == null) {
+ fLimitAnalyzer = fEntityManager.fLimitAnalyzer;
+ }
+ if (isPEDecl) {
+ fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, "%" + entityName, len);
+ if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+ fSecurityManager.debugPrint(fLimitAnalyzer);
+ reportFatalError("MaxEntitySizeLimit", new Object[]{"%" + entityName,
+ fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)});
+ }
+ } else {
+ fLimitAnalyzer.addValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName, len);
+ if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+ fSecurityManager.debugPrint(fLimitAnalyzer);
+ reportFatalError("MaxEntitySizeLimit", new Object[]{entityName,
+ fLimitAnalyzer.getValue(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getLimit(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT)});
+ }
+ }
+ if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) {
+ fSecurityManager.debugPrint(fLimitAnalyzer);
+ reportFatalError("TotalEntitySizeLimit",
+ new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT),
+ fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)});
+ }
+ }
} // class XMLScanner
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLVersionDetector.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,62 +1,21 @@
/*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999-2003 The Apache Software Foundation.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
- * 4. The names "Xerces" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 2003, International
- * Business Machines, Inc., http://www.apache.org. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.sun.org.apache.xerces.internal.impl;
@@ -192,40 +151,46 @@
// in the XML declaration.
fEntityManager.setScannerVersion(Constants.XML_VERSION_1_0);
XMLEntityScanner scanner = fEntityManager.getEntityScanner();
+ scanner.detectingVersion = true;
try {
if (!scanner.skipString("<?xml")) {
// definitely not a well-formed 1.1 doc!
+ scanner.detectingVersion = false;
return Constants.XML_VERSION_1_0;
}
if (!scanner.skipDeclSpaces()) {
fixupCurrentEntity(fEntityManager, fExpectedVersionString, 5);
+ scanner.detectingVersion = false;
return Constants.XML_VERSION_1_0;
}
if (!scanner.skipString("version")) {
fixupCurrentEntity(fEntityManager, fExpectedVersionString, 6);
+ scanner.detectingVersion = false;
return Constants.XML_VERSION_1_0;
}
scanner.skipDeclSpaces();
// Check if the next character is '='. If it is then consume it.
if (scanner.peekChar() != '=') {
fixupCurrentEntity(fEntityManager, fExpectedVersionString, 13);
+ scanner.detectingVersion = false;
return Constants.XML_VERSION_1_0;
}
- scanner.scanChar();
+ scanner.scanChar(null);
scanner.skipDeclSpaces();
- int quoteChar = scanner.scanChar();
+ int quoteChar = scanner.scanChar(null);
fExpectedVersionString[14] = (char) quoteChar;
for (int versionPos = 0; versionPos < XML11_VERSION.length; versionPos++) {
- fExpectedVersionString[15 + versionPos] = (char) scanner.scanChar();
+ fExpectedVersionString[15 + versionPos] = (char) scanner.scanChar(null);
}
// REVISIT: should we check whether this equals quoteChar?
- fExpectedVersionString[18] = (char) scanner.scanChar();
+ fExpectedVersionString[18] = (char) scanner.scanChar(null);
fixupCurrentEntity(fEntityManager, fExpectedVersionString, 19);
int matched = 0;
for (; matched < XML11_VERSION.length; matched++) {
if (fExpectedVersionString[15 + matched] != XML11_VERSION[matched])
break;
}
+ scanner.detectingVersion = false;
if (matched == XML11_VERSION.length)
return Constants.XML_VERSION_1_1;
return Constants.XML_VERSION_1_0;
@@ -237,10 +202,9 @@
"PrematureEOF",
null,
XMLErrorReporter.SEVERITY_FATAL_ERROR);
+ scanner.detectingVersion = false;
return Constants.XML_VERSION_1_0;
-
}
-
}
// This method prepends "length" chars from the char array,
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/msg/XMLMessages.properties Wed Jul 27 13:33:55 2016 +0000
@@ -298,7 +298,8 @@
EntityExpansionLimit=JAXP00010001: The parser has encountered more than \"{0}\" entity expansions in this document; this is the limit imposed by the JDK.
ElementAttributeLimit=JAXP00010002: Element \"{0}\" has more than \"{1}\" attributes, \"{1}\" is the limit imposed by the JDK.
MaxEntitySizeLimit=JAXP00010003: The length of entity \"{0}\" is \"{1}\" that exceeds the \"{2}\" limit set by \"{3}\".
- TotalEntitySizeLimit=JAXP00010004: The accumulated size of entities is \"{1}\" that exceeded the \"{2}\" limit set by \"{3}\".
+ TotalEntitySizeLimit=JAXP00010004: The accumulated size of entities is \"{0}\" that exceeded the \"{1}\" limit set by \"{2}\".
MaxXMLNameLimit=JAXP00010005: The length of entity \"{0}\" is \"{1}\" that exceeds the \"{2}\" limit set by \"{3}\".
MaxElementDepthLimit=JAXP00010006: The element \"{0}\" has a depth of \"{1}\" that exceeds the limit \"{2}\" set by \"{3}\".
+ EntityReplacementLimit=JAXP00010007: The total number of nodes in entity references is \"{0}\" that is over the limit \"{1}\" set by \"{2}\".
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLLimitAnalyzer.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLLimitAnalyzer.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,7 +1,7 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
@@ -129,13 +129,15 @@
if (index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() ||
index == Limit.MAX_OCCUR_NODE_LIMIT.ordinal() ||
index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() ||
- index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()
+ index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() ||
+ index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()
) {
totalValue[index] += value;
return;
}
if (index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() ||
index == Limit.MAX_NAME_LIMIT.ordinal()) {
+ values[index] = value;
totalValue[index] = value;
return;
}
@@ -175,10 +177,13 @@
* @return the value of the property
*/
public int getValue(Limit limit) {
- return values[limit.ordinal()];
+ return getValue(limit.ordinal());
}
public int getValue(int index) {
+ if (index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal()) {
+ return totalValue[index];
+ }
return values[index];
}
/**
@@ -233,6 +238,11 @@
public void reset(Limit limit) {
if (limit.ordinal() == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal()) {
totalValue[limit.ordinal()] = 0;
+ } else if (limit.ordinal() == Limit.GENERAL_ENTITY_SIZE_LIMIT.ordinal()) {
+ names[limit.ordinal()] = null;
+ values[limit.ordinal()] = 0;
+ caches[limit.ordinal()] = null;
+ totalValue[limit.ordinal()] = 0;
}
}
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLSecurityManager.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/utils/XMLSecurityManager.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,9 @@
MAX_ELEMENT_DEPTH_LIMIT("MaxElementDepthLimit",
Constants.JDK_MAX_ELEMENT_DEPTH, Constants.SP_MAX_ELEMENT_DEPTH, 0, 0),
MAX_NAME_LIMIT("MaxXMLNameLimit",
- Constants.JDK_XML_NAME_LIMIT, Constants.SP_XML_NAME_LIMIT, 1000, 1000);
+ Constants.JDK_XML_NAME_LIMIT, Constants.SP_XML_NAME_LIMIT, 1000, 1000),
+ ENTITY_REPLACEMENT_LIMIT("EntityReplacementLimit",
+ Constants.JDK_ENTITY_REPLACEMENT_LIMIT, Constants.SP_ENTITY_REPLACEMENT_LIMIT, 0, 3000000);
final String key;
final String apiProperty;
@@ -450,6 +452,7 @@
if (index == Limit.ELEMENT_ATTRIBUTE_LIMIT.ordinal() ||
index == Limit.ENTITY_EXPANSION_LIMIT.ordinal() ||
index == Limit.TOTAL_ENTITY_SIZE_LIMIT.ordinal() ||
+ index == Limit.ENTITY_REPLACEMENT_LIMIT.ordinal() ||
index == Limit.MAX_ELEMENT_DEPTH_LIMIT.ordinal() ||
index == Limit.MAX_NAME_LIMIT.ordinal()
) {
--- a/jaxp/test/javax/xml/jaxp/unittest/transform/XSLTFunctionsTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxp/test/javax/xml/jaxp/unittest/transform/XSLTFunctionsTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@
public class XSLTFunctionsTest {
/**
- * @bug 8062518
+ * @bug 8062518 8153082
* Verifies that a reference to the DTM created by XSLT document function is
* actually read from the DTM by an extension function.
* @param xml Content of xml file to process
--- a/jaxws/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/jaxws/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -373,3 +373,4 @@
5b0570e3db29f6b8c80a4beac70d51284507b203 jdk-9+125
264a44128cd6286e598d5a849ceeb613c06269d0 jdk-9+126
06d706c70634775418dc79a2671780ba1c624fd2 jdk-9+127
+fe4e11bd2423635dc0f5f5cb9a64eb2f2cce7f4c jdk-9+128
--- a/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/make/lib/Awt2dLibraries.gmk Wed Jul 27 13:33:55 2016 +0000
@@ -350,8 +350,6 @@
BUILD_LIBAWT_XAWT_awt_Font.c_CFLAGS := -w
# initializing a declared 'extern'
BUILD_LIBAWT_XAWT_debug_mem.c_CFLAGS := -w
- # decimal constant is unsigned only in ISO C90 (JAVASE_EMBEDDED)
- BUILD_LIBAWT_XAWT_XToolkit.c_CFLAGS := -w
endif
$(eval $(call SetupNativeCompilation,BUILD_LIBAWT_XAWT, \
--- a/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/lang/VersionProps.java.template Wed Jul 27 13:33:55 2016 +0000
@@ -166,10 +166,6 @@
ps.print(java_runtime_name + " (" + jdk_debug_level + "build " + java_runtime_version);
- if (java_runtime_name.indexOf("Embedded") != -1 && isHeadless) {
- // embedded builds report headless state
- ps.print(", headless");
- }
ps.println(')');
/* Third line: JVM information. */
--- a/jdk/src/java.base/share/classes/java/net/URLPermission.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/net/URLPermission.java Wed Jul 27 13:33:55 2016 +0000
@@ -461,11 +461,10 @@
}
private String actions() {
- String b = String.join(",", methods);
- if (!requestHeaders.isEmpty()) {
- b += ":" + String.join(",", requestHeaders);
- }
- return b;
+ // The colon separator is optional when the request headers list is
+ // empty.This implementation chooses to include it even when the request
+ // headers list is empty.
+ return String.join(",", methods) + ":" + String.join(",", requestHeaders);
}
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Wed Jul 27 13:33:55 2016 +0000
@@ -221,7 +221,10 @@
* across both while pushing actions. The second completion is
* a CoCompletion pointing to the first, shared so that at most
* one performs the action. The multiple-arity methods allOf
- * and anyOf do this pairwise to form trees of completions.
+ * does this pairwise to form trees of completions. Method
+ * anyOf is handled differently from allOf because completion of
+ * any source should trigger a cleanStack of other sources.
+ * Each AnyOf completion can reach others via a shared array.
*
* Note that the generic type parameters of methods vary according
* to whether "this" is a source, dependent, or completion.
@@ -588,9 +591,9 @@
}
/**
- * Post-processing by dependent after successful UniCompletion
- * tryFire. Tries to clean stack of source a, and then either runs
- * postComplete or returns this to caller, depending on mode.
+ * Post-processing by dependent after successful UniCompletion tryFire.
+ * Tries to clean stack of source a, and then either runs postComplete
+ * or returns this to caller, depending on mode.
*/
final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
if (a != null && a.stack != null) {
@@ -1003,12 +1006,12 @@
}
@SuppressWarnings("serial")
- static final class UniRelay<T> extends UniCompletion<T,T> {
- UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+ static final class UniRelay<U, T extends U> extends UniCompletion<T,U> {
+ UniRelay(CompletableFuture<U> dep, CompletableFuture<T> src) {
super(null, dep, src);
}
- final CompletableFuture<T> tryFire(int mode) {
- CompletableFuture<T> d; CompletableFuture<T> a; Object r;
+ final CompletableFuture<U> tryFire(int mode) {
+ CompletableFuture<U> d; CompletableFuture<T> a; Object r;
if ((d = dep) == null
|| (a = src) == null || (r = a.result) == null)
return null;
@@ -1019,13 +1022,14 @@
}
}
- private CompletableFuture<T> uniCopyStage() {
+ private static <U, T extends U> CompletableFuture<U> uniCopyStage(
+ CompletableFuture<T> src) {
Object r;
- CompletableFuture<T> d = newIncompleteFuture();
- if ((r = result) != null)
+ CompletableFuture<U> d = src.newIncompleteFuture();
+ if ((r = src.result) != null)
d.result = encodeRelay(r);
else
- unipush(new UniRelay<T>(d, this));
+ src.unipush(new UniRelay<U,T>(d, src));
return d;
}
@@ -1034,7 +1038,7 @@
if ((r = result) != null)
return new MinimalStage<T>(encodeRelay(r));
MinimalStage<T> d = new MinimalStage<T>();
- unipush(new UniRelay<T>(d, this));
+ unipush(new UniRelay<T,T>(d, this));
return d;
}
@@ -1069,7 +1073,7 @@
if ((r = g.result) != null)
d.completeRelay(r);
else {
- g.unipush(new UniRelay<V>(d, g));
+ g.unipush(new UniRelay<V,V>(d, g));
if (d.result == null)
return null;
}
@@ -1103,7 +1107,7 @@
if ((s = g.result) != null)
d.result = encodeRelay(s);
else {
- g.unipush(new UniRelay<V>(d, g));
+ g.unipush(new UniRelay<V,V>(d, g));
}
} catch (Throwable ex) {
d.result = encodeThrowable(ex);
@@ -1637,45 +1641,40 @@
return d;
}
+ /** Completion for an anyOf input future. */
@SuppressWarnings("serial")
- static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
- OrRelay(CompletableFuture<Object> dep,
- CompletableFuture<T> src, CompletableFuture<U> snd) {
- super(null, dep, src, snd);
+ static class AnyOf extends Completion {
+ CompletableFuture<Object> dep; CompletableFuture<?> src;
+ CompletableFuture<?>[] srcs;
+ AnyOf(CompletableFuture<Object> dep, CompletableFuture<?> src,
+ CompletableFuture<?>[] srcs) {
+ this.dep = dep; this.src = src; this.srcs = srcs;
}
final CompletableFuture<Object> tryFire(int mode) {
- CompletableFuture<Object> d;
- CompletableFuture<T> a;
- CompletableFuture<U> b;
+ // assert mode != ASYNC;
+ CompletableFuture<Object> d; CompletableFuture<?> a;
+ CompletableFuture<?>[] as;
Object r;
if ((d = dep) == null
- || (a = src) == null || (b = snd) == null
- || ((r = a.result) == null && (r = b.result) == null))
+ || (a = src) == null || (r = a.result) == null
+ || (as = srcs) == null)
return null;
- d.completeRelay(r);
- src = null; snd = null; dep = null;
- return d.postFire(a, b, mode);
+ dep = null; src = null; srcs = null;
+ if (d.completeRelay(r)) {
+ for (CompletableFuture<?> b : as)
+ if (b != a)
+ b.cleanStack();
+ if (mode < 0)
+ return d;
+ else
+ d.postComplete();
+ }
+ return null;
}
- }
-
- /** Recursively constructs a tree of completions. */
- static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<Object> d = new CompletableFuture<Object>();
- if (lo <= hi) {
- CompletableFuture<?> a, b; Object r;
- int mid = (lo + hi) >>> 1;
- if ((a = (lo == mid ? cfs[lo] :
- orTree(cfs, lo, mid))) == null ||
- (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
- orTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- if ((r = a.result) != null && (r = b.result) != null)
- d.result = encodeRelay(r);
- else
- a.orpush(b, new OrRelay<>(d, a, b));
+ final boolean isLive() {
+ CompletableFuture<Object> d;
+ return (d = dep) != null && d.result == null;
}
- return d;
}
/* ------------- Zero-input Async forms -------------- */
@@ -2354,7 +2353,28 @@
* {@code null}
*/
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
- return orTree(cfs, 0, cfs.length - 1);
+ int n; Object r;
+ if ((n = cfs.length) <= 1)
+ return (n == 0)
+ ? new CompletableFuture<Object>()
+ : uniCopyStage(cfs[0]);
+ for (CompletableFuture<?> cf : cfs)
+ if ((r = cf.result) != null)
+ return new CompletableFuture<Object>(encodeRelay(r));
+ cfs = cfs.clone();
+ CompletableFuture<Object> d = new CompletableFuture<>();
+ for (CompletableFuture<?> cf : cfs)
+ cf.unipush(new AnyOf(d, cf, cfs));
+ // If d was completed while we were adding completions, we should
+ // clean the stack of any sources that may have had completions
+ // pushed on their stack after d was completed.
+ if (d.result != null)
+ for (int i = 0, len = cfs.length; i < len; i++)
+ if (cfs[i].result != null)
+ for (i++; i < len; i++)
+ if (cfs[i].result == null)
+ cfs[i].cleanStack();
+ return d;
}
/* ------------- Control and status methods -------------- */
@@ -2526,7 +2546,7 @@
* @since 9
*/
public CompletableFuture<T> copy() {
- return uniCopyStage();
+ return uniCopyStage(this);
}
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Wed Jul 27 13:33:55 2016 +0000
@@ -1023,7 +1023,7 @@
int hash = spread(key.hashCode());
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
- Node<K,V> f; int n, i, fh;
+ Node<K,V> f; int n, i, fh; K fk; V fv;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
@@ -1032,6 +1032,10 @@
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
+ else if (onlyIfAbsent && fh == hash && // check first node
+ ((fk = f.key) == key || fk != null && key.equals(fk)) &&
+ (fv = f.val) != null)
+ return fv;
else {
V oldVal = null;
synchronized (f) {
@@ -1702,7 +1706,7 @@
V val = null;
int binCount = 0;
for (Node<K,V>[] tab = table;;) {
- Node<K,V> f; int n, i, fh;
+ Node<K,V> f; int n, i, fh; K fk; V fv;
if (tab == null || (n = tab.length) == 0)
tab = initTable();
else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
@@ -1724,6 +1728,10 @@
}
else if ((fh = f.hash) == MOVED)
tab = helpTransfer(tab, f);
+ else if (fh == h && // check first node
+ ((fk = f.key) == key || fk != null && key.equals(fk)) &&
+ (fv = f.val) != null)
+ return fv;
else {
boolean added = false;
synchronized (f) {
@@ -4553,14 +4561,21 @@
return true;
}
- public final boolean removeAll(Collection<?> c) {
+ public boolean removeAll(Collection<?> c) {
if (c == null) throw new NullPointerException();
boolean modified = false;
- for (Iterator<E> it = iterator(); it.hasNext();) {
- if (c.contains(it.next())) {
- it.remove();
- modified = true;
+ // Use (c instanceof Set) as a hint that lookup in c is as
+ // efficient as this view
+ if (c instanceof Set<?> && c.size() > map.table.length) {
+ for (Iterator<?> it = iterator(); it.hasNext(); ) {
+ if (c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
}
+ } else {
+ for (Object e : c)
+ modified |= remove(e);
}
return modified;
}
@@ -4747,6 +4762,18 @@
throw new UnsupportedOperationException();
}
+ @Override public boolean removeAll(Collection<?> c) {
+ if (c == null) throw new NullPointerException();
+ boolean modified = false;
+ for (Iterator<V> it = iterator(); it.hasNext();) {
+ if (c.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
public boolean removeIf(Predicate<? super V> filter) {
return map.removeValueIf(filter);
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/Exchanger.java Wed Jul 27 13:33:55 2016 +0000
@@ -235,22 +235,16 @@
* As is too common in this sort of code, methods are monolithic
* because most of the logic relies on reads of fields that are
* maintained as local variables so can't be nicely factored --
- * mainly, here, bulky spin->yield->block/cancel code), and
- * heavily dependent on intrinsics (VarHandles) to use inlined
- * embedded CAS and related memory access operations (that tend
- * not to be as readily inlined by dynamic compilers when they are
- * hidden behind other methods that would more nicely name and
- * encapsulate the intended effects). This includes the use of
- * setRelease to clear fields of the per-thread Nodes between
- * uses. Note that field Node.item is not declared as volatile
- * even though it is read by releasing threads, because they only
- * do so after CAS operations that must precede access, and all
- * uses by the owning thread are otherwise acceptably ordered by
- * other operations. (Because the actual points of atomicity are
- * slot CASes, it would also be legal for the write to Node.match
- * in a release to be weaker than a full volatile write. However,
- * this is not done because it could allow further postponement of
- * the write, delaying progress.)
+ * mainly, here, bulky spin->yield->block/cancel code. Note that
+ * field Node.item is not declared as volatile even though it is
+ * read by releasing threads, because they only do so after CAS
+ * operations that must precede access, and all uses by the owning
+ * thread are otherwise acceptably ordered by other operations.
+ * (Because the actual points of atomicity are slot CASes, it
+ * would also be legal for the write to Node.match in a release to
+ * be weaker than a full volatile write. However, this is not done
+ * because it could allow further postponement of the write,
+ * delaying progress.)
*/
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java Wed Jul 27 13:33:55 2016 +0000
@@ -35,7 +35,6 @@
package java.util.concurrent.atomic;
-import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
@@ -54,11 +53,18 @@
*/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
- private static final VarHandle VALUE;
+
+ /*
+ * This class intended to be implemented using VarHandles, but there
+ * are unresolved cyclic startup dependencies.
+ */
+ private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final long VALUE;
+
static {
try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- VALUE = l.findVarHandle(AtomicInteger.class, "value", int.class);
+ VALUE = U.objectFieldOffset
+ (AtomicInteger.class.getDeclaredField("value"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -109,7 +115,7 @@
* @since 1.6
*/
public final void lazySet(int newValue) {
- VALUE.setRelease(this, newValue);
+ U.putIntRelease(this, VALUE, newValue);
}
/**
@@ -120,7 +126,7 @@
* @return the previous value
*/
public final int getAndSet(int newValue) {
- return (int)VALUE.getAndSet(this, newValue);
+ return U.getAndSetInt(this, VALUE, newValue);
}
/**
@@ -134,7 +140,7 @@
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expectedValue, int newValue) {
- return VALUE.compareAndSet(this, expectedValue, newValue);
+ return U.compareAndSwapInt(this, VALUE, expectedValue, newValue);
}
/**
@@ -147,7 +153,7 @@
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(int expectedValue, int newValue) {
- return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+ return U.weakCompareAndSwapInt(this, VALUE, expectedValue, newValue);
}
/**
@@ -159,7 +165,7 @@
* @return the previous value
*/
public final int getAndIncrement() {
- return (int)VALUE.getAndAdd(this, 1);
+ return U.getAndAddInt(this, VALUE, 1);
}
/**
@@ -171,7 +177,7 @@
* @return the previous value
*/
public final int getAndDecrement() {
- return (int)VALUE.getAndAdd(this, -1);
+ return U.getAndAddInt(this, VALUE, -1);
}
/**
@@ -182,7 +188,7 @@
* @return the previous value
*/
public final int getAndAdd(int delta) {
- return (int)VALUE.getAndAdd(this, delta);
+ return U.getAndAddInt(this, VALUE, delta);
}
/**
@@ -194,7 +200,7 @@
* @return the updated value
*/
public final int incrementAndGet() {
- return (int)VALUE.addAndGet(this, 1);
+ return U.getAndAddInt(this, VALUE, 1) + 1;
}
/**
@@ -206,7 +212,7 @@
* @return the updated value
*/
public final int decrementAndGet() {
- return (int)VALUE.addAndGet(this, -1);
+ return U.getAndAddInt(this, VALUE, -1) - 1;
}
/**
@@ -217,7 +223,7 @@
* @return the updated value
*/
public final int addAndGet(int delta) {
- return (int)VALUE.addAndGet(this, delta);
+ return U.getAndAddInt(this, VALUE, delta) + delta;
}
/**
@@ -373,7 +379,7 @@
* @since 9
*/
public final int getPlain() {
- return (int)VALUE.get(this);
+ return U.getInt(this, VALUE);
}
/**
@@ -385,7 +391,7 @@
* @since 9
*/
public final void setPlain(int newValue) {
- VALUE.set(this, newValue);
+ U.putInt(this, VALUE, newValue);
}
/**
@@ -396,7 +402,7 @@
* @since 9
*/
public final int getOpaque() {
- return (int)VALUE.getOpaque(this);
+ return U.getIntOpaque(this, VALUE);
}
/**
@@ -407,7 +413,7 @@
* @since 9
*/
public final void setOpaque(int newValue) {
- VALUE.setOpaque(this, newValue);
+ U.putIntOpaque(this, VALUE, newValue);
}
/**
@@ -418,7 +424,7 @@
* @since 9
*/
public final int getAcquire() {
- return (int)VALUE.getAcquire(this);
+ return U.getIntAcquire(this, VALUE);
}
/**
@@ -429,7 +435,7 @@
* @since 9
*/
public final void setRelease(int newValue) {
- VALUE.setRelease(this, newValue);
+ U.putIntRelease(this, VALUE, newValue);
}
/**
@@ -445,7 +451,7 @@
* @since 9
*/
public final int compareAndExchange(int expectedValue, int newValue) {
- return (int)VALUE.compareAndExchange(this, expectedValue, newValue);
+ return U.compareAndExchangeIntVolatile(this, VALUE, expectedValue, newValue);
}
/**
@@ -461,7 +467,7 @@
* @since 9
*/
public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
- return (int)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+ return U.compareAndExchangeIntAcquire(this, VALUE, expectedValue, newValue);
}
/**
@@ -477,7 +483,7 @@
* @since 9
*/
public final int compareAndExchangeRelease(int expectedValue, int newValue) {
- return (int)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+ return U.compareAndExchangeIntRelease(this, VALUE, expectedValue, newValue);
}
/**
@@ -492,7 +498,7 @@
* @since 9
*/
public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
- return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+ return U.weakCompareAndSwapIntVolatile(this, VALUE, expectedValue, newValue);
}
/**
@@ -507,7 +513,7 @@
* @since 9
*/
public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
- return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+ return U.weakCompareAndSwapIntAcquire(this, VALUE, expectedValue, newValue);
}
/**
@@ -522,7 +528,7 @@
* @since 9
*/
public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
- return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+ return U.weakCompareAndSwapIntRelease(this, VALUE, expectedValue, newValue);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java Wed Jul 27 13:33:55 2016 +0000
@@ -35,7 +35,6 @@
package java.util.concurrent.atomic;
-import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
@@ -54,7 +53,6 @@
*/
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;
- private static final VarHandle VALUE;
/**
* Records whether the underlying JVM supports lockless
@@ -70,10 +68,17 @@
*/
private static native boolean VMSupportsCS8();
+ /*
+ * This class intended to be implemented using VarHandles, but there
+ * are unresolved cyclic startup dependencies.
+ */
+ private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+ private static final long VALUE;
+
static {
try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- VALUE = l.findVarHandle(AtomicLong.class, "value", long.class);
+ VALUE = U.objectFieldOffset
+ (AtomicLong.class.getDeclaredField("value"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@@ -113,7 +118,9 @@
* @param newValue the new value
*/
public final void set(long newValue) {
- VALUE.setVolatile(this, newValue);
+ // Use putLongVolatile instead of ordinary volatile store when
+ // using compareAndSwapLong, for sake of some 32bit systems.
+ U.putLongVolatile(this, VALUE, newValue);
}
/**
@@ -124,7 +131,7 @@
* @since 1.6
*/
public final void lazySet(long newValue) {
- VALUE.setRelease(this, newValue);
+ U.putLongRelease(this, VALUE, newValue);
}
/**
@@ -135,7 +142,7 @@
* @return the previous value
*/
public final long getAndSet(long newValue) {
- return (long)VALUE.getAndSet(this, newValue);
+ return U.getAndSetLong(this, VALUE, newValue);
}
/**
@@ -149,7 +156,7 @@
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(long expectedValue, long newValue) {
- return VALUE.compareAndSet(this, expectedValue, newValue);
+ return U.compareAndSwapLong(this, VALUE, expectedValue, newValue);
}
/**
@@ -162,7 +169,7 @@
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(long expectedValue, long newValue) {
- return VALUE.weakCompareAndSet(this, expectedValue, newValue);
+ return U.weakCompareAndSwapLong(this, VALUE, expectedValue, newValue);
}
/**
@@ -174,7 +181,7 @@
* @return the previous value
*/
public final long getAndIncrement() {
- return (long)VALUE.getAndAdd(this, 1L);
+ return U.getAndAddLong(this, VALUE, 1L);
}
/**
@@ -186,7 +193,7 @@
* @return the previous value
*/
public final long getAndDecrement() {
- return (long)VALUE.getAndAdd(this, -1L);
+ return U.getAndAddLong(this, VALUE, -1L);
}
/**
@@ -197,7 +204,7 @@
* @return the previous value
*/
public final long getAndAdd(long delta) {
- return (long)VALUE.getAndAdd(this, delta);
+ return U.getAndAddLong(this, VALUE, delta);
}
/**
@@ -209,7 +216,7 @@
* @return the updated value
*/
public final long incrementAndGet() {
- return (long)VALUE.addAndGet(this, 1L);
+ return U.getAndAddLong(this, VALUE, 1L) + 1L;
}
/**
@@ -221,7 +228,7 @@
* @return the updated value
*/
public final long decrementAndGet() {
- return (long)VALUE.addAndGet(this, -1L);
+ return U.getAndAddLong(this, VALUE, -1L) - 1L;
}
/**
@@ -232,7 +239,7 @@
* @return the updated value
*/
public final long addAndGet(long delta) {
- return (long)VALUE.addAndGet(this, delta);
+ return U.getAndAddLong(this, VALUE, delta) + delta;
}
/**
@@ -386,7 +393,7 @@
* @since 9
*/
public final long getPlain() {
- return (long)VALUE.get(this);
+ return U.getLong(this, VALUE);
}
/**
@@ -398,7 +405,7 @@
* @since 9
*/
public final void setPlain(long newValue) {
- VALUE.set(this, newValue);
+ U.putLong(this, VALUE, newValue);
}
/**
@@ -409,7 +416,7 @@
* @since 9
*/
public final long getOpaque() {
- return (long)VALUE.getOpaque(this);
+ return U.getLongOpaque(this, VALUE);
}
/**
@@ -420,7 +427,7 @@
* @since 9
*/
public final void setOpaque(long newValue) {
- VALUE.setOpaque(this, newValue);
+ U.putLongOpaque(this, VALUE, newValue);
}
/**
@@ -431,7 +438,7 @@
* @since 9
*/
public final long getAcquire() {
- return (long)VALUE.getAcquire(this);
+ return U.getLongAcquire(this, VALUE);
}
/**
@@ -442,7 +449,7 @@
* @since 9
*/
public final void setRelease(long newValue) {
- VALUE.setRelease(this, newValue);
+ U.putLongRelease(this, VALUE, newValue);
}
/**
@@ -458,7 +465,7 @@
* @since 9
*/
public final long compareAndExchange(long expectedValue, long newValue) {
- return (long)VALUE.compareAndExchange(this, expectedValue, newValue);
+ return U.compareAndExchangeLongVolatile(this, VALUE, expectedValue, newValue);
}
/**
@@ -474,7 +481,7 @@
* @since 9
*/
public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
- return (long)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
+ return U.compareAndExchangeLongAcquire(this, VALUE, expectedValue, newValue);
}
/**
@@ -490,7 +497,7 @@
* @since 9
*/
public final long compareAndExchangeRelease(long expectedValue, long newValue) {
- return (long)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
+ return U.compareAndExchangeLongRelease(this, VALUE, expectedValue, newValue);
}
/**
@@ -505,7 +512,7 @@
* @since 9
*/
public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
- return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
+ return U.weakCompareAndSwapLongVolatile(this, VALUE, expectedValue, newValue);
}
/**
@@ -520,7 +527,7 @@
* @since 9
*/
public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
- return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
+ return U.weakCompareAndSwapLongAcquire(this, VALUE, expectedValue, newValue);
}
/**
@@ -535,7 +542,7 @@
* @since 9
*/
public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
- return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
+ return U.weakCompareAndSwapLongRelease(this, VALUE, expectedValue, newValue);
}
}
--- a/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java Wed Jul 27 13:33:55 2016 +0000
@@ -60,7 +60,7 @@
}
}
- private volatile Object value;
+ private volatile V value;
/**
* Creates a new AtomicReference with the given initial value.
@@ -83,9 +83,8 @@
*
* @return the current value
*/
- @SuppressWarnings("unchecked")
public final V get() {
- return (V)value;
+ return value;
}
/**
--- a/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java Wed Jul 27 13:33:55 2016 +0000
@@ -256,8 +256,12 @@
* method validate()) requires stricter ordering rules than apply
* to normal volatile reads (of "state"). To force orderings of
* reads before a validation and the validation itself in those
- * cases where this is not already forced, we use
- * VarHandle.acquireFence.
+ * cases where this is not already forced, we use acquireFence.
+ * Unlike in that paper, we allow writers to use plain writes.
+ * One would not expect reorderings of such writes with the lock
+ * acquisition CAS because there is a "control dependency", but it
+ * is theoretically possible, so we additionally add a
+ * storeStoreFence after lock acquisition CAS.
*
* The memory layout keeps lock state and queue pointers together
* (normally on the same cache line). This usually works well for
@@ -355,6 +359,20 @@
state = ORIGIN;
}
+ private boolean casState(long expectedValue, long newValue) {
+ return STATE.compareAndSet(this, expectedValue, newValue);
+ }
+
+ private long tryWriteLock(long s) {
+ // assert (s & ABITS) == 0L;
+ long next;
+ if (casState(s, next = s | WBIT)) {
+ VarHandle.storeStoreFence();
+ return next;
+ }
+ return 0L;
+ }
+
/**
* Exclusively acquires the lock, blocking if necessary
* until available.
@@ -363,10 +381,8 @@
*/
@ReservedStackAccess
public long writeLock() {
- long s, next; // bypass acquireWrite in fully unlocked case only
- return ((((s = state) & ABITS) == 0L &&
- STATE.compareAndSet(this, s, next = s + WBIT)) ?
- next : acquireWrite(false, 0L));
+ long next;
+ return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
}
/**
@@ -377,10 +393,8 @@
*/
@ReservedStackAccess
public long tryWriteLock() {
- long s, next;
- return ((((s = state) & ABITS) == 0L &&
- STATE.compareAndSet(this, s, next = s + WBIT)) ?
- next : 0L);
+ long s;
+ return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
}
/**
@@ -440,10 +454,13 @@
*/
@ReservedStackAccess
public long readLock() {
- long s = state, next; // bypass acquireRead on common uncontended case
- return ((whead == wtail && (s & ABITS) < RFULL &&
- STATE.compareAndSet(this, s, next = s + RUNIT)) ?
- next : acquireRead(false, 0L));
+ long s, next;
+ // bypass acquireRead on common uncontended case
+ return (whead == wtail
+ && ((s = state) & ABITS) < RFULL
+ && casState(s, next = s + RUNIT))
+ ? next
+ : acquireRead(false, 0L);
}
/**
@@ -457,7 +474,7 @@
long s, m, next;
while ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
- if (STATE.compareAndSet(this, s, next = s + RUNIT))
+ if (casState(s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
@@ -487,7 +504,7 @@
if (!Thread.interrupted()) {
if ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
- if (STATE.compareAndSet(this, s, next = s + RUNIT))
+ if (casState(s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
@@ -514,10 +531,15 @@
* before acquiring the lock
*/
@ReservedStackAccess
- public long readLockInterruptibly() throws InterruptedException {
- long next;
- if (!Thread.interrupted() &&
- (next = acquireRead(true, 0L)) != INTERRUPTED)
+ public long readLockInterruptibly() throws InterruptedException {
+ long s, next;
+ if (!Thread.interrupted()
+ // bypass acquireRead on common uncontended case
+ && ((whead == wtail
+ && ((s = state) & ABITS) < RFULL
+ && casState(s, next = s + RUNIT))
+ ||
+ (next = acquireRead(true, 0L)) != INTERRUPTED))
return next;
throw new InterruptedException();
}
@@ -598,7 +620,7 @@
&& (stamp & RBITS) > 0L
&& ((m = s & RBITS) > 0L)) {
if (m < RFULL) {
- if (STATE.compareAndSet(this, s, s - RUNIT)) {
+ if (casState(s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
@@ -620,7 +642,7 @@
*/
@ReservedStackAccess
public void unlock(long stamp) {
- if ((stamp & WBIT) != 0)
+ if ((stamp & WBIT) != 0L)
unlockWrite(stamp);
else
unlockRead(stamp);
@@ -644,7 +666,7 @@
if ((m = s & ABITS) == 0L) {
if (a != 0L)
break;
- if (STATE.compareAndSet(this, s, next = s + WBIT))
+ if ((next = tryWriteLock(s)) != 0L)
return next;
}
else if (m == WBIT) {
@@ -653,8 +675,10 @@
return stamp;
}
else if (m == RUNIT && a != 0L) {
- if (STATE.compareAndSet(this, s, next = s - RUNIT + WBIT))
+ if (casState(s, next = s - RUNIT + WBIT)) {
+ VarHandle.storeStoreFence();
return next;
+ }
}
else
break;
@@ -688,7 +712,7 @@
else if (a == 0L) {
// optimistic read stamp
if ((s & ABITS) < RFULL) {
- if (STATE.compareAndSet(this, s, next = s + RUNIT))
+ if (casState(s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
@@ -730,7 +754,7 @@
else if ((m = s & ABITS) == 0L) // invalid read stamp
break;
else if (m < RFULL) {
- if (STATE.compareAndSet(this, s, next = s - RUNIT)) {
+ if (casState(s, next = s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return next & SBITS;
@@ -771,7 +795,7 @@
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
if (m < RFULL) {
- if (STATE.compareAndSet(this, s, s - RUNIT)) {
+ if (casState(s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return true;
@@ -940,7 +964,7 @@
long s, m; WNode h;
while ((m = (s = state) & RBITS) > 0L) {
if (m < RFULL) {
- if (STATE.compareAndSet(this, s, s - RUNIT)) {
+ if (casState(s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
@@ -971,7 +995,7 @@
private long tryIncReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
- if (STATE.compareAndSet(this, s, s | RBITS)) {
+ if (casState(s, s | RBITS)) {
++readerOverflow;
STATE.setVolatile(this, s);
return s;
@@ -993,7 +1017,7 @@
private long tryDecReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
- if (STATE.compareAndSet(this, s, s | RBITS)) {
+ if (casState(s, s | RBITS)) {
int r; long next;
if ((r = readerOverflow) > 0) {
readerOverflow = r - 1;
@@ -1047,7 +1071,7 @@
for (int spins = -1;;) { // spin while enqueuing
long m, s, ns;
if ((m = (s = state) & ABITS) == 0L) {
- if (STATE.compareAndSet(this, s, ns = s + WBIT))
+ if ((ns = tryWriteLock(s)) != 0L)
return ns;
}
else if (spins < 0)
@@ -1082,7 +1106,7 @@
for (int k = spins; k > 0; --k) { // spin at head
long s, ns;
if (((s = state) & ABITS) == 0L) {
- if (STATE.compareAndSet(this, s, ns = s + WBIT)) {
+ if ((ns = tryWriteLock(s)) != 0L) {
whead = node;
node.prev = null;
if (wasInterrupted)
@@ -1158,7 +1182,7 @@
if ((h = whead) == (p = wtail)) {
for (long m, s, ns;;) {
if ((m = (s = state) & ABITS) < RFULL ?
- STATE.compareAndSet(this, s, ns = s + RUNIT) :
+ casState(s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
if (wasInterrupted)
Thread.currentThread().interrupt();
@@ -1208,7 +1232,7 @@
long m, s, ns;
do {
if ((m = (s = state) & ABITS) < RFULL ?
- STATE.compareAndSet(this, s, ns = s + RUNIT) :
+ casState(s, ns = s + RUNIT) :
(m < WBIT &&
(ns = tryIncReaderOverflow(s)) != 0L)) {
if (wasInterrupted)
@@ -1260,7 +1284,7 @@
for (int k = spins;;) { // spin at head
long m, s, ns;
if ((m = (s = state) & ABITS) < RFULL ?
- STATE.compareAndSet(this, s, ns = s + RUNIT) :
+ casState(s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
WNode c; Thread w;
whead = node;
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipEntry.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipEntry.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -568,9 +568,18 @@
int pos = off + 4; // reserved 4 bytes
if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24)
break;
- mtime = winTimeToFileTime(get64(extra, pos + 4));
- atime = winTimeToFileTime(get64(extra, pos + 12));
- ctime = winTimeToFileTime(get64(extra, pos + 20));
+ long wtime = get64(extra, pos + 4);
+ if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+ mtime = winTimeToFileTime(wtime);
+ }
+ wtime = get64(extra, pos + 12);
+ if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+ atime = winTimeToFileTime(wtime);
+ }
+ wtime = get64(extra, pos + 20);
+ if (wtime != WINDOWS_TIME_NOT_AVAILABLE) {
+ ctime = winTimeToFileTime(wtime);
+ }
break;
case EXTID_EXTT:
int flag = Byte.toUnsignedInt(extra[off]);
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -421,22 +421,36 @@
byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
- int elenEXTT = 0; // info-zip extended timestamp
+ int elenEXTT = 0; // info-zip extended timestamp
int flagEXTT = 0;
+ long umtime = -1;
+ long uatime = -1;
+ long uctime = -1;
if (e.mtime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LMT;
+ umtime = fileTimeToUnixTime(e.mtime);
}
if (e.atime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAG_LAT;
+ uatime = fileTimeToUnixTime(e.atime);
}
if (e.ctime != null) {
elenEXTT += 4;
flagEXTT |= EXTT_FLAT_CT;
+ uctime = fileTimeToUnixTime(e.ctime);
}
- if (flagEXTT != 0)
- elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
+ if (flagEXTT != 0) {
+ // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+ if (umtime > UPPER_UNIXTIME_BOUND ||
+ uatime > UPPER_UNIXTIME_BOUND ||
+ uctime > UPPER_UNIXTIME_BOUND) {
+ elen += 36; // NTFS time, total 36 bytes
+ } else {
+ elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
+ }
+ }
writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
@@ -446,15 +460,31 @@
writeLong(e.csize);
}
if (flagEXTT != 0) {
- writeShort(EXTID_EXTT);
- writeShort(elenEXTT + 1); // flag + data
- writeByte(flagEXTT);
- if (e.mtime != null)
- writeInt(fileTimeToUnixTime(e.mtime));
- if (e.atime != null)
- writeInt(fileTimeToUnixTime(e.atime));
- if (e.ctime != null)
- writeInt(fileTimeToUnixTime(e.ctime));
+ if (umtime > UPPER_UNIXTIME_BOUND ||
+ uatime > UPPER_UNIXTIME_BOUND ||
+ uctime > UPPER_UNIXTIME_BOUND) {
+ writeShort(EXTID_NTFS); // id
+ writeShort(32); // data size
+ writeInt(0); // reserved
+ writeShort(0x0001); // NTFS attr tag
+ writeShort(24);
+ writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.mtime));
+ writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.atime));
+ writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.ctime));
+ } else {
+ writeShort(EXTID_EXTT);
+ writeShort(elenEXTT + 1); // flag + data
+ writeByte(flagEXTT);
+ if (e.mtime != null)
+ writeInt(umtime);
+ if (e.atime != null)
+ writeInt(uatime);
+ if (e.ctime != null)
+ writeInt(uctime);
+ }
}
writeExtra(e.extra);
locoff = written;
@@ -528,18 +558,30 @@
// cen info-zip extended timestamp only outputs mtime
// but set the flag for a/ctime, if present in loc
int flagEXTT = 0;
+ long umtime = -1;
+ long uatime = -1;
+ long uctime = -1;
if (e.mtime != null) {
- elen += 4; // + mtime(4)
flagEXTT |= EXTT_FLAG_LMT;
+ umtime = fileTimeToUnixTime(e.mtime);
}
if (e.atime != null) {
flagEXTT |= EXTT_FLAG_LAT;
+ uatime = fileTimeToUnixTime(e.atime);
}
if (e.ctime != null) {
flagEXTT |= EXTT_FLAT_CT;
+ uctime = fileTimeToUnixTime(e.ctime);
}
if (flagEXTT != 0) {
- elen += 5; // headid + sz + flag
+ // to use ntfs time if any m/a/ctime is beyond unixtime upper bound
+ if (umtime > UPPER_UNIXTIME_BOUND ||
+ uatime > UPPER_UNIXTIME_BOUND ||
+ uctime > UPPER_UNIXTIME_BOUND) {
+ elen += 36; // NTFS time total 36 bytes
+ } else {
+ elen += 9; // headid(2) + sz(2) + flag(1) + mtime (4)
+ }
}
writeShort(elen);
byte[] commentBytes;
@@ -568,14 +610,30 @@
writeLong(xentry.offset);
}
if (flagEXTT != 0) {
- writeShort(EXTID_EXTT);
- if (e.mtime != null) {
- writeShort(5); // flag + mtime
- writeByte(flagEXTT);
- writeInt(fileTimeToUnixTime(e.mtime));
+ if (umtime > UPPER_UNIXTIME_BOUND ||
+ uatime > UPPER_UNIXTIME_BOUND ||
+ uctime > UPPER_UNIXTIME_BOUND) {
+ writeShort(EXTID_NTFS); // id
+ writeShort(32); // data size
+ writeInt(0); // reserved
+ writeShort(0x0001); // NTFS attr tag
+ writeShort(24);
+ writeLong(e.mtime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.mtime));
+ writeLong(e.atime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.atime));
+ writeLong(e.ctime == null ? WINDOWS_TIME_NOT_AVAILABLE
+ : fileTimeToWinTime(e.ctime));
} else {
- writeShort(1); // flag only
- writeByte(flagEXTT);
+ writeShort(EXTID_EXTT);
+ if (e.mtime != null) {
+ writeShort(5); // flag + mtime
+ writeByte(flagEXTT);
+ writeInt(umtime);
+ } else {
+ writeShort(1); // flag only
+ writeByte(flagEXTT);
+ }
}
}
writeExtra(e.extra);
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,9 @@
// used to adjust values between Windows and java epoch
private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
+ // used to indicate the corresponding windows time is not available
+ public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
+
/**
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
*/
@@ -54,6 +57,11 @@
}
/**
+ * The upper bound of the 32-bit unix time, the "year 2038 problem".
+ */
+ public static final long UPPER_UNIXTIME_BOUND = 0x7fffffff;
+
+ /**
* Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
*/
public static final FileTime unixTimeToFileTime(long utime) {
--- a/jdk/src/java.base/share/classes/module-info.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/share/classes/module-info.java Wed Jul 27 13:33:55 2016 +0000
@@ -149,7 +149,6 @@
exports jdk.internal.module to
java.instrument,
java.management,
- java.xml,
jdk.dynalink,
jdk.jartool,
jdk.jlink;
@@ -309,4 +308,3 @@
provides java.nio.file.spi.FileSystemProvider with
jdk.internal.jrtfs.JrtFileSystemProvider;
}
-
--- a/jdk/src/java.base/unix/native/libjava/java_props_md.c Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.base/unix/native/libjava/java_props_md.c Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -68,11 +68,6 @@
#endif
#endif /* !_ALLBSD_SOURCE */
-#ifdef JAVASE_EMBEDDED
-#include <dlfcn.h>
-#include <sys/stat.h>
-#endif
-
/* Take an array of string pairs (map of key->value) and a string (key).
* Examine each pair in the map to see if the first string (key) matches the
* string. If so, store the second string of the pair (value) in the value and
@@ -350,36 +345,6 @@
return 1;
}
-#ifdef JAVASE_EMBEDDED
-/* Determine the default embedded toolkit based on whether libawt_xawt
- * exists in the JRE. This can still be overridden by -Dawt.toolkit=XXX
- */
-static char* getEmbeddedToolkit() {
- Dl_info dlinfo;
- char buf[MAXPATHLEN];
- int32_t len;
- char *p;
- struct stat statbuf;
-
- /* Get address of this library and the directory containing it. */
- dladdr((void *)getEmbeddedToolkit, &dlinfo);
- realpath((char *)dlinfo.dli_fname, buf);
- len = strlen(buf);
- p = strrchr(buf, '/');
- /* Default AWT Toolkit on Linux and Solaris is XAWT (libawt_xawt.so). */
- strncpy(p, "/libawt_xawt.so", MAXPATHLEN-len-1);
- /* Check if it exists */
- if (stat(buf, &statbuf) == -1 && errno == ENOENT) {
- /* No - this is a reduced-headless-jre so use special HToolkit */
- return "sun.awt.HToolkit";
- }
- else {
- /* Yes - this is a headful JRE so fallback to SE defaults */
- return NULL;
- }
-}
-#endif
-
/* This function gets called very early, before VM_CALLS are setup.
* Do not use any of the VM_CALLS entries!!!
*/
@@ -424,10 +389,6 @@
sprops.awt_headless = isInAquaSession() ? NULL : "true";
#else
sprops.graphics_env = "sun.awt.X11GraphicsEnvironment";
-#ifdef JAVASE_EMBEDDED
- sprops.awt_toolkit = getEmbeddedToolkit();
- if (sprops.awt_toolkit == NULL) // default as below
-#endif
sprops.awt_toolkit = "sun.awt.X11.XToolkit";
#endif
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/xawt/XToolkit.c Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -122,11 +122,7 @@
JNIEXPORT jlong JNICALL Java_sun_awt_X11_XToolkit_getTrayIconDisplayTimeout
(JNIEnv *env, jclass clazz)
{
-#ifndef JAVASE_EMBEDDED
return (jlong) 2000;
-#else
- return (jlong) 10000;
-#endif
}
/*
@@ -369,12 +365,7 @@
#define AWT_READPIPE (awt_pipe_fds[0])
#define AWT_WRITEPIPE (awt_pipe_fds[1])
-#ifdef JAVASE_EMBEDDED
- #define DEF_AWT_MAX_POLL_TIMEOUT ((uint32_t)4000000000) /* milliseconds */
-#else
- #define DEF_AWT_MAX_POLL_TIMEOUT ((uint32_t)500) /* milliseconds */
-#endif
-
+#define DEF_AWT_MAX_POLL_TIMEOUT ((uint32_t)500) /* milliseconds */
#define DEF_AWT_FLUSH_TIMEOUT ((uint32_t)100) /* milliseconds */
#define AWT_MIN_POLL_TIMEOUT ((uint32_t)0) /* milliseconds */
@@ -391,11 +382,7 @@
// Static fields
-#ifdef JAVASE_EMBEDDED
- static int awt_poll_alg = AWT_POLL_AGING_FAST;
-#else
- static int awt_poll_alg = AWT_POLL_AGING_SLOW;
-#endif
+static int awt_poll_alg = AWT_POLL_AGING_SLOW;
static uint32_t AWT_FLUSH_TIMEOUT = DEF_AWT_FLUSH_TIMEOUT; /* milliseconds */
static uint32_t AWT_MAX_POLL_TIMEOUT = DEF_AWT_MAX_POLL_TIMEOUT; /* milliseconds */
--- a/jdk/src/java.desktop/unix/native/libjawt/jawt.c Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/src/java.desktop/unix/native/libjawt/jawt.c Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,10 +39,6 @@
*/
JNIEXPORT jboolean JNICALL JAWT_GetAWT(JNIEnv* env, JAWT* awt)
{
-#if defined(JAVASE_EMBEDDED) && defined(HEADLESS)
- /* there are no AWT libs available at all */
- return JNI_FALSE;
-#else
if (awt == NULL) {
return JNI_FALSE;
}
@@ -62,5 +58,4 @@
}
return JNI_TRUE;
-#endif
}
--- a/jdk/test/java/net/URLPermission/URLPermissionTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/net/URLPermission/URLPermissionTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -26,7 +26,7 @@
/**
* @test
- * @bug 8010464 8027570 8027687 8029354 8114860 8071660
+ * @bug 8010464 8027570 8027687 8029354 8114860 8071660 8161291
*/
public class URLPermissionTest {
@@ -355,15 +355,16 @@
};
static Test[] actionsStringTest = {
- actionstest("", ""),
+ actionstest("", ":"),
+ actionstest(":", ":"),
actionstest(":X-Bar", ":X-Bar"),
- actionstest("GET", "GET"),
- actionstest("get", "GET"),
- actionstest("GET,POST", "GET,POST"),
- actionstest("GET,post", "GET,POST"),
- actionstest("get,post", "GET,POST"),
- actionstest("get,post,DELETE", "DELETE,GET,POST"),
- actionstest("GET,POST:", "GET,POST"),
+ actionstest("GET", "GET:"),
+ actionstest("get", "GET:"),
+ actionstest("GET,POST", "GET,POST:"),
+ actionstest("GET,post", "GET,POST:"),
+ actionstest("get,post", "GET,POST:"),
+ actionstest("get,post,DELETE", "DELETE,GET,POST:"),
+ actionstest("GET,POST:", "GET,POST:"),
actionstest("GET:X-Foo,X-bar", "GET:X-Bar,X-Foo"),
actionstest("GET,POST,DELETE:X-Bar,X-Foo,X-Bar,Y-Foo", "DELETE,GET,POST:X-Bar,X-Bar,X-Foo,Y-Foo")
};
--- a/jdk/test/java/security/Provider/SecurityProviderModularTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/security/Provider/SecurityProviderModularTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -63,8 +63,7 @@
"TestSecurityProviderClient.java");
private static final String C_PKG = "client";
private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
- private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
- + C_PKG + AUTO + JAR_EXTN;
+ private static final String MCN_JAR_NAME = MODULAR + C_PKG + "N" + JAR_EXTN;
private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
private static final Path BUILD_DIR = Paths.get(".").resolve("build");
@@ -72,7 +71,7 @@
private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
S_PKG + DESCRIPTOR);
- private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+ private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
@@ -88,8 +87,7 @@
private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
- private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
- .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+ private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
private static final String MAIN = C_PKG + ".TestSecurityProviderClient";
private static final String S_INTERFACE = "java.security.Provider";
@@ -102,8 +100,6 @@
private static final boolean WITH_S_DESCR = true;
private static final boolean WITHOUT_S_DESCR = false;
- private static final String CLASS_NOT_FOUND_MSG = "NoClassDefFoundError:"
- + " provider/TestSecurityProvider";
private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test"
+ " Security Provider";
private static final String CAN_NOT_ACCESS_MSG = "cannot access class";
@@ -126,10 +122,10 @@
boolean useCLoader = CLASS_LOADER.equals(mechanism);
boolean useSLoader = SERVICE_LOADER.equals(mechanism);
String[] args = new String[]{mechanism};
- //PARAMETER ORDERS -
- //client Module Type, Service Module Type,
- //Service META Descriptor Required,
- //Expected Failure message, mech used to find the provider
+ // PARAMETER ORDERS -
+ // Client Module Type, Service Module Type,
+ // If Service META Descriptor Required,
+ // Expected Failure message, mechanism used to find the provider
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
@@ -138,7 +134,8 @@
WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
: NO_FAILURE), args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
+ : PROVIDER_NOT_FOUND_MSG), args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG
: NO_FAILURE), args));
@@ -150,11 +147,12 @@
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
- WITH_S_DESCR, NO_FAILURE, args));
+ WITHOUT_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR,
+ (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
@@ -168,7 +166,8 @@
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR,
+ (useCLoader) ? NO_FAILURE : PROVIDER_NOT_FOUND_MSG, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
@@ -191,22 +190,23 @@
done &= CompilerUtils.compile(S_SRC, S_BUILD_DIR);
done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
- //Generate regular/modular jars with(out) META-INF
- //Service descriptor
+ // Generate modular/regular jars with(out) META-INF
+ // service descriptor
generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
S_WITH_META_DESCR_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
S_WITH_META_DESCR_BUILD_DIR, false);
- //Generate regular/modular(depends on explicit/auto Service)
- //jars for client
- done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR, "-cp",
+ // Compile client source codes.
+ done &= CompilerUtils.compile(C_SRC, C_BLD_DIR, "-cp",
S_JAR.toFile().getCanonicalPath());
- generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
- generateJar(false, MODULE_TYPE.EXPLICIT,
- MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
- generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+ // Generate modular client jar with explicit dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+ // Generate modular client jar without any dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+ // Generate regular client jar
+ generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
System.out.format("%nArtifacts generated successfully? %s", done);
if (!done) {
throw new RuntimeException("Artifacts generation failed");
@@ -244,10 +244,9 @@
OutputAnalyzer output = null;
try {
-
- //For automated/explicit module type copy the corresponding
- //jars to module base folder, which will be considered as
- //module base path during execution.
+ // For automated/explicit module types, copy the corresponding
+ // jars to module base folder, which will be considered as
+ // module base path during execution.
if (!(cModuleType == MODULE_TYPE.UNNAMED
&& sModuletype == MODULE_TYPE.UNNAMED)) {
copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
@@ -262,15 +261,14 @@
String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
sJarPath);
- Map<String, String> VM_ARGS = getVMArgs(sModuletype, args);
+ Map<String, String> vmArgs = getVMArgs(sModuletype,
+ getModuleName(sModuletype, sJarPath, S_PKG), args);
output = ProcessTools.executeTestJava(
- getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+ getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
args)).outputTo(System.out).errorTo(System.out);
} finally {
- //clean module path so that the modulepath can hold only
- //the required jars for next run.
+ // Clean module path to hold required jars for next run.
cleanModuleBasePath(M_BASE_PATH);
- System.out.println("--------------------------------------------");
}
return output;
}
@@ -297,11 +295,12 @@
}
}
} else {
+ // Choose corresponding client jar to use dependent module
if (moduleType == MODULE_TYPE.EXPLICIT) {
if (dependsOnServiceModule) {
return MC_JAR;
} else {
- return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+ return MCN_JAR;
}
} else {
return C_JAR;
@@ -313,13 +312,16 @@
* VM argument required for the test.
*/
private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
- String... args) throws IOException {
- final Map<String, String> VM_ARGS = new LinkedHashMap<>();
- VM_ARGS.put("-Duser.language=", "en");
- VM_ARGS.put("-Duser.region=", "US");
- //If mechanism selected to find the provider through
- //Security.getProvider() then use providerName/ProviderClassName based
- //on modular/regular provider jar in security configuration file.
+ String addModName, String... args) throws IOException {
+ final Map<String, String> vmArgs = new LinkedHashMap<>();
+ vmArgs.put("-Duser.language=", "en");
+ vmArgs.put("-Duser.region=", "US");
+ if (addModName != null && sModuletype == MODULE_TYPE.AUTO) {
+ vmArgs.put("-addmods ", addModName);
+ }
+ // If mechanism selected to find the provider through
+ // Security.getProvider() then use providerName/ProviderClassName based
+ // on modular/regular provider jar in security configuration file.
if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) {
if (sModuletype == MODULE_TYPE.UNNAMED) {
Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL)
@@ -328,10 +330,10 @@
Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST"
.getBytes());
}
- VM_ARGS.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
+ vmArgs.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile()
.getCanonicalPath());
}
- return VM_ARGS;
+ return vmArgs;
}
}
--- a/jdk/test/java/security/modules/ModularTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/security/modules/ModularTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -82,7 +82,7 @@
String testName = new StringJoiner("_").add(cModuleType.toString())
.add(sModuletype.toString()).add(
- (addMetaDesc) ? "DESCRIPTOR" : "NO_DESCRIPTOR")
+ (addMetaDesc) ? "WITH_SERVICE" : "NO_SERVICE")
.toString();
System.out.format("%nStarting Test case: '%s'", testName);
@@ -165,10 +165,12 @@
if (moduleType == MODULE_TYPE.EXPLICIT) {
System.out.format(" %nGenerating ModuleDescriptor object");
builder = new Builder(moduleName).exports(pkg);
- if (isService) {
+ if (isService && serviceInterface != null && serviceImpl != null) {
builder.provides(serviceInterface, serviceImpl);
} else {
- builder.uses(serviceInterface);
+ if (serviceInterface != null) {
+ builder.uses(serviceInterface);
+ }
if (depends) {
builder.requires(serviceModuleName);
}
@@ -261,7 +263,7 @@
String jarName = jarPath.toFile().getName();
return (moduleType == MODULE_TYPE.EXPLICIT) ? mName
: ((moduleType == MODULE_TYPE.AUTO) ? jarName.substring(0,
- jarName.indexOf(JAR_EXTN)) : "");
+ jarName.indexOf(JAR_EXTN)) : null);
}
/**
--- a/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/concurrent/BlockingQueue/PollMemoryLeak.java Wed Jul 27 13:33:55 2016 +0000
@@ -42,6 +42,7 @@
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.SynchronousQueue;
@@ -50,9 +51,11 @@
public class PollMemoryLeak {
public static void main(String[] args) throws InterruptedException {
final BlockingQueue[] qs = {
+ new LinkedBlockingDeque(10),
new LinkedBlockingQueue(10),
new LinkedTransferQueue(),
new ArrayBlockingQueue(10),
+ new ArrayBlockingQueue(10, true),
new SynchronousQueue(),
new SynchronousQueue(true),
};
--- a/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/concurrent/tck/CompletableFutureTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -4269,12 +4269,11 @@
}
}
- /*
- * Tests below currently fail in stress mode due to memory retention.
- * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest tck
+ /**
+ * Reproduction recipe for:
+ * 8160402: Garbage retention with CompletableFuture.anyOf
+ * cvs update -D '2016-05-01' ./src/main/java/util/concurrent/CompletableFuture.java && ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testAnyOfGarbageRetention tck; cvs update -A
*/
-
- /** Checks for garbage retention with anyOf. */
public void testAnyOfGarbageRetention() throws Throwable {
for (Integer v : new Integer[] { 1, null })
{
@@ -4288,7 +4287,12 @@
checkCompletedNormally(CompletableFuture.anyOf(fs), v);
}}
- /** Checks for garbage retention with allOf. */
+ /**
+ * Checks for garbage retention with allOf.
+ *
+ * As of 2016-07, fails with OOME:
+ * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testCancelledAllOfGarbageRetention tck
+ */
public void testCancelledAllOfGarbageRetention() throws Throwable {
final int n = expensiveTests ? 100_000 : 10;
CompletableFuture<Integer>[] fs
@@ -4299,6 +4303,21 @@
assertTrue(CompletableFuture.allOf(fs).cancel(false));
}
+ /**
+ * Checks for garbage retention when a dependent future is
+ * cancelled and garbage-collected.
+ * 8161600: Garbage retention when source CompletableFutures are never completed
+ *
+ * As of 2016-07, fails with OOME:
+ * ant -Dvmoptions=-Xmx8m -Djsr166.expensiveTests=true -Djsr166.tckTestClass=CompletableFutureTest -Djsr166.methodFilter=testCancelledGarbageRetention tck
+ */
+ public void testCancelledGarbageRetention() throws Throwable {
+ final int n = expensiveTests ? 100_000 : 10;
+ CompletableFuture<Integer> neverCompleted = new CompletableFuture<>();
+ for (int i = 0; i < n; i++)
+ assertTrue(neverCompleted.thenRun(() -> {}).cancel(true));
+ }
+
// static <U> U join(CompletionStage<U> stage) {
// CompletableFuture<U> f = new CompletableFuture<>();
// stage.whenComplete((v, ex) -> {
--- a/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/concurrent/tck/ConcurrentHashMapTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -43,6 +43,8 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -830,4 +832,47 @@
}
}
+ /**
+ * Tests performance of removeAll when the other collection is much smaller.
+ * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testRemoveAll_performance -Djsr166.expensiveTests=true tck
+ */
+ public void testRemoveAll_performance() {
+ final int mapSize = expensiveTests ? 1_000_000 : 100;
+ final int iterations = expensiveTests ? 500 : 2;
+ final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+ for (int i = 0; i < mapSize; i++)
+ map.put(i, i);
+ Set<Integer> keySet = map.keySet();
+ Collection<Integer> removeMe = Arrays.asList(new Integer[] { -99, -86 });
+ for (int i = 0; i < iterations; i++)
+ assertFalse(keySet.removeAll(removeMe));
+ assertEquals(mapSize, map.size());
+ }
+
+ /**
+ * Tests performance of computeIfAbsent when the element is present.
+ * See JDK-8161372
+ * ant -Djsr166.tckTestClass=ConcurrentHashMapTest -Djsr166.methodFilter=testcomputeIfAbsent_performance -Djsr166.expensiveTests=true tck
+ */
+ public void testcomputeIfAbsent_performance() {
+ final int mapSize = 20;
+ final int iterations = expensiveTests ? (1 << 23) : mapSize * 2;
+ final int threads = expensiveTests ? 10 : 2;
+ final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
+ for (int i = 0; i < mapSize; i++)
+ map.put(i, i);
+ final ExecutorService pool = Executors.newFixedThreadPool(2);
+ try (PoolCleaner cleaner = cleaner(pool)) {
+ Runnable r = new CheckedRunnable() {
+ public void realRun() {
+ int result = 0;
+ for (int i = 0; i < iterations; i++)
+ result += map.computeIfAbsent(i % mapSize, (k) -> k + k);
+ if (result == -42) throw new Error();
+ }};
+ for (int i = 0; i < threads; i++)
+ pool.execute(r);
+ }
+ }
+
}
--- a/jdk/test/java/util/concurrent/tck/StampedLockTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/concurrent/tck/StampedLockTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -32,11 +32,18 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
+import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.StampedLock;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -1078,4 +1085,121 @@
assertThrows(IllegalMonitorStateException.class, actions);
}
+ static long writeLockInterruptiblyUninterrupted(StampedLock sl) {
+ try { return sl.writeLockInterruptibly(); }
+ catch (InterruptedException ex) { throw new AssertionError(ex); }
+ }
+
+ static long tryWriteLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
+ try { return sl.tryWriteLock(time, unit); }
+ catch (InterruptedException ex) { throw new AssertionError(ex); }
+ }
+
+ static long readLockInterruptiblyUninterrupted(StampedLock sl) {
+ try { return sl.readLockInterruptibly(); }
+ catch (InterruptedException ex) { throw new AssertionError(ex); }
+ }
+
+ static long tryReadLockUninterrupted(StampedLock sl, long time, TimeUnit unit) {
+ try { return sl.tryReadLock(time, unit); }
+ catch (InterruptedException ex) { throw new AssertionError(ex); }
+ }
+
+ /**
+ * Invalid write stamps result in IllegalMonitorStateException
+ */
+ public void testInvalidWriteStampsThrowIllegalMonitorStateException() {
+ List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
+ writeLockers.add((sl) -> sl.writeLock());
+ writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
+
+ List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
+ writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
+ writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
+ writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
+ writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+ List<Consumer<StampedLock>> mutaters = new ArrayList<>();
+ mutaters.add((sl) -> {});
+ mutaters.add((sl) -> sl.readLock());
+ for (Function<StampedLock, Long> writeLocker : writeLockers)
+ mutaters.add((sl) -> writeLocker.apply(sl));
+
+ for (Function<StampedLock, Long> writeLocker : writeLockers)
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers)
+ for (Consumer<StampedLock> mutater : mutaters) {
+ final StampedLock sl = new StampedLock();
+ final long stamp = writeLocker.apply(sl);
+ assertTrue(stamp != 0L);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlockRead(stamp));
+ writeUnlocker.accept(sl, stamp);
+ mutater.accept(sl);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlock(stamp),
+ () -> sl.unlockRead(stamp),
+ () -> sl.unlockWrite(stamp));
+ }
+ }
+
+ /**
+ * Invalid read stamps result in IllegalMonitorStateException
+ */
+ public void testInvalidReadStampsThrowIllegalMonitorStateException() {
+ List<Function<StampedLock, Long>> readLockers = new ArrayList<>();
+ readLockers.add((sl) -> sl.readLock());
+ readLockers.add((sl) -> readLockInterruptiblyUninterrupted(sl));
+ readLockers.add((sl) -> tryReadLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+ readLockers.add((sl) -> tryReadLockUninterrupted(sl, 0, DAYS));
+
+ List<BiConsumer<StampedLock, Long>> readUnlockers = new ArrayList<>();
+ readUnlockers.add((sl, stamp) -> sl.unlockRead(stamp));
+ readUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockRead()));
+ readUnlockers.add((sl, stamp) -> sl.asReadLock().unlock());
+ readUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+ List<Function<StampedLock, Long>> writeLockers = new ArrayList<>();
+ writeLockers.add((sl) -> sl.writeLock());
+ writeLockers.add((sl) -> writeLockInterruptiblyUninterrupted(sl));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, Long.MIN_VALUE, DAYS));
+ writeLockers.add((sl) -> tryWriteLockUninterrupted(sl, 0, DAYS));
+
+ List<BiConsumer<StampedLock, Long>> writeUnlockers = new ArrayList<>();
+ writeUnlockers.add((sl, stamp) -> sl.unlockWrite(stamp));
+ writeUnlockers.add((sl, stamp) -> assertTrue(sl.tryUnlockWrite()));
+ writeUnlockers.add((sl, stamp) -> sl.asWriteLock().unlock());
+ writeUnlockers.add((sl, stamp) -> sl.unlock(stamp));
+
+
+ for (Function<StampedLock, Long> readLocker : readLockers)
+ for (BiConsumer<StampedLock, Long> readUnlocker : readUnlockers)
+ for (Function<StampedLock, Long> writeLocker : writeLockers)
+ for (BiConsumer<StampedLock, Long> writeUnlocker : writeUnlockers) {
+ final StampedLock sl = new StampedLock();
+ final long stamp = readLocker.apply(sl);
+ assertTrue(stamp != 0L);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlockWrite(stamp));
+ readUnlocker.accept(sl, stamp);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlock(stamp),
+ () -> sl.unlockRead(stamp),
+ () -> sl.unlockWrite(stamp));
+ final long writeStamp = writeLocker.apply(sl);
+ assertTrue(writeStamp != 0L);
+ assertTrue(writeStamp != stamp);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlock(stamp),
+ () -> sl.unlockRead(stamp),
+ () -> sl.unlockWrite(stamp));
+ writeUnlocker.accept(sl, writeStamp);
+ assertThrows(IllegalMonitorStateException.class,
+ () -> sl.unlock(stamp),
+ () -> sl.unlockRead(stamp),
+ () -> sl.unlockWrite(stamp));
+ }
+ }
+
}
--- a/jdk/test/java/util/zip/TestExtraTime.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/zip/TestExtraTime.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/**
* @test
- * @bug 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914
+ * @bug 4759491 6303183 7012868 8015666 8023713 8068790 8076641 8075526 8130914 8161942
* @summary Test ZOS and ZIS timestamp in extra field correctly
*/
@@ -32,6 +32,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
+import java.time.Instant;
import java.util.Arrays;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;
@@ -40,37 +41,52 @@
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
+
+
public class TestExtraTime {
public static void main(String[] args) throws Throwable{
File src = new File(System.getProperty("test.src", "."), "TestExtraTime.java");
- if (src.exists()) {
+ if (!src.exists()) {
+ return;
+ }
+
+ TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
+
+ for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
+
+ // ms-dos 1980 epoch problem
+ test0(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
+ // negative epoch time
+ test0(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
+
long time = src.lastModified();
- FileTime mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
- FileTime atime = FileTime.from(time + 300000, TimeUnit.MILLISECONDS);
- FileTime ctime = FileTime.from(time - 300000, TimeUnit.MILLISECONDS);
- TimeZone tz = TimeZone.getTimeZone("Asia/Shanghai");
-
- for (byte[] extra : new byte[][] { null, new byte[] {1, 2, 3}}) {
- test(mtime, null, null, null, extra);
+ test(FileTime.from(time, TimeUnit.MILLISECONDS),
+ FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
+ FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
+ tz, extra);
- // ms-dos 1980 epoch problem
- test(FileTime.from(10, TimeUnit.MILLISECONDS), null, null, null, extra);
- // negative epoch time
- test(FileTime.from(-100, TimeUnit.DAYS), null, null, null, extra);
-
- // non-default tz
- test(mtime, null, null, tz, extra);
+ // now
+ time = Instant.now().toEpochMilli();
+ test(FileTime.from(time, TimeUnit.MILLISECONDS),
+ FileTime.from(time + 300000, TimeUnit.MILLISECONDS),
+ FileTime.from(time - 300000, TimeUnit.MILLISECONDS),
+ tz, extra);
- test(mtime, atime, null, null, extra);
- test(mtime, null, ctime, null, extra);
- test(mtime, atime, ctime, null, extra);
+ // unix 2038
+ time = 0x80000000L;
+ test(FileTime.from(time, TimeUnit.SECONDS),
+ FileTime.from(time, TimeUnit.SECONDS),
+ FileTime.from(time, TimeUnit.SECONDS),
+ tz, extra);
- test(mtime, atime, null, tz, extra);
- test(mtime, null, ctime, tz, extra);
- test(mtime, atime, ctime, tz, extra);
- }
+ // mtime < unix 2038
+ time = 0x7fffffffL;
+ test(FileTime.from(time, TimeUnit.SECONDS),
+ FileTime.from(time + 30000, TimeUnit.SECONDS),
+ FileTime.from(time + 30000, TimeUnit.SECONDS),
+ tz, extra);
}
testNullHandling();
@@ -80,6 +96,18 @@
static void test(FileTime mtime, FileTime atime, FileTime ctime,
TimeZone tz, byte[] extra) throws Throwable {
+ test0(mtime, null, null, null, extra);
+ test0(mtime, null, null, tz, extra); // non-default tz
+ test0(mtime, atime, null, null, extra);
+ test0(mtime, null, ctime, null, extra);
+ test0(mtime, atime, ctime, null, extra);
+ test0(mtime, atime, null, tz, extra);
+ test0(mtime, null, ctime, tz, extra);
+ test0(mtime, atime, ctime, tz, extra);
+ }
+
+ static void test0(FileTime mtime, FileTime atime, FileTime ctime,
+ TimeZone tz, byte[] extra) throws Throwable {
System.out.printf("--------------------%nTesting: [%s]/[%s]/[%s]%n",
mtime, atime, ctime);
TimeZone tz0 = TimeZone.getDefault();
@@ -120,13 +148,14 @@
Path zpath = Paths.get(System.getProperty("test.dir", "."),
"TestExtraTime.zip");
Files.copy(new ByteArrayInputStream(baos.toByteArray()), zpath);
- ZipFile zf = new ZipFile(zpath.toFile());
- ze = zf.getEntry("TestExtraTime.java");
- // ZipFile read entry from cen, which does not have a/ctime,
- // for now.
- check(mtime, null, null, ze, extra);
- zf.close();
- Files.delete(zpath);
+ try (ZipFile zf = new ZipFile(zpath.toFile())) {
+ ze = zf.getEntry("TestExtraTime.java");
+ // ZipFile read entry from cen, which does not have a/ctime,
+ // for now.
+ check(mtime, null, null, ze, extra);
+ } finally {
+ Files.delete(zpath);
+ }
}
static void check(FileTime mtime, FileTime atime, FileTime ctime,
--- a/jdk/test/java/util/zip/TestLocalTime.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/java/util/zip/TestLocalTime.java Wed Jul 27 13:33:55 2016 +0000
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 8075526 8135108 8155616
+ * @bug 8075526 8135108 8155616 8161942
* @summary Test timestamp via ZipEntry.get/setTimeLocal()
*/
@@ -65,6 +65,9 @@
test(LocalDateTime.of(1968, 04, 28, 2, 51, 25));
test(LocalDateTime.of(1970, 04, 26, 2, 31, 52));
+ // for #8161942
+ test(LocalDateTime.of(2200, 04, 26, 2, 31, 52)); // unix 2038
+
} finally {
TimeZone.setDefault(tz0);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/templates/SSLSocketSample.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// Please run in othervm mode. SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8161106
+ * @summary Improve SSLSocket test template
+ * @run main/othervm SSLSocketSample
+ */
+
+import java.io.*;
+import javax.net.ssl.*;
+import java.net.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Template to help speed your client/server tests.
+ */
+public final class SSLSocketSample {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ private static final boolean separateServerThread = false;
+
+ /*
+ * Where do we find the keystores?
+ */
+ private static final String pathToStores = "../etc";
+ private static final String keyStoreFile = "keystore";
+ private static final String trustStoreFile = "truststore";
+ private static final String passwd = "passphrase";
+
+ /*
+ * Turn on SSL debugging?
+ */
+ private static final boolean debug = false;
+
+ /*
+ * Is the server ready to serve?
+ */
+ private static final CountDownLatch serverCondition = new CountDownLatch(1);
+
+ /*
+ * Is the client ready to handshake?
+ */
+ private static final CountDownLatch clientCondition = new CountDownLatch(1);
+
+ /*
+ * What's the server port? Use any free port by default
+ */
+ private volatile int serverPort = 0;
+
+ /*
+ * If the client or server is doing some kind of object creation
+ * that the other side depends on, and that thread prematurely
+ * exits, you may experience a hang. The test harness will
+ * terminate all hung threads after its timeout has expired,
+ * currently 3 minutes by default, but you might try to be
+ * smart about it....
+ */
+
+ /*
+ * Define the server side of the test.
+ */
+ void doServerSide() throws Exception {
+ SSLServerSocket sslServerSocket;
+
+ // kick start the server side service
+ SSLServerSocketFactory sslssf =
+ (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+ sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+
+ serverPort = sslServerSocket.getLocalPort();
+
+ // Signal the client, the server is ready to accept connection.
+ serverCondition.countDown();
+
+
+ // Try to accept a connection in 30 seconds.
+ SSLSocket sslSocket;
+ try {
+ sslServerSocket.setSoTimeout(30000);
+ sslSocket = (SSLSocket)sslServerSocket.accept();
+ } catch (SocketTimeoutException ste) {
+ sslServerSocket.close();
+
+ // Ignore the test case if no connection within 30 seconds.
+ System.out.println(
+ "No incoming client connection in 30 seconds. " +
+ "Ignore in server side.");
+ return;
+ }
+
+ // handle the connection
+ try {
+ // Is it the expected client connection?
+ //
+ // Naughty test cases or third party routines may try to
+ // connection to this server port unintentionally. In
+ // order to mitigate the impact of unexpected client
+ // connections and avoid intermittent failure, it should
+ // be checked that the accepted connection is really linked
+ // to the expected client.
+ boolean clientIsReady =
+ clientCondition.await(30L, TimeUnit.SECONDS);
+
+ if (clientIsReady) {
+ // Run the application in server side.
+ runServerApplication(sslSocket);
+ } else { // Otherwise, ignore
+ // We don't actually care about plain socket connections
+ // for TLS communication testing generally. Just ignore
+ // the test if the accepted connection is not linked to
+ // the expected client or the client connection timeout
+ // in 30 seconds.
+ System.out.println(
+ "The client is not the expected one or timeout. " +
+ "Ignore in server side.");
+ }
+ } finally {
+ sslSocket.close();
+ sslServerSocket.close();
+ }
+ }
+
+ /*
+ * Define the server side application of the test for the specified socket.
+ */
+ void runServerApplication(SSLSocket socket) throws Exception {
+ // here comes the test logic
+ InputStream sslIS = socket.getInputStream();
+ OutputStream sslOS = socket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write(85);
+ sslOS.flush();
+ }
+
+ /*
+ * Define the client side of the test.
+ */
+ void doClientSide() throws Exception {
+
+ // Wait for server to get started.
+ //
+ // The server side takes care of the issue if the server cannot
+ // get started in 90 seconds. The client side would just ignore
+ // the test case if the serer is not ready.
+ boolean serverIsReady =
+ serverCondition.await(90L, TimeUnit.SECONDS);
+ if (!serverIsReady) {
+ System.out.println(
+ "The server is not ready yet in 90 seconds. " +
+ "Ignore in client side.");
+ return;
+ }
+
+ SSLSocketFactory sslsf =
+ (SSLSocketFactory)SSLSocketFactory.getDefault();
+ try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
+ try {
+ sslSocket.connect(
+ new InetSocketAddress("localhost", serverPort), 15000);
+ } catch (IOException ioe) {
+ // The server side may be impacted by naughty test cases or
+ // third party routines, and cannot accept connections.
+ //
+ // Just ignore the test if the connection cannot be
+ // established.
+ System.out.println(
+ "Cannot make a connection in 15 seconds. " +
+ "Ignore in client side.");
+ return;
+ }
+
+ // OK, here the client and server get connected.
+
+ // Signal the server, the client is ready to communicate.
+ clientCondition.countDown();
+
+ // There is still a chance in theory that the server thread may
+ // wait client-ready timeout and then quit. The chance should
+ // be really rare so we don't consider it until it becomes a
+ // real problem.
+
+ // Run the application in client side.
+ runClientApplication(sslSocket);
+ }
+ }
+
+ /*
+ * Define the server side application of the test for the specified socket.
+ */
+ void runClientApplication(SSLSocket socket) throws Exception {
+ InputStream sslIS = socket.getInputStream();
+ OutputStream sslOS = socket.getOutputStream();
+
+ sslOS.write(280);
+ sslOS.flush();
+ sslIS.read();
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+
+ private volatile Exception serverException = null;
+ private volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ String keyFilename =
+ System.getProperty("test.src", ".") + "/" + pathToStores +
+ "/" + keyStoreFile;
+ String trustFilename =
+ System.getProperty("test.src", ".") + "/" + pathToStores +
+ "/" + trustStoreFile;
+
+ System.setProperty("javax.net.ssl.keyStore", keyFilename);
+ System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+ System.setProperty("javax.net.ssl.trustStore", trustFilename);
+ System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+ if (debug) {
+ System.setProperty("javax.net.debug", "all");
+ }
+
+ /*
+ * Start the tests.
+ */
+ new SSLSocketSample();
+ }
+
+ private Thread clientThread = null;
+ private Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ SSLSocketSample() throws Exception {
+ Exception startException = null;
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ startException = e;
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ if (serverThread != null) {
+ serverThread.join();
+ }
+ } else {
+ if (clientThread != null) {
+ clientThread.join();
+ }
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ } else {
+ remote = clientException;
+ local = serverException;
+ }
+
+ Exception exception = null;
+
+ /*
+ * Check various exception conditions.
+ */
+ if ((local != null) && (remote != null)) {
+ // If both failed, return the curthread's exception.
+ local.initCause(remote);
+ exception = local;
+ } else if (local != null) {
+ exception = local;
+ } else if (remote != null) {
+ exception = remote;
+ } else if (startException != null) {
+ exception = startException;
+ }
+
+ /*
+ * If there was an exception *AND* a startException,
+ * output it.
+ */
+ if (exception != null) {
+ if (exception != startException && startException != null) {
+ exception.addSuppressed(startException);
+ }
+ throw exception;
+ }
+
+ // Fall-through: no exception to throw!
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.out.println("Server died: " + e);
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ System.out.println("Server failed: " + e);
+ serverException = e;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.out.println("Client died: " + e);
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ System.out.println("Client failed: " + e);
+ clientException = e;
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/JaasClientWithDefaultHandler.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package login;
+
+import java.security.Principal;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import com.sun.security.auth.UnixPrincipal;
+
+public class JaasClientWithDefaultHandler {
+
+ private static final String USER_NAME = "testUser";
+ private static final String LOGIN_CONTEXT = "ModularLoginConf";
+ private static final String CBH_PROP = "auth.login.defaultCallbackHandler";
+
+ public static void main(String[] args) {
+ try {
+ java.security.Security.setProperty(CBH_PROP, args[0]);
+ LoginContext lc = new LoginContext(LOGIN_CONTEXT);
+ lc.login();
+ checkPrincipal(lc, true);
+ lc.logout();
+ checkPrincipal(lc, false);
+ } catch (LoginException le) {
+ throw new RuntimeException(le);
+ }
+ System.out.println("Test passed.");
+
+ }
+
+ /*
+ * Verify principal for the test user.
+ */
+ private static void checkPrincipal(LoginContext loginContext,
+ boolean principalShouldExist) {
+ if (!principalShouldExist) {
+ if (loginContext.getSubject().getPrincipals().size() != 0) {
+ throw new RuntimeException("Test failed. Principal was not "
+ + "cleared.");
+ }
+ return;
+ }
+ for (Principal p : loginContext.getSubject().getPrincipals()) {
+ if (p instanceof UnixPrincipal
+ && USER_NAME.equals(p.getName())) {
+ //Proper principal was found, return.
+ return;
+ }
+ }
+ throw new RuntimeException("Test failed. UnixPrincipal "
+ + USER_NAME + " expected.");
+ }
+
+}
--- a/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -59,8 +59,7 @@
private static final Path C_SRC = SRC.resolve("JaasClient.java");
private static final String C_PKG = "client";
private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
- private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR
- + C_PKG + AUTO + JAR_EXTN;
+ private static final String MCN_JAR_NAME = MODULAR + C_PKG + "N" + JAR_EXTN;
private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
private static final Path BUILD_DIR = Paths.get(".").resolve("build");
@@ -68,7 +67,7 @@
private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve(
S_PKG + DESCRIPTOR);
- private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG);
+ private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
@@ -83,8 +82,7 @@
private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
- private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR
- .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME);
+ private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
private static final String MAIN = C_PKG + ".JaasClient";
private static final String S_INTERFACE
@@ -99,10 +97,7 @@
private static final boolean WITH_S_DESCR = true;
private static final boolean WITHOUT_S_DESCR = false;
- private static final String LOGIN_MODULE_NOT_FOUND_MSG
- = "No LoginModule found";
private static final String NO_FAILURE = null;
- private static final Map<String, String> VM_ARGS = new LinkedHashMap<>();
/**
* Generates Test specific input parameters.
@@ -112,10 +107,10 @@
List<List<Object>> params = new ArrayList<>();
String[] args = new String[]{};
- //PARAMETER ORDERS -
- //client Module Type, Service Module Type,
- //Service META Descriptor Required,
- //Expected Failure message, mechanism used to find the provider
+ // PARAMETER ORDERS -
+ // Client Module Type, Service Module Type,
+ // If Service META descriptor Required,
+ // Expected Failure message, Client arguments
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
@@ -123,7 +118,7 @@
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
@@ -136,7 +131,7 @@
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
@@ -149,7 +144,7 @@
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
- WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args));
+ WITHOUT_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
WITH_S_DESCR, NO_FAILURE, args));
params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
@@ -166,29 +161,25 @@
boolean done = true;
try {
- VM_ARGS.put("-Duser.language=", "en");
- VM_ARGS.put("-Duser.region", "US");
- VM_ARGS.put("-Djava.security.auth.login.config=", SRC.resolve(
- "jaas.conf").toFile().getCanonicalPath());
-
done = CompilerUtils.compile(S_SRC, S_BUILD_DIR);
done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR);
done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL);
- //Generate regular/modular jars with(out) META-INF
- //service descriptor
+ // Generate modular/regular jars with(out) META-INF
+ // service descriptor
generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR,
S_WITH_META_DESCR_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR,
S_WITH_META_DESCR_BUILD_DIR, false);
- //Generate regular/modular(depends on explicit/auto service)
- //jars for client
- done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR);
- generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true);
- generateJar(false, MODULE_TYPE.EXPLICIT,
- MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false);
- generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false);
+ // Compile client source codes.
+ done &= CompilerUtils.compile(C_SRC, C_BLD_DIR);
+ // Generate modular client jar with explicit dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+ // Generate modular client jar without any dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+ // Generate regular client jar
+ generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
System.out.format("%nArtifacts generated successfully? %s", done);
if (!done) {
throw new RuntimeException("Artifact generation failed");
@@ -226,9 +217,9 @@
OutputAnalyzer output = null;
try {
- //For automated/explicit module type copy the corresponding
- //jars to module base folder, which will be considered as
- //module base path during execution.
+ // For automated/explicit module types, copy the corresponding
+ // jars to module base folder, which will be considered as
+ // module base path during execution.
if (!(cModuleType == MODULE_TYPE.UNNAMED
&& sModuletype == MODULE_TYPE.UNNAMED)) {
copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
@@ -237,20 +228,19 @@
System.out.format("%nExecuting java client with required"
+ " custom service in class/module path.");
- String mName = getModuleName(cModuleType, cJarPath,
- C_PKG);
+ String mName = getModuleName(cModuleType, cJarPath, C_PKG);
Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
|| sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
sJarPath);
+ Map<String, String> vmArgs = getVMArgs(sModuletype,
+ getModuleName(sModuletype, sJarPath, S_PKG));
output = ProcessTools.executeTestJava(
- getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS,
+ getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
args)).outputTo(System.out).errorTo(System.out);
} finally {
- //clean module path so that the modulepath can hold only
- //the required jars for next run.
+ // Clean module path to hold required jars for next run.
cleanModuleBasePath(M_BASE_PATH);
- System.out.println("--------------------------------------------");
}
return output;
}
@@ -260,9 +250,9 @@
* based on client/service module type.
*/
@Override
- public Path findJarPath(boolean service, MODULE_TYPE moduleType,
+ public Path findJarPath(boolean isService, MODULE_TYPE moduleType,
boolean addMetaDesc, boolean dependsOnServiceModule) {
- if (service) {
+ if (isService) {
if (moduleType == MODULE_TYPE.EXPLICIT) {
if (addMetaDesc) {
return MS_WITH_DESCR_JAR;
@@ -277,11 +267,12 @@
}
}
} else {
+ // Choose corresponding client jar using dependent module
if (moduleType == MODULE_TYPE.EXPLICIT) {
if (dependsOnServiceModule) {
return MC_JAR;
} else {
- return MC_DEPENDS_ON_AUTO_SERVICE_JAR;
+ return MCN_JAR;
}
} else {
return C_JAR;
@@ -289,4 +280,20 @@
}
}
+ /**
+ * VM argument required for the test.
+ */
+ private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
+ String addModName) throws IOException {
+ final Map<String, String> vmArgs = new LinkedHashMap<>();
+ vmArgs.put("-Duser.language=", "en");
+ vmArgs.put("-Duser.region=", "US");
+ vmArgs.put("-Djava.security.auth.login.config=", SRC.resolve(
+ "jaas.conf").toFile().getCanonicalPath());
+ if (addModName != null && sModuletype == MODULE_TYPE.AUTO) {
+ vmArgs.put("-addmods ", addModName);
+ }
+ return vmArgs;
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/JaasModularDefaultHandlerTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.IOException;
+import java.lang.module.ModuleDescriptor;
+import java.util.ArrayList;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.OutputAnalyzer;
+import org.testng.annotations.BeforeTest;
+
+/**
+ * @test
+ * @bug 8151654
+ * @library /lib/testlibrary
+ * @library /java/security/modules
+ * @build CompilerUtils JarUtils
+ * @summary Test custom JAAS callback handler with all possible modular option.
+ * @run testng JaasModularDefaultHandlerTest
+ */
+public class JaasModularDefaultHandlerTest extends ModularTest {
+
+ private static final Path S_SRC = SRC.resolve("TestCallbackHandler.java");
+ private static final String MODULAR = "M";
+ private static final String S_PKG = "handler";
+ private static final String S_JAR_NAME = S_PKG + JAR_EXTN;
+ private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN;
+ private static final String HANDLER = S_PKG + ".TestCallbackHandler";
+
+ private static final Path C_SRC
+ = SRC.resolve("JaasClientWithDefaultHandler.java");
+ private static final Path CL_SRC = SRC.resolve("TestLoginModule.java");
+ private static final String C_PKG = "login";
+ private static final String C_JAR_NAME = C_PKG + JAR_EXTN;
+ private static final String MCN_JAR_NAME
+ = MODULAR + C_PKG + "NoMUse" + JAR_EXTN;
+ private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN;
+
+ private static final Path BUILD_DIR = Paths.get(".").resolve("build");
+ private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin");
+ private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG);
+ private static final Path C_BLD_DIR = COMPILE_DIR.resolve(C_PKG);
+ private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase");
+ private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts");
+
+ private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG);
+ private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME);
+ private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(MS_JAR_NAME);
+
+ private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG);
+ private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME);
+ private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME);
+ private static final Path MCN_JAR = C_ARTIFACTS_DIR.resolve(MCN_JAR_NAME);
+
+ private static final String MAIN = C_PKG + ".JaasClientWithDefaultHandler";
+ private static final List<String> M_REQUIRED = Arrays.asList("java.base",
+ "jdk.security.auth");
+
+ private static final String CLASS_NOT_FOUND_MSG
+ = "java.lang.ClassNotFoundException: handler.TestCallbackHandler";
+ private static final String NO_FAILURE = null;
+
+ /**
+ * Generates Test specific input parameters.
+ */
+ @Override
+ public Object[][] getTestInput() {
+
+ List<List<Object>> params = new ArrayList<>();
+ String[] args = new String[]{HANDLER};
+ // PARAMETER ORDERS -
+ // Client Module Type, Service Module Type,
+ // Service META Descriptor Required,
+ // Expected Failure message, Client arguments
+ params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED,
+ false, NO_FAILURE, args));
+
+ params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED,
+ false, NO_FAILURE, args));
+
+ params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO,
+ false, NO_FAILURE, args));
+ params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED,
+ false, NO_FAILURE, args));
+ return params.stream().map(p -> p.toArray()).toArray(Object[][]::new);
+ }
+
+ /**
+ * Pre-compile and generate the artifacts required to run this test before
+ * running each test cases.
+ */
+ @BeforeTest
+ public void buildArtifacts() {
+
+ boolean done = true;
+ try {
+ done = CompilerUtils.compile(S_SRC, S_BUILD_DIR);
+ // Generate modular/regular handler jars.
+ generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false);
+ generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false);
+ // Compile client source codes.
+ done &= CompilerUtils.compile(C_SRC, C_BLD_DIR);
+ done &= CompilerUtils.compile(CL_SRC, C_BLD_DIR);
+ // Generate modular client jar with explicit dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BLD_DIR, true);
+ // Generate modular client jar without any dependency
+ generateJar(false, MODULE_TYPE.EXPLICIT, MCN_JAR, C_BLD_DIR, false);
+ // Generate regular client jar
+ generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BLD_DIR, false);
+ System.out.format("%nArtifacts generated successfully? %s", done);
+ if (!done) {
+ throw new RuntimeException("Artifact generation failed");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Generate modular/regular jar based on module type for this test.
+ */
+ private void generateJar(boolean isService, MODULE_TYPE moduleType,
+ Path jar, Path compilePath, boolean depends) throws IOException {
+
+ ModuleDescriptor mDescriptor = null;
+ if (isService) {
+ mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG,
+ S_PKG, null, null, null, M_REQUIRED, depends);
+ } else {
+ mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG,
+ C_PKG, null, null, S_PKG, M_REQUIRED, depends);
+ }
+ generateJar(mDescriptor, jar, compilePath);
+ }
+
+ /**
+ * Holds Logic for the test client. This method will get called with each
+ * test parameter.
+ */
+ @Override
+ public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType,
+ Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath,
+ String... args) throws Exception {
+
+ OutputAnalyzer output = null;
+ try {
+ // For automated/explicit module types, copy the corresponding
+ // jars to module base folder, which will be considered as
+ // module base path during execution.
+ if (!(cModuleType == MODULE_TYPE.UNNAMED
+ && sModuletype == MODULE_TYPE.UNNAMED)) {
+ copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH);
+ copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH);
+ }
+
+ System.out.format("%nExecuting java client with required"
+ + " custom service in class/module path.");
+ String mName = getModuleName(cModuleType, cJarPath, C_PKG);
+ Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED
+ || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null;
+ String cPath = buildClassPath(cModuleType, cJarPath, sModuletype,
+ sJarPath);
+ Map<String, String> vmArgs = getVMArgs(sModuletype, cModuleType,
+ getModuleName(sModuletype, sJarPath, S_PKG));
+ output = ProcessTools.executeTestJava(
+ getJavaCommand(cmBasePath, cPath, mName, MAIN, vmArgs,
+ args)).outputTo(System.out).errorTo(System.out);
+ } finally {
+ // Clean module path to hold required jars for next run.
+ cleanModuleBasePath(M_BASE_PATH);
+ }
+ return output;
+ }
+
+ /**
+ * Decide the pre-generated client/service jar path for each test case
+ * based on client/service module type.
+ */
+ @Override
+ public Path findJarPath(boolean depends, MODULE_TYPE moduleType,
+ boolean addMetaDesc, boolean dependsOnServiceModule) {
+ if (depends) {
+ if (moduleType == MODULE_TYPE.EXPLICIT) {
+ return MS_JAR;
+ } else {
+ return S_JAR;
+ }
+ } else {
+ // Choose corresponding client jar using dependent module
+ if (moduleType == MODULE_TYPE.EXPLICIT) {
+ if (dependsOnServiceModule) {
+ return MC_JAR;
+ } else {
+ return MCN_JAR;
+ }
+ } else {
+ return C_JAR;
+ }
+ }
+ }
+
+ /**
+ * VM argument required for the test.
+ */
+ private Map<String, String> getVMArgs(MODULE_TYPE sModuletype,
+ MODULE_TYPE cModuleType, String addModName) throws IOException {
+ final Map<String, String> vmArgs = new LinkedHashMap<>();
+ vmArgs.put("-Duser.language=", "en");
+ vmArgs.put("-Duser.region=", "US");
+ vmArgs.put("-Djava.security.auth.login.config=", SRC.resolve(
+ "jaas.conf").toFile().getCanonicalPath());
+ if (addModName != null
+ && !(cModuleType == MODULE_TYPE.EXPLICIT
+ && sModuletype == MODULE_TYPE.EXPLICIT)) {
+ vmArgs.put("-addmods ", addModName);
+ }
+ return vmArgs;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/security/auth/login/modules/TestCallbackHandler.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package handler;
+
+import java.io.IOException;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class TestCallbackHandler implements CallbackHandler {
+
+ private static final String USER_NAME = "testUser";
+ private static final String PASSWORD = "testPassword";
+
+ @Override
+ public void handle(Callback[] callbacks) throws IOException,
+ UnsupportedCallbackException {
+ System.out.println("TestCallbackHandler will get resolved through"
+ + " auth.login.defaultCallbackHandler property.");
+ for (Callback callback : callbacks) {
+ if (callback instanceof NameCallback) {
+ ((NameCallback) callback).setName(USER_NAME);
+ } else if (callback instanceof PasswordCallback) {
+ ((PasswordCallback) callback).setPassword(
+ PASSWORD.toCharArray());
+ } else {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+
+}
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java Wed Jul 27 08:33:15 2016 -0400
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -58,10 +58,6 @@
return vmName.endsWith(" Minimal VM");
}
- public static boolean isEmbedded() {
- return vmName.contains("Embedded");
- }
-
public static boolean isTieredSupported() {
return compiler.contains("Tiered Compilers");
}
--- a/langtools/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -370,3 +370,4 @@
2d65e127e93d5ff0df61bf78e57d7f46a2f1edeb jdk-9+125
ea4eea2997b9e2f26cd7965839921710ff4065c8 jdk-9+126
a42768b48cb0c5af9063e12093975baeeca3b5fa jdk-9+127
+2764986661b6d339ba73af52d69d3506ce12e648 jdk-9+128
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Wed Jul 27 13:33:55 2016 +0000
@@ -1900,7 +1900,8 @@
Type qualifier = (tree.meth.hasTag(SELECT))
? ((JCFieldAccess) tree.meth).selected.type
: env.enclClass.sym.type;
- restype = adjustMethodReturnType(qualifier, methName, argtypes, restype);
+ Symbol msym = TreeInfo.symbol(tree.meth);
+ restype = adjustMethodReturnType(msym, qualifier, methName, argtypes, restype);
chk.checkRefTypes(tree.typeargs, typeargtypes);
@@ -1912,19 +1913,25 @@
chk.validate(tree.typeargs, localEnv);
}
//where
- Type adjustMethodReturnType(Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
- if (methodName == names.clone && types.isArray(qualifierType)) {
+ Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, List<Type> argtypes, Type restype) {
+ if (msym != null &&
+ msym.owner == syms.objectType.tsym &&
+ methodName == names.getClass &&
+ argtypes.isEmpty()) {
+ // as a special case, x.getClass() has type Class<? extends |X|>
+ return new ClassType(restype.getEnclosingType(),
+ List.<Type>of(new WildcardType(types.erasure(qualifierType),
+ BoundKind.EXTENDS,
+ syms.boundClass)),
+ restype.tsym,
+ restype.getMetadata());
+ } else if (msym != null &&
+ msym.owner == syms.arrayClass &&
+ methodName == names.clone &&
+ types.isArray(qualifierType)) {
// as a special case, array.clone() has a result that is
// the same as static type of the array being cloned
return qualifierType;
- } else if (methodName == names.getClass && argtypes.isEmpty()) {
- // as a special case, x.getClass() has type Class<? extends |X|>
- return new ClassType(restype.getEnclosingType(),
- List.<Type>of(new WildcardType(types.erasure(qualifierType),
- BoundKind.EXTENDS,
- syms.boundClass)),
- restype.tsym,
- restype.getMetadata());
} else {
return restype;
}
@@ -2989,7 +2996,7 @@
if (!refType.isErroneous()) {
refType = types.createMethodTypeWithReturn(refType,
- adjustMethodReturnType(lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
+ adjustMethodReturnType(refSym, lookupHelper.site, that.name, checkInfo.pt.getParameterTypes(), refType.getReturnType()));
}
//go ahead with standard method reference compatibility check - note that param check
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java Wed Jul 27 13:33:55 2016 +0000
@@ -902,13 +902,7 @@
/** Return binary operator that corresponds to given access code.
*/
private OperatorSymbol binaryAccessOperator(int acode) {
- for (Symbol sym : syms.predefClass.members().getSymbols(NON_RECURSIVE)) {
- if (sym instanceof OperatorSymbol) {
- OperatorSymbol op = (OperatorSymbol)sym;
- if (accessCode(op.opcode) == acode) return op;
- }
- }
- return null;
+ return (OperatorSymbol)operators.lookupBinaryOp(sym -> accessCode(((OperatorSymbol)sym).opcode) == acode);
}
/** Return tree tag for assignment operation corresponding
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -798,6 +798,15 @@
.addBinaryOperator(BOOLEAN, BOOLEAN, BOOLEAN, bool_or));
}
+ Symbol lookupBinaryOp(Predicate<Symbol> applicabilityTest) {
+ return binaryOperators.values().stream()
+ .flatMap(List::stream)
+ .map(helper -> helper.doLookup(applicabilityTest))
+ .distinct()
+ .filter(sym -> sym != syms.noSymbol)
+ .findFirst().get();
+ }
+
/**
* Complete the initialization of an operator helper by storing it into the corresponding operator map.
*/
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java Wed Jul 27 13:33:55 2016 +0000
@@ -449,7 +449,7 @@
? CompileState.valueOf(options.get("shouldstop.ifNoError"))
: CompileState.GENERATE;
- if (options.isUnset("oldDiags"))
+ if (options.isUnset("diags.legacy"))
log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context));
PlatformDescription platformProvider = context.get(PlatformDescription.class);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Option.java Wed Jul 27 13:33:55 2016 +0000
@@ -346,21 +346,6 @@
}
},
- DIAGS("-XDdiags=", null, HIDDEN, INFO) {
- @Override
- public boolean process(OptionHelper helper, String option) {
- option = option.substring(option.indexOf('=') + 1);
- String diagsOption = option.contains("%") ?
- "-XDdiagsFormat=" :
- "-XDdiags=";
- diagsOption += option;
- if (XD.matches(diagsOption))
- return XD.process(helper, diagsOption);
- else
- return false;
- }
- },
-
HELP("-help", "opt.help", STANDARD, INFO) {
@Override
public boolean process(OptionHelper helper, String option) {
@@ -506,30 +491,6 @@
XDIAGS("-Xdiags:", "opt.diags", EXTENDED, BASIC, ONEOF, "compact", "verbose"),
- /* This is a back door to the compiler's option table.
- * -XDx=y sets the option x to the value y.
- * -XDx sets the option x to the value x.
- */
- XD("-XD", null, HIDDEN, BASIC) {
- @Override
- public boolean matches(String s) {
- return s.startsWith(text);
- }
- @Override
- public boolean process(OptionHelper helper, String option) {
- return process(helper, option, option.substring(text.length()));
- }
-
- @Override
- public boolean process(OptionHelper helper, String option, String arg) {
- int eq = arg.indexOf('=');
- String key = (eq < 0) ? arg : arg.substring(0, eq);
- String value = (eq < 0) ? arg : arg.substring(eq+1);
- helper.put(key, value);
- return false;
- }
- },
-
XDEBUG("-Xdebug:", null, HIDDEN, BASIC) {
@Override
public boolean process(OptionHelper helper, String option) {
@@ -556,6 +517,37 @@
}
},
+ DIAGS("-diags:", null, HIDDEN, BASIC, true) {
+ @Override
+ public boolean process(OptionHelper helper, String option) {
+ return HiddenGroup.DIAGS.process(helper, option);
+ }
+ },
+
+ /* This is a back door to the compiler's option table.
+ * -XDx=y sets the option x to the value y.
+ * -XDx sets the option x to the value x.
+ */
+ XD("-XD", null, HIDDEN, BASIC) {
+ @Override
+ public boolean matches(String s) {
+ return s.startsWith(text);
+ }
+ @Override
+ public boolean process(OptionHelper helper, String option) {
+ return process(helper, option, option.substring(text.length()));
+ }
+
+ @Override
+ public boolean process(OptionHelper helper, String option, String arg) {
+ int eq = arg.indexOf('=');
+ String key = (eq < 0) ? arg : arg.substring(0, eq);
+ String value = (eq < 0) ? arg : arg.substring(eq+1);
+ helper.put(key, value);
+ return false;
+ }
+ },
+
XADDEXPORTS("-XaddExports:", "opt.arg.addExports", "opt.addExports", EXTENDED, BASIC) {
@Override
public boolean process(OptionHelper helper, String option) {
@@ -672,6 +664,26 @@
ANYOF
}
+ enum HiddenGroup {
+ DIAGS("diags");
+
+ final String text;
+
+ HiddenGroup(String text) {
+ this.text = text;
+ }
+
+ public boolean process(OptionHelper helper, String option) {
+ String p = option.substring(option.indexOf(':') + 1).trim();
+ String[] subOptions = p.split(";");
+ for (String subOption : subOptions) {
+ subOption = text + "." + subOption.trim();
+ XD.process(helper, subOption, subOption);
+ }
+ return false;
+ }
+ }
+
public final String text;
final OptionKind kind;
@@ -705,6 +717,12 @@
this(text, null, descrKey, kind, group, null, null, false);
}
+ Option(String text, String descrKey,
+ OptionKind kind, OptionGroup group,
+ boolean doHasSuffix) {
+ this(text, null, descrKey, kind, group, null, null, doHasSuffix);
+ }
+
Option(String text, String argsNameKey, String descrKey,
OptionKind kind, OptionGroup group) {
this(text, argsNameKey, descrKey, kind, group, null, null, false);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractDiagnosticFormatter.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -403,13 +403,13 @@
public SimpleConfiguration(Options options, Set<DiagnosticPart> parts) {
this(parts);
String showSource = null;
- if ((showSource = options.get("showSource")) != null) {
+ if ((showSource = options.get("diags.showSource")) != null) {
if (showSource.equals("true"))
setVisiblePart(DiagnosticPart.SOURCE, true);
else if (showSource.equals("false"))
setVisiblePart(DiagnosticPart.SOURCE, false);
}
- String diagOpts = options.get("diags");
+ String diagOpts = options.get("diags.formatterOptions");
if (diagOpts != null) {//override -XDshowSource
Collection<String> args = Arrays.asList(diagOpts.split(","));
if (args.contains("short")) {
@@ -422,7 +422,7 @@
setVisiblePart(DiagnosticPart.SOURCE, false);
}
String multiPolicy = null;
- if ((multiPolicy = options.get("multilinePolicy")) != null) {
+ if ((multiPolicy = options.get("diags.multilinePolicy")) != null) {
if (multiPolicy.equals("disabled"))
setVisiblePart(DiagnosticPart.SUBDIAGNOSTICS, false);
else if (multiPolicy.startsWith("limit:")) {
@@ -447,7 +447,7 @@
}
}
String showCaret = null;
- if (((showCaret = options.get("showCaret")) != null) &&
+ if (((showCaret = options.get("diags.showCaret")) != null) &&
showCaret.equals("false"))
setCaretEnabled(false);
else
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/BasicDiagnosticFormatter.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -229,9 +229,9 @@
DiagnosticPart.SOURCE));
initFormat();
initIndentation();
- if (options.isSet("oldDiags"))
+ if (options.isSet("diags.legacy"))
initOldFormat();
- String fmt = options.get("diagsFormat");
+ String fmt = options.get("diags.layout");
if (fmt != null) {
if (fmt.equals("OLD"))
initOldFormat();
@@ -239,12 +239,12 @@
initFormats(fmt);
}
String srcPos = null;
- if ((((srcPos = options.get("sourcePosition")) != null)) &&
+ if ((((srcPos = options.get("diags.sourcePosition")) != null)) &&
srcPos.equals("bottom"))
setSourcePosition(SourcePosition.BOTTOM);
else
setSourcePosition(SourcePosition.AFTER_SUMMARY);
- String indent = options.get("diagsIndentation");
+ String indent = options.get("diags.indent");
if (indent != null) {
String[] levels = indent.split("\\|");
try {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -644,7 +644,7 @@
EnumSet.of(RichFormatterFeature.SIMPLE_NAMES,
RichFormatterFeature.WHERE_CLAUSES,
RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
- String diagOpts = options.get("diags");
+ String diagOpts = options.get("diags.formatterOptions");
if (diagOpts != null) {
for (String args: diagOpts.split(",")) {
if (args.equals("-where")) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/ClassTracker.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jshell.jdi;
-
-import java.util.HashMap;
-import java.util.Objects;
-import com.sun.jdi.ReferenceType;
-import java.util.List;
-import com.sun.jdi.VirtualMachine;
-
-/**
- * Tracks the state of a class.
- */
-class ClassTracker {
-
- private final VirtualMachine vm;
- private final HashMap<String, ClassInfo> map;
-
- ClassTracker(VirtualMachine vm) {
- this.vm = vm;
- this.map = new HashMap<>();
- }
-
- /**
- * Associates a class name, class bytes, and ReferenceType.
- */
- class ClassInfo {
-
- // The name of the class -- always set
- private final String className;
-
- // The corresponding compiled class bytes when a load or redefine
- // is started. May not be the loaded bytes. May be null.
- private byte[] bytes;
-
- // The class bytes successfully loaded/redefined into the remote VM.
- private byte[] loadedBytes;
-
- // The corresponding JDI ReferenceType. Used by redefineClasses and
- // acts as indicator of successful load (null if not loaded).
- private ReferenceType rt;
-
- private ClassInfo(String className) {
- this.className = className;
- }
-
- String getClassName() {
- return className;
- }
-
- byte[] getLoadedBytes() {
- return loadedBytes;
- }
-
- byte[] getBytes() {
- return bytes;
- }
-
- private void setBytes(byte[] potentialBytes) {
- this.bytes = potentialBytes;
- }
-
- // The class has been successful loaded redefined. The class bytes
- // sent are now actually loaded.
- void markLoaded() {
- loadedBytes = bytes;
- }
-
- // Ask JDI for the ReferenceType, null if not loaded.
- ReferenceType getReferenceTypeOrNull() {
- if (rt == null) {
- rt = nameToRef(className);
- }
- return rt;
- }
-
- private ReferenceType nameToRef(String name) {
- List<ReferenceType> rtl = vm.classesByName(name);
- if (rtl.size() != 1) {
- return null;
- }
- return rtl.get(0);
- }
-
- @Override
- public boolean equals(Object o) {
- return o instanceof ClassInfo
- && ((ClassInfo) o).className.equals(className);
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(this.className);
- }
- }
-
- // Map a class name to the current compiled class bytes.
- ClassInfo classInfo(String className, byte[] bytes) {
- ClassInfo ci = get(className);
- ci.setBytes(bytes);
- return ci;
- }
-
- // Lookup the ClassInfo by class name, create if it does not exist.
- ClassInfo get(String className) {
- return map.computeIfAbsent(className, k -> new ClassInfo(k));
- }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/FailOverExecutionControl.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.jshell.jdi;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import jdk.internal.jshell.debug.InternalDebugControl;
-import jdk.jshell.JShellException;
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-
-/**
- * A meta implementation of ExecutionControl which cycles through the specified
- * ExecutionControl instances until it finds one that starts.
- */
-public class FailOverExecutionControl implements ExecutionControl {
-
- private final List<ExecutionControl> ecl = new ArrayList<>();
- private ExecutionControl active = null;
- private final List<Exception> thrown = new ArrayList<>();
-
- /**
- * Create the ExecutionControl instance with at least one actual
- * ExecutionControl instance.
- *
- * @param ec0 the first instance to try
- * @param ecs the second and on instance to try
- */
- public FailOverExecutionControl(ExecutionControl ec0, ExecutionControl... ecs) {
- ecl.add(ec0);
- for (ExecutionControl ec : ecs) {
- ecl.add(ec);
- }
- }
-
- @Override
- public void start(ExecutionEnv env) throws Exception {
- for (ExecutionControl ec : ecl) {
- try {
- ec.start(env);
- // Success! This is our active ExecutionControl
- active = ec;
- return;
- } catch (Exception ex) {
- thrown.add(ex);
- } catch (Throwable ex) {
- thrown.add(new RuntimeException(ex));
- }
- InternalDebugControl.debug(env.state(), env.userErr(),
- thrown.get(thrown.size() - 1), "failed one in FailOverExecutionControl");
- }
- // They have all failed -- rethrow the first exception we encountered
- throw thrown.get(0);
- }
-
- @Override
- public void close() {
- active.close();
- }
-
- @Override
- public boolean addToClasspath(String path) {
- return active.addToClasspath(path);
- }
-
- @Override
- public String invoke(String classname, String methodname) throws JShellException {
- return active.invoke(classname, methodname);
- }
-
- @Override
- public boolean load(Collection<String> classes) {
- return active.load(classes);
- }
-
- @Override
- public boolean redefine(Collection<String> classes) {
- return active.redefine(classes);
- }
-
- @Override
- public ClassStatus getClassStatus(String classname) {
- return active.getClassStatus(classname);
- }
-
- @Override
- public void stop() {
- active.stop();
- }
-
- @Override
- public String varValue(String classname, String varname) {
- return active.varValue(classname, varname);
- }
-
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIConnection.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-/*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This source code is provided to illustrate the usage of a given feature
- * or technique and has been deliberately simplified. Additional steps
- * required for a production-quality application, such as security checks,
- * input validation and proper error handling, might not be present in
- * this sample code.
- */
-
-
-package jdk.internal.jshell.jdi;
-
-import com.sun.jdi.*;
-import com.sun.jdi.connect.*;
-
-import java.util.*;
-import java.util.Map.Entry;
-import java.io.*;
-import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
-
-/**
- * Connection to a Java Debug Interface VirtualMachine instance.
- * Adapted from jdb VMConnection. Message handling, exception handling, and I/O
- * redirection changed. Interface to JShell added.
- */
-class JDIConnection {
-
- private static final String REMOTE_AGENT = "jdk.internal.jshell.remote.RemoteAgent";
-
- private VirtualMachine vm;
- private boolean active = true;
- private Process process = null;
- private int outputCompleteCount = 0;
-
- private final JDIExecutionControl ec;
- private final Connector connector;
- private final Map<String, com.sun.jdi.connect.Connector.Argument> connectorArgs;
- private final int traceFlags;
-
- private synchronized void notifyOutputComplete() {
- outputCompleteCount++;
- notifyAll();
- }
-
- private synchronized void waitOutputComplete() {
- // Wait for stderr and stdout
- if (process != null) {
- while (outputCompleteCount < 2) {
- try {wait();} catch (InterruptedException e) {}
- }
- }
- }
-
- private Connector findConnector(String name) {
- for (Connector cntor :
- Bootstrap.virtualMachineManager().allConnectors()) {
- if (cntor.name().equals(name)) {
- return cntor;
- }
- }
- return null;
- }
-
- private Map <String, Connector.Argument> mergeConnectorArgs(Connector connector, Map<String, String> argumentName2Value) {
- Map<String, Connector.Argument> arguments = connector.defaultArguments();
-
- for (Entry<String, String> argumentEntry : argumentName2Value.entrySet()) {
- String name = argumentEntry.getKey();
- String value = argumentEntry.getValue();
- Connector.Argument argument = arguments.get(name);
-
- if (argument == null) {
- throw new IllegalArgumentException("Argument is not defined for connector:" +
- name + " -- " + connector.name());
- }
-
- argument.setValue(value);
- }
-
- return arguments;
- }
-
- /**
- * The JShell specific Connector args for the LaunchingConnector.
- *
- * @param portthe socket port for (non-JDI) commands
- * @param remoteVMOptions any user requested VM options
- * @return the argument map
- */
- private static Map<String, String> launchArgs(int port, String remoteVMOptions) {
- Map<String, String> argumentName2Value = new HashMap<>();
- argumentName2Value.put("main", REMOTE_AGENT + " " + port);
- argumentName2Value.put("options", remoteVMOptions);
- return argumentName2Value;
- }
-
- /**
- * Start the remote agent and establish a JDI connection to it.
- *
- * @param ec the execution control instance
- * @param port the socket port for (non-JDI) commands
- * @param remoteVMOptions any user requested VM options
- * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
- * otherwise we start explicitly and use ListeningConnector
- */
- JDIConnection(JDIExecutionControl ec, int port, List<String> remoteVMOptions, boolean isLaunch) {
- this(ec,
- isLaunch
- ? "com.sun.jdi.CommandLineLaunch"
- : "com.sun.jdi.SocketListen",
- isLaunch
- ? launchArgs(port, String.join(" ", remoteVMOptions))
- : new HashMap<>(),
- 0);
- if (isLaunch) {
- vm = launchTarget();
- } else {
- vm = listenTarget(port, remoteVMOptions);
- }
-
- if (isOpen() && vm().canBeModified()) {
- /*
- * Connection opened on startup.
- */
- new JDIEventHandler(vm(), (b) -> ec.handleVMExit())
- .start();
- }
- }
-
- /**
- * Base constructor -- set-up a JDI connection.
- *
- * @param ec the execution control instance
- * @param connectorName the standardized name of the connector
- * @param argumentName2Value the argument map
- * @param traceFlags should we trace JDI behavior
- */
- JDIConnection(JDIExecutionControl ec, String connectorName, Map<String, String> argumentName2Value, int traceFlags) {
- this.ec = ec;
- this.connector = findConnector(connectorName);
- if (connector == null) {
- throw new IllegalArgumentException("No connector named: " + connectorName);
- }
- connectorArgs = mergeConnectorArgs(connector, argumentName2Value);
- this.traceFlags = traceFlags;
- }
-
- final synchronized VirtualMachine vm() {
- if (vm == null) {
- throw new JDINotConnectedException();
- } else {
- return vm;
- }
- }
-
- private synchronized boolean isOpen() {
- return (vm != null);
- }
-
- synchronized boolean isRunning() {
- return process != null && process.isAlive();
- }
-
- // Beginning shutdown, ignore any random dying squeals
- void beginShutdown() {
- active = false;
- }
-
- synchronized void disposeVM() {
- try {
- if (vm != null) {
- vm.dispose(); // This could NPE, so it is caught below
- vm = null;
- }
- } catch (VMDisconnectedException ex) {
- // Ignore if already closed
- } catch (Throwable e) {
- ec.debug(DBG_GEN, null, "disposeVM threw: " + e);
- } finally {
- if (process != null) {
- process.destroy();
- process = null;
- }
- waitOutputComplete();
- }
- }
-
- private void dumpStream(InputStream inStream, final PrintStream pStream) throws IOException {
- BufferedReader in =
- new BufferedReader(new InputStreamReader(inStream));
- int i;
- try {
- while ((i = in.read()) != -1) {
- // directly copy input to output, but skip if asked to close
- if (active) {
- pStream.print((char) i);
- }
- }
- } catch (IOException ex) {
- String s = ex.getMessage();
- if (active && !s.startsWith("Bad file number")) {
- throw ex;
- }
- // else we are being shutdown (and don't want any spurious death
- // throws to ripple) or
- // we got a Bad file number IOException which just means
- // that the debuggee has gone away. We'll just treat it the
- // same as if we got an EOF.
- }
- }
-
- /**
- * Create a Thread that will retrieve and display any output.
- * Needs to be high priority, else debugger may exit before
- * it can be displayed.
- */
- private void displayRemoteOutput(final InputStream inStream, final PrintStream pStream) {
- Thread thr = new Thread("output reader") {
- @Override
- public void run() {
- try {
- dumpStream(inStream, pStream);
- } catch (IOException ex) {
- ec.debug(ex, "Failed reading output");
- ec.handleVMExit();
- } finally {
- notifyOutputComplete();
- }
- }
- };
- thr.setPriority(Thread.MAX_PRIORITY-1);
- thr.start();
- }
-
- /**
- * Create a Thread that will ship all input to remote.
- * Does it need be high priority?
- */
- private void readRemoteInput(final OutputStream outStream, final InputStream inputStream) {
- Thread thr = new Thread("input reader") {
- @Override
- public void run() {
- try {
- byte[] buf = new byte[256];
- int cnt;
- while ((cnt = inputStream.read(buf)) != -1) {
- outStream.write(buf, 0, cnt);
- outStream.flush();
- }
- } catch (IOException ex) {
- ec.debug(ex, "Failed reading output");
- ec.handleVMExit();
- }
- }
- };
- thr.setPriority(Thread.MAX_PRIORITY-1);
- thr.start();
- }
-
- private void forwardIO() {
- displayRemoteOutput(process.getErrorStream(), ec.execEnv.userErr());
- displayRemoteOutput(process.getInputStream(), ec.execEnv.userOut());
- readRemoteInput(process.getOutputStream(), ec.execEnv.userIn());
- }
-
- /* launch child target vm */
- private VirtualMachine launchTarget() {
- LaunchingConnector launcher = (LaunchingConnector)connector;
- try {
- VirtualMachine new_vm = launcher.launch(connectorArgs);
- process = new_vm.process();
- forwardIO();
- return new_vm;
- } catch (Exception ex) {
- reportLaunchFail(ex, "launch");
- }
- return null;
- }
-
- /**
- * Directly launch the remote agent and connect JDI to it with a
- * ListeningConnector.
- */
- private VirtualMachine listenTarget(int port, List<String> remoteVMOptions) {
- ListeningConnector listener = (ListeningConnector) connector;
- try {
- // Start listening, get the JDI connection address
- String addr = listener.startListening(connectorArgs);
- ec.debug(DBG_GEN, "Listening at address: " + addr);
-
- // Launch the RemoteAgent requesting a connection on that address
- String javaHome = System.getProperty("java.home");
- List<String> args = new ArrayList<>();
- args.add(javaHome == null
- ? "java"
- : javaHome + File.separator + "bin" + File.separator + "java");
- args.add("-agentlib:jdwp=transport=" + connector.transport().name() +
- ",address=" + addr);
- args.addAll(remoteVMOptions);
- args.add(REMOTE_AGENT);
- args.add("" + port);
- ProcessBuilder pb = new ProcessBuilder(args);
- process = pb.start();
-
- // Forward out, err, and in
- forwardIO();
-
- // Accept the connection from the remote agent
- vm = listener.accept(connectorArgs);
- listener.stopListening(connectorArgs);
- return vm;
- } catch (Exception ex) {
- reportLaunchFail(ex, "listen");
- }
- return null;
- }
-
- private void reportLaunchFail(Exception ex, String context) {
- throw new InternalError("Failed remote " + context + ": " + connector +
- " -- " + connectorArgs, ex);
- }
-}
\ No newline at end of file
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIEventHandler.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-import java.util.function.Consumer;
-import com.sun.jdi.*;
-import com.sun.jdi.event.*;
-
-/**
- * Handler of Java Debug Interface events.
- * Adapted from jdb EventHandler; Handling of events not used by JShell stubbed out.
- */
-class JDIEventHandler implements Runnable {
-
- private final Thread thread;
- private volatile boolean connected = true;
- private boolean completed = false;
- private final VirtualMachine vm;
- private final Consumer<Boolean> reportVMExit;
-
- JDIEventHandler(VirtualMachine vm, Consumer<Boolean> reportVMExit) {
- this.vm = vm;
- this.reportVMExit = reportVMExit;
- this.thread = new Thread(this, "event-handler");
- }
-
- void start() {
- thread.start();
- }
-
- synchronized void shutdown() {
- connected = false; // force run() loop termination
- thread.interrupt();
- while (!completed) {
- try {wait();} catch (InterruptedException exc) {}
- }
- }
-
- @Override
- public void run() {
- EventQueue queue = vm.eventQueue();
- while (connected) {
- try {
- EventSet eventSet = queue.remove();
- boolean resumeStoppedApp = false;
- EventIterator it = eventSet.eventIterator();
- while (it.hasNext()) {
- resumeStoppedApp |= handleEvent(it.nextEvent());
- }
-
- if (resumeStoppedApp) {
- eventSet.resume();
- }
- } catch (InterruptedException exc) {
- // Do nothing. Any changes will be seen at top of loop.
- } catch (VMDisconnectedException discExc) {
- handleDisconnectedException();
- break;
- }
- }
- synchronized (this) {
- completed = true;
- notifyAll();
- }
- }
-
- private boolean handleEvent(Event event) {
- if (event instanceof ExceptionEvent) {
- exceptionEvent(event);
- } else if (event instanceof WatchpointEvent) {
- fieldWatchEvent(event);
- } else if (event instanceof MethodEntryEvent) {
- methodEntryEvent(event);
- } else if (event instanceof MethodExitEvent) {
- methodExitEvent(event);
- } else if (event instanceof ClassPrepareEvent) {
- classPrepareEvent(event);
- } else if (event instanceof ThreadStartEvent) {
- threadStartEvent(event);
- } else if (event instanceof ThreadDeathEvent) {
- threadDeathEvent(event);
- } else if (event instanceof VMStartEvent) {
- vmStartEvent(event);
- return true;
- } else {
- handleExitEvent(event);
- }
- return true;
- }
-
- private boolean vmDied = false;
-
- private void handleExitEvent(Event event) {
- if (event instanceof VMDeathEvent) {
- vmDied = true;
- } else if (event instanceof VMDisconnectEvent) {
- connected = false;
- } else {
- throw new InternalError("Unexpected event type: " +
- event.getClass());
- }
- reportVMExit.accept(vmDied);
- }
-
- private synchronized void handleDisconnectedException() {
- /*
- * A VMDisconnectedException has happened while dealing with
- * another event. We need to flush the event queue, dealing only
- * with exit events (VMDeath, VMDisconnect) so that we terminate
- * correctly.
- */
- EventQueue queue = vm.eventQueue();
- while (connected) {
- try {
- EventSet eventSet = queue.remove();
- EventIterator iter = eventSet.eventIterator();
- while (iter.hasNext()) {
- handleExitEvent(iter.next());
- }
- } catch (InterruptedException exc) {
- // ignore
- } catch (InternalError exc) {
- // ignore
- }
- }
- }
-
- private void vmStartEvent(Event event) {
- VMStartEvent se = (VMStartEvent)event;
- }
-
- private void methodEntryEvent(Event event) {
- MethodEntryEvent me = (MethodEntryEvent)event;
- }
-
- private void methodExitEvent(Event event) {
- MethodExitEvent me = (MethodExitEvent)event;
- }
-
- private void fieldWatchEvent(Event event) {
- WatchpointEvent fwe = (WatchpointEvent)event;
- }
-
- private void classPrepareEvent(Event event) {
- ClassPrepareEvent cle = (ClassPrepareEvent)event;
- }
-
- private void exceptionEvent(Event event) {
- ExceptionEvent ee = (ExceptionEvent)event;
- }
-
- private void threadDeathEvent(Event event) {
- ThreadDeathEvent tee = (ThreadDeathEvent)event;
- }
-
- private void threadStartEvent(Event event) {
- ThreadStartEvent tse = (ThreadStartEvent)event;
- }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDIExecutionControl.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,598 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-import static jdk.internal.jshell.remote.RemoteCodes.*;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.PrintStream;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.io.EOFException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import com.sun.jdi.BooleanValue;
-import com.sun.jdi.ClassNotLoadedException;
-import com.sun.jdi.IncompatibleThreadStateException;
-import com.sun.jdi.InvalidTypeException;
-import com.sun.jdi.ObjectReference;
-import com.sun.jdi.ReferenceType;
-import com.sun.jdi.StackFrame;
-import com.sun.jdi.ThreadReference;
-import com.sun.jdi.VirtualMachine;
-import static java.util.stream.Collectors.toList;
-import jdk.jshell.JShellException;
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-import jdk.internal.jshell.jdi.ClassTracker.ClassInfo;
-import static java.util.stream.Collectors.toMap;
-import jdk.internal.jshell.debug.InternalDebugControl;
-import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
-
-/**
- * Controls the remote execution environment.
- * Interfaces to the JShell-core by implementing ExecutionControl SPI.
- * Interfaces to RemoteAgent over a socket and via JDI.
- * Launches a remote process.
- */
-public class JDIExecutionControl implements ExecutionControl {
-
- ExecutionEnv execEnv;
- private final boolean isLaunch;
- private JDIConnection connection;
- private ClassTracker classTracker;
- private Socket socket;
- private ObjectInputStream remoteIn;
- private ObjectOutputStream remoteOut;
-
- /**
- * Creates an ExecutionControl instance based on JDI.
- *
- * @param isLaunch true for LaunchingConnector; false for ListeningConnector
- */
- public JDIExecutionControl(boolean isLaunch) {
- this.isLaunch = isLaunch;
- }
-
- /**
- * Creates an ExecutionControl instance based on a JDI LaunchingConnector.
- */
- public JDIExecutionControl() {
- this.isLaunch = true;
- }
-
- /**
- * Initializes the launching JDI execution engine. Initialize JDI and use it
- * to launch the remote JVM. Set-up control and result communications socket
- * to the remote execution environment. This socket also transports the
- * input/output channels.
- *
- * @param execEnv the execution environment provided by the JShell-core
- * @throws IOException
- */
- @Override
- public void start(ExecutionEnv execEnv) throws IOException {
- this.execEnv = execEnv;
- StringBuilder sb = new StringBuilder();
- try (ServerSocket listener = new ServerSocket(0)) {
- // timeout after 60 seconds
- listener.setSoTimeout(60000);
- int port = listener.getLocalPort();
- connection = new JDIConnection(this, port, execEnv.extraRemoteVMOptions(), isLaunch);
- this.socket = listener.accept();
- // out before in -- match remote creation so we don't hang
- this.remoteOut = new ObjectOutputStream(socket.getOutputStream());
- PipeInputStream commandIn = new PipeInputStream();
- new DemultiplexInput(socket.getInputStream(), commandIn, execEnv.userOut(), execEnv.userErr()).start();
- this.remoteIn = new ObjectInputStream(commandIn);
- }
- }
-
- /**
- * Closes the execution engine. Send an exit command to the remote agent.
- * Shuts down the JDI connection. Should this close the socket?
- */
- @Override
- public void close() {
- try {
- if (connection != null) {
- connection.beginShutdown();
- }
- if (remoteOut != null) {
- remoteOut.writeInt(CMD_EXIT);
- remoteOut.flush();
- }
- if (connection != null) {
- connection.disposeVM();
- }
- } catch (IOException ex) {
- debug(DBG_GEN, "Exception on JDI exit: %s\n", ex);
- }
- }
-
- /**
- * Loads the list of classes specified. Sends a load command to the remote
- * agent with pairs of classname/bytes.
- *
- * @param classes the names of the wrapper classes to loaded
- * @return true if all classes loaded successfully
- */
- @Override
- public boolean load(Collection<String> classes) {
- try {
- // Create corresponding ClassInfo instances to track the classes.
- // Each ClassInfo has the current class bytes associated with it.
- List<ClassInfo> infos = withBytes(classes);
- // Send a load command to the remote agent.
- remoteOut.writeInt(CMD_LOAD);
- remoteOut.writeInt(classes.size());
- for (ClassInfo ci : infos) {
- remoteOut.writeUTF(ci.getClassName());
- remoteOut.writeObject(ci.getBytes());
- }
- remoteOut.flush();
- // Retrieve and report results from the remote agent.
- boolean result = readAndReportResult();
- // For each class that now has a JDI ReferenceType, mark the bytes
- // as loaded.
- infos.stream()
- .filter(ci -> ci.getReferenceTypeOrNull() != null)
- .forEach(ci -> ci.markLoaded());
- return result;
- } catch (IOException ex) {
- debug(DBG_GEN, "IOException on remote load operation: %s\n", ex);
- return false;
- }
- }
-
- /**
- * Invoke the doit method on the specified class.
- *
- * @param classname name of the wrapper class whose doit should be invoked
- * @return return the result value of the doit
- * @throws JShellException if a user exception was thrown (EvalException) or
- * an unresolved reference was encountered (UnresolvedReferenceException)
- */
- @Override
- public String invoke(String classname, String methodname) throws JShellException {
- try {
- synchronized (STOP_LOCK) {
- userCodeRunning = true;
- }
- // Send the invoke command to the remote agent.
- remoteOut.writeInt(CMD_INVOKE);
- remoteOut.writeUTF(classname);
- remoteOut.writeUTF(methodname);
- remoteOut.flush();
- // Retrieve and report results from the remote agent.
- if (readAndReportExecutionResult()) {
- String result = remoteIn.readUTF();
- return result;
- }
- } catch (IOException | RuntimeException ex) {
- if (!connection.isRunning()) {
- // The JDI connection is no longer live, shutdown.
- handleVMExit();
- } else {
- debug(DBG_GEN, "Exception on remote invoke: %s\n", ex);
- return "Execution failure: " + ex.getMessage();
- }
- } finally {
- synchronized (STOP_LOCK) {
- userCodeRunning = false;
- }
- }
- return "";
- }
-
- /**
- * Retrieves the value of a JShell variable.
- *
- * @param classname name of the wrapper class holding the variable
- * @param varname name of the variable
- * @return the value as a String
- */
- @Override
- public String varValue(String classname, String varname) {
- try {
- // Send the variable-value command to the remote agent.
- remoteOut.writeInt(CMD_VARVALUE);
- remoteOut.writeUTF(classname);
- remoteOut.writeUTF(varname);
- remoteOut.flush();
- // Retrieve and report results from the remote agent.
- if (readAndReportResult()) {
- String result = remoteIn.readUTF();
- return result;
- }
- } catch (EOFException ex) {
- handleVMExit();
- } catch (IOException ex) {
- debug(DBG_GEN, "Exception on remote var value: %s\n", ex);
- return "Execution failure: " + ex.getMessage();
- }
- return "";
- }
-
- /**
- * Adds a path to the remote classpath.
- *
- * @param cp the additional path element
- * @return true if succesful
- */
- @Override
- public boolean addToClasspath(String cp) {
- try {
- // Send the classpath addition command to the remote agent.
- remoteOut.writeInt(CMD_CLASSPATH);
- remoteOut.writeUTF(cp);
- remoteOut.flush();
- // Retrieve and report results from the remote agent.
- return readAndReportResult();
- } catch (IOException ex) {
- throw new InternalError("Classpath addition failed: " + cp, ex);
- }
- }
-
- /**
- * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI,
- * an in-place replacement of the classes (preserving class identity) --
- * that is, existing references to the class do not need to be recompiled.
- * This implementation uses JDI redefineClasses. It will be unsuccessful if
- * the signature of the class has changed (see the JDI spec). The
- * JShell-core is designed to adapt to unsuccessful redefine.
- *
- * @param classes the names of the classes to redefine
- * @return true if all the classes were redefined
- */
- @Override
- public boolean redefine(Collection<String> classes) {
- try {
- // Create corresponding ClassInfo instances to track the classes.
- // Each ClassInfo has the current class bytes associated with it.
- List<ClassInfo> infos = withBytes(classes);
- // Convert to the JDI ReferenceType to class bytes map form needed
- // by JDI.
- Map<ReferenceType, byte[]> rmp = infos.stream()
- .collect(toMap(
- ci -> ci.getReferenceTypeOrNull(),
- ci -> ci.getBytes()));
- // Attempt redefine. Throws exceptions on failure.
- connection.vm().redefineClasses(rmp);
- // Successful: mark the bytes as loaded.
- infos.stream()
- .forEach(ci -> ci.markLoaded());
- return true;
- } catch (UnsupportedOperationException ex) {
- // A form of class transformation not supported by JDI
- return false;
- } catch (Exception ex) {
- debug(DBG_GEN, "Exception on JDI redefine: %s\n", ex);
- return false;
- }
- }
-
- // the VM has gone down in flames or because user evaled System.exit() or the like
- void handleVMExit() {
- if (connection != null) {
- // If there is anything left dispose of it
- connection.disposeVM();
- }
- // Tell JShell-core that the VM has died
- execEnv.closeDown();
- }
-
- // Lazy init class tracker
- private ClassTracker classTracker() {
- if (classTracker == null) {
- classTracker = new ClassTracker(connection.vm());
- }
- return classTracker;
- }
-
- /**
- * Converts a collection of class names into ClassInfo instances associated
- * with the most recently compiled class bytes.
- *
- * @param classes names of the classes
- * @return a list of corresponding ClassInfo instances
- */
- private List<ClassInfo> withBytes(Collection<String> classes) {
- return classes.stream()
- .map(cn -> classTracker().classInfo(cn, execEnv.getClassBytes(cn)))
- .collect(toList());
- }
-
- /**
- * Reports the status of the named class. UNKNOWN if not loaded. CURRENT if
- * the most recent successfully loaded/redefined bytes match the current
- * compiled bytes.
- *
- * @param classname the name of the class to test
- * @return the status
- */
- @Override
- public ClassStatus getClassStatus(String classname) {
- ClassInfo ci = classTracker().get(classname);
- if (ci.getReferenceTypeOrNull() == null) {
- // If the class does not have a JDI ReferenceType it has not been loaded
- return ClassStatus.UNKNOWN;
- }
- // Compare successfully loaded with last compiled bytes.
- return (Arrays.equals(execEnv.getClassBytes(classname), ci.getLoadedBytes()))
- ? ClassStatus.CURRENT
- : ClassStatus.NOT_CURRENT;
- }
-
- /**
- * Reports results from a remote agent command that does not expect
- * exceptions.
- *
- * @return true if successful
- * @throws IOException if the connection has dropped
- */
- private boolean readAndReportResult() throws IOException {
- int ok = remoteIn.readInt();
- switch (ok) {
- case RESULT_SUCCESS:
- return true;
- case RESULT_FAIL: {
- String ex = remoteIn.readUTF();
- debug(DBG_GEN, "Exception on remote operation: %s\n", ex);
- return false;
- }
- default: {
- debug(DBG_GEN, "Bad remote result code: %s\n", ok);
- return false;
- }
- }
- }
-
- /**
- * Reports results from a remote agent command that expects runtime
- * exceptions.
- *
- * @return true if successful
- * @throws IOException if the connection has dropped
- * @throws EvalException if a user exception was encountered on invoke
- * @throws UnresolvedReferenceException if an unresolved reference was
- * encountered
- */
- private boolean readAndReportExecutionResult() throws IOException, JShellException {
- int ok = remoteIn.readInt();
- switch (ok) {
- case RESULT_SUCCESS:
- return true;
- case RESULT_FAIL: {
- // An internal error has occurred.
- String ex = remoteIn.readUTF();
- return false;
- }
- case RESULT_EXCEPTION: {
- // A user exception was encountered.
- String exceptionClassName = remoteIn.readUTF();
- String message = remoteIn.readUTF();
- StackTraceElement[] elems = readStackTrace();
- throw execEnv.createEvalException(message, exceptionClassName, elems);
- }
- case RESULT_CORRALLED: {
- // An unresolved reference was encountered.
- int id = remoteIn.readInt();
- StackTraceElement[] elems = readStackTrace();
- throw execEnv.createUnresolvedReferenceException(id, elems);
- }
- case RESULT_KILLED: {
- // Execution was aborted by the stop()
- debug(DBG_GEN, "Killed.");
- return false;
- }
- default: {
- debug(DBG_GEN, "Bad remote result code: %s\n", ok);
- return false;
- }
- }
- }
-
- private StackTraceElement[] readStackTrace() throws IOException {
- int elemCount = remoteIn.readInt();
- StackTraceElement[] elems = new StackTraceElement[elemCount];
- for (int i = 0; i < elemCount; ++i) {
- String className = remoteIn.readUTF();
- String methodName = remoteIn.readUTF();
- String fileName = remoteIn.readUTF();
- int line = remoteIn.readInt();
- elems[i] = new StackTraceElement(className, methodName, fileName, line);
- }
- return elems;
- }
-
- private final Object STOP_LOCK = new Object();
- private boolean userCodeRunning = false;
-
- /**
- * Interrupt a running invoke.
- */
- @Override
- public void stop() {
- synchronized (STOP_LOCK) {
- if (!userCodeRunning) {
- return;
- }
-
- VirtualMachine vm = connection.vm();
- vm.suspend();
- try {
- OUTER:
- for (ThreadReference thread : vm.allThreads()) {
- // could also tag the thread (e.g. using name), to find it easier
- for (StackFrame frame : thread.frames()) {
- String remoteAgentName = "jdk.internal.jshell.remote.RemoteAgent";
- if (remoteAgentName.equals(frame.location().declaringType().name())
- && "commandLoop".equals(frame.location().method().name())) {
- ObjectReference thiz = frame.thisObject();
- if (((BooleanValue) thiz.getValue(thiz.referenceType().fieldByName("inClientCode"))).value()) {
- thiz.setValue(thiz.referenceType().fieldByName("expectingStop"), vm.mirrorOf(true));
- ObjectReference stopInstance = (ObjectReference) thiz.getValue(thiz.referenceType().fieldByName("stopException"));
-
- vm.resume();
- debug(DBG_GEN, "Attempting to stop the client code...\n");
- thread.stop(stopInstance);
- thiz.setValue(thiz.referenceType().fieldByName("expectingStop"), vm.mirrorOf(false));
- }
-
- break OUTER;
- }
- }
- }
- } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) {
- debug(DBG_GEN, "Exception on remote stop: %s\n", ex);
- } finally {
- vm.resume();
- }
- }
- }
-
- void debug(int flags, String format, Object... args) {
- InternalDebugControl.debug(execEnv.state(), execEnv.userErr(), flags, format, args);
- }
-
- void debug(Exception ex, String where) {
- InternalDebugControl.debug(execEnv.state(), execEnv.userErr(), ex, where);
- }
-
- private final class DemultiplexInput extends Thread {
-
- private final DataInputStream delegate;
- private final PipeInputStream command;
- private final PrintStream out;
- private final PrintStream err;
-
- public DemultiplexInput(InputStream input,
- PipeInputStream command,
- PrintStream out,
- PrintStream err) {
- super("output reader");
- this.delegate = new DataInputStream(input);
- this.command = command;
- this.out = out;
- this.err = err;
- }
-
- public void run() {
- try {
- while (true) {
- int nameLen = delegate.read();
- if (nameLen == (-1))
- break;
- byte[] name = new byte[nameLen];
- DemultiplexInput.this.delegate.readFully(name);
- int dataLen = delegate.read();
- byte[] data = new byte[dataLen];
- DemultiplexInput.this.delegate.readFully(data);
- switch (new String(name, "UTF-8")) {
- case "err":
- err.write(data);
- break;
- case "out":
- out.write(data);
- break;
- case "command":
- for (byte b : data) {
- command.write(Byte.toUnsignedInt(b));
- }
- break;
- }
- }
- } catch (IOException ex) {
- debug(ex, "Failed reading output");
- } finally {
- command.close();
- }
- }
-
- }
-
- public static final class PipeInputStream extends InputStream {
- public static final int INITIAL_SIZE = 128;
-
- private int[] buffer = new int[INITIAL_SIZE];
- private int start;
- private int end;
- private boolean closed;
-
- @Override
- public synchronized int read() {
- while (start == end) {
- if (closed) {
- return -1;
- }
- try {
- wait();
- } catch (InterruptedException ex) {
- //ignore
- }
- }
- try {
- return buffer[start];
- } finally {
- start = (start + 1) % buffer.length;
- }
- }
-
- public synchronized void write(int b) {
- if (closed)
- throw new IllegalStateException("Already closed.");
- int newEnd = (end + 1) % buffer.length;
- if (newEnd == start) {
- //overflow:
- int[] newBuffer = new int[buffer.length * 2];
- int rightPart = (end > start ? end : buffer.length) - start;
- int leftPart = end > start ? 0 : start - 1;
- System.arraycopy(buffer, start, newBuffer, 0, rightPart);
- System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart);
- buffer = newBuffer;
- start = 0;
- end = rightPart + leftPart;
- newEnd = end + 1;
- }
- buffer[end] = b;
- end = newEnd;
- notifyAll();
- }
-
- @Override
- public synchronized void close() {
- closed = true;
- notifyAll();
- }
-
- }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/jdi/JDINotConnectedException.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.jdi;
-
-/**
- * Internal exception when Java Debug Interface VirtualMacine is not connected.
- * Copy of jdb VMNotConnectedException.
- */
-class JDINotConnectedException extends RuntimeException {
-
- private static final long serialVersionUID = -7433430494903950165L;
-
- public JDINotConnectedException() {
- super();
- }
-
- public JDINotConnectedException(String s) {
- super(s);
- }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,326 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-import jdk.jshell.spi.SPIResolutionException;
-import java.io.File;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.Socket;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static jdk.internal.jshell.remote.RemoteCodes.*;
-
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * The remote agent runs in the execution process (separate from the main JShell
- * process. This agent loads code over a socket from the main JShell process,
- * executes the code, and other misc,
- * @author Robert Field
- */
-class RemoteAgent {
-
- private final RemoteClassLoader loader = new RemoteClassLoader();
- private final Map<String, Class<?>> klasses = new TreeMap<>();
-
- public static void main(String[] args) throws Exception {
- String loopBack = null;
- Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
- (new RemoteAgent()).commandLoop(socket);
- }
-
- void commandLoop(Socket socket) throws IOException {
- // in before out -- so we don't hang the controlling process
- ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
- OutputStream socketOut = socket.getOutputStream();
- System.setOut(new PrintStream(new MultiplexingOutputStream("out", socketOut), true));
- System.setErr(new PrintStream(new MultiplexingOutputStream("err", socketOut), true));
- ObjectOutputStream out = new ObjectOutputStream(new MultiplexingOutputStream("command", socketOut));
- while (true) {
- int cmd = in.readInt();
- switch (cmd) {
- case CMD_EXIT:
- // Terminate this process
- return;
- case CMD_LOAD:
- // Load a generated class file over the wire
- try {
- int count = in.readInt();
- List<String> names = new ArrayList<>(count);
- for (int i = 0; i < count; ++i) {
- String name = in.readUTF();
- byte[] kb = (byte[]) in.readObject();
- loader.delare(name, kb);
- names.add(name);
- }
- for (String name : names) {
- Class<?> klass = loader.loadClass(name);
- klasses.put(name, klass);
- // Get class loaded to the point of, at least, preparation
- klass.getDeclaredMethods();
- }
- out.writeInt(RESULT_SUCCESS);
- out.flush();
- } catch (IOException | ClassNotFoundException | ClassCastException ex) {
- debug("*** Load failure: %s\n", ex);
- out.writeInt(RESULT_FAIL);
- out.writeUTF(ex.toString());
- out.flush();
- }
- break;
- case CMD_INVOKE: {
- // Invoke executable entry point in loaded code
- String name = in.readUTF();
- Class<?> klass = klasses.get(name);
- if (klass == null) {
- debug("*** Invoke failure: no such class loaded %s\n", name);
- out.writeInt(RESULT_FAIL);
- out.writeUTF("no such class loaded: " + name);
- out.flush();
- break;
- }
- String methodName = in.readUTF();
- Method doitMethod;
- try {
- this.getClass().getModule().addExports(SPIResolutionException.class.getPackage().getName(), klass.getModule());
- doitMethod = klass.getDeclaredMethod(methodName, new Class<?>[0]);
- doitMethod.setAccessible(true);
- Object res;
- try {
- clientCodeEnter();
- res = doitMethod.invoke(null, new Object[0]);
- } catch (InvocationTargetException ex) {
- if (ex.getCause() instanceof StopExecutionException) {
- expectingStop = false;
- throw (StopExecutionException) ex.getCause();
- }
- throw ex;
- } catch (StopExecutionException ex) {
- expectingStop = false;
- throw ex;
- } finally {
- clientCodeLeave();
- }
- out.writeInt(RESULT_SUCCESS);
- out.writeUTF(valueString(res));
- out.flush();
- } catch (InvocationTargetException ex) {
- Throwable cause = ex.getCause();
- StackTraceElement[] elems = cause.getStackTrace();
- if (cause instanceof SPIResolutionException) {
- out.writeInt(RESULT_CORRALLED);
- out.writeInt(((SPIResolutionException) cause).id());
- } else {
- out.writeInt(RESULT_EXCEPTION);
- out.writeUTF(cause.getClass().getName());
- out.writeUTF(cause.getMessage() == null ? "<none>" : cause.getMessage());
- }
- out.writeInt(elems.length);
- for (StackTraceElement ste : elems) {
- out.writeUTF(ste.getClassName());
- out.writeUTF(ste.getMethodName());
- out.writeUTF(ste.getFileName() == null ? "<none>" : ste.getFileName());
- out.writeInt(ste.getLineNumber());
- }
- out.flush();
- } catch (NoSuchMethodException | IllegalAccessException ex) {
- debug("*** Invoke failure: %s -- %s\n", ex, ex.getCause());
- out.writeInt(RESULT_FAIL);
- out.writeUTF(ex.toString());
- out.flush();
- } catch (StopExecutionException ex) {
- try {
- out.writeInt(RESULT_KILLED);
- out.flush();
- } catch (IOException err) {
- debug("*** Error writing killed result: %s -- %s\n", ex, ex.getCause());
- }
- }
- System.out.flush();
- break;
- }
- case CMD_VARVALUE: {
- // Retrieve a variable value
- String classname = in.readUTF();
- String varname = in.readUTF();
- Class<?> klass = klasses.get(classname);
- if (klass == null) {
- debug("*** Var value failure: no such class loaded %s\n", classname);
- out.writeInt(RESULT_FAIL);
- out.writeUTF("no such class loaded: " + classname);
- out.flush();
- break;
- }
- try {
- Field var = klass.getDeclaredField(varname);
- var.setAccessible(true);
- Object res = var.get(null);
- out.writeInt(RESULT_SUCCESS);
- out.writeUTF(valueString(res));
- out.flush();
- } catch (Exception ex) {
- debug("*** Var value failure: no such field %s.%s\n", classname, varname);
- out.writeInt(RESULT_FAIL);
- out.writeUTF("no such field loaded: " + varname + " in class: " + classname);
- out.flush();
- }
- break;
- }
- case CMD_CLASSPATH: {
- // Append to the claspath
- String cp = in.readUTF();
- for (String path : cp.split(File.pathSeparator)) {
- loader.addURL(new File(path).toURI().toURL());
- }
- out.writeInt(RESULT_SUCCESS);
- out.flush();
- break;
- }
- default:
- debug("*** Bad command code: %d\n", cmd);
- break;
- }
- }
- }
-
- // These three variables are used by the main JShell process in interrupting
- // the running process. Access is via JDI, so the reference is not visible
- // to code inspection.
- private boolean inClientCode; // Queried by the main process
- private boolean expectingStop; // Set by the main process
-
- // thrown by the main process via JDI:
- private final StopExecutionException stopException = new StopExecutionException();
-
- @SuppressWarnings("serial") // serialVersionUID intentionally omitted
- private class StopExecutionException extends ThreadDeath {
- @Override public synchronized Throwable fillInStackTrace() {
- return this;
- }
- }
-
- void clientCodeEnter() {
- expectingStop = false;
- inClientCode = true;
- }
-
- void clientCodeLeave() {
- inClientCode = false;
- while (expectingStop) {
- try {
- Thread.sleep(0);
- } catch (InterruptedException ex) {
- debug("*** Sleep interrupted while waiting for stop exception: %s\n", ex);
- }
- }
- }
-
- private void debug(String format, Object... args) {
- System.err.printf("REMOTE: "+format, args);
- }
-
- static String valueString(Object value) {
- if (value == null) {
- return "null";
- } else if (value instanceof String) {
- return "\"" + (String)value + "\"";
- } else if (value instanceof Character) {
- return "'" + value + "'";
- } else {
- return value.toString();
- }
- }
-
- private static final class MultiplexingOutputStream extends OutputStream {
-
- private static final int PACKET_SIZE = 127;
-
- private final byte[] name;
- private final OutputStream delegate;
-
- public MultiplexingOutputStream(String name, OutputStream delegate) {
- try {
- this.name = name.getBytes("UTF-8");
- this.delegate = delegate;
- } catch (UnsupportedEncodingException ex) {
- throw new IllegalStateException(ex); //should not happen
- }
- }
-
- @Override
- public void write(int b) throws IOException {
- synchronized (delegate) {
- delegate.write(name.length); //assuming the len is small enough to fit into byte
- delegate.write(name);
- delegate.write(1);
- delegate.write(b);
- delegate.flush();
- }
- }
-
- @Override
- public void write(byte[] b, int off, int len) throws IOException {
- synchronized (delegate) {
- int i = 0;
- while (len > 0) {
- int size = Math.min(PACKET_SIZE, len);
-
- delegate.write(name.length); //assuming the len is small enough to fit into byte
- delegate.write(name);
- delegate.write(size);
- delegate.write(b, off + i, size);
- i += size;
- len -= size;
- }
-
- delegate.flush();
- }
- }
-
- @Override
- public void flush() throws IOException {
- super.flush();
- delegate.flush();
- }
-
- @Override
- public void close() throws IOException {
- super.close();
- delegate.close();
- }
-
- }
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteClassLoader.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * Class loader wrapper which caches class files by name until requested.
- * @author Robert Field
- */
-class RemoteClassLoader extends URLClassLoader {
-
- private final Map<String, byte[]> classObjects = new TreeMap<>();
-
- RemoteClassLoader() {
- super(new URL[0]);
- }
-
- void delare(String name, byte[] bytes) {
- classObjects.put(name, bytes);
- }
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- byte[] b = classObjects.get(name);
- if (b == null) {
- return super.findClass(name);
- }
- return super.defineClass(name, b, 0, b.length, (CodeSource) null);
- }
-
- @Override
- public void addURL(URL url) {
- super.addURL(url);
- }
-
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteCodes.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.jshell.remote;
-
-/**
- * Communication constants shared between the main process and the remote
- * execution process
- * @author Robert Field
- */
-public class RemoteCodes {
- // Command codes
- public static final int CMD_EXIT = 0;
- public static final int CMD_LOAD = 1;
- public static final int CMD_INVOKE = 3;
- public static final int CMD_CLASSPATH = 4;
- public static final int CMD_VARVALUE = 5;
-
- // Return result codes
- public static final int RESULT_SUCCESS = 100;
- public static final int RESULT_FAIL = 101;
- public static final int RESULT_EXCEPTION = 102;
- public static final int RESULT_CORRALLED = 103;
- public static final int RESULT_KILLED = 104;
-}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java Wed Jul 27 13:33:55 2016 +0000
@@ -233,6 +233,7 @@
private static final String DOCUMENTATION_SHORTCUT = "\033\133\132"; //Shift-TAB
private static final String[] SHORTCUT_FIXES = {
"\033\015", //Alt-Enter (Linux)
+ "\033\012", //Alt-Enter (Linux)
"\033\133\061\067\176", //F6/Alt-F1 (Mac)
"\u001BO3P" //Alt-F1 (Linux)
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ClassTracker.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Objects;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+
+/**
+ * Tracks the state of a class.
+ */
+class ClassTracker {
+
+ private final HashMap<String, ClassInfo> map;
+
+ ClassTracker() {
+ this.map = new HashMap<>();
+ }
+
+ /**
+ * Associates a class name, class bytes (current and loaded).
+ */
+ class ClassInfo {
+
+ // The name of the class
+ private final String className;
+
+ // The corresponding compiled class bytes when a load or redefine
+ // is started. May not be the loaded bytes. May be null.
+ private byte[] currentBytes;
+
+ // The class bytes successfully loaded/redefined into the remote VM.
+ private byte[] loadedBytes;
+
+ private ClassInfo(String className) {
+ this.className = className;
+ }
+
+ String getClassName() {
+ return className;
+ }
+
+ byte[] getLoadedBytes() {
+ return loadedBytes;
+ }
+
+ byte[] getCurrentBytes() {
+ return currentBytes;
+ }
+
+ void setCurrentBytes(byte[] bytes) {
+ this.currentBytes = bytes;
+ }
+
+ void setLoadedBytes(byte[] bytes) {
+ this.loadedBytes = bytes;
+ }
+
+ boolean isLoaded() {
+ return loadedBytes != null;
+ }
+
+ boolean isCurrent() {
+ return Arrays.equals(currentBytes, loadedBytes);
+ }
+
+ ClassBytecodes toClassBytecodes() {
+ return new ClassBytecodes(className, currentBytes);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof ClassInfo
+ && ((ClassInfo) o).className.equals(className);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.className);
+ }
+ }
+
+ void markLoaded(ClassBytecodes[] cbcs) {
+ for (ClassBytecodes cbc : cbcs) {
+ get(cbc.name()).setLoadedBytes(cbc.bytecodes());
+ }
+ }
+
+ void markLoaded(ClassBytecodes[] cbcs, boolean[] isLoaded) {
+ for (int i = 0; i < cbcs.length; ++i) {
+ if (isLoaded[i]) {
+ ClassBytecodes cbc = cbcs[i];
+ get(cbc.name()).setLoadedBytes(cbc.bytecodes());
+ }
+ }
+ }
+
+ // Map a class name to the current compiled class bytes.
+ void setCurrentBytes(String className, byte[] bytes) {
+ ClassInfo ci = get(className);
+ ci.setCurrentBytes(bytes);
+ }
+
+ // Lookup the ClassInfo by class name, create if it does not exist.
+ ClassInfo get(String className) {
+ return map.computeIfAbsent(className, k -> new ClassInfo(k));
+ }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java Wed Jul 27 13:33:55 2016 +0000
@@ -61,6 +61,14 @@
import jdk.jshell.TreeDissector.ExpressionInfo;
import jdk.jshell.Wrap.Range;
import jdk.jshell.Snippet.Status;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+import jdk.jshell.spi.ExecutionControl.ResolutionException;
+import jdk.jshell.spi.ExecutionControl.RunException;
+import jdk.jshell.spi.ExecutionControl.UserException;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static java.util.Collections.singletonList;
@@ -541,15 +549,21 @@
if (si.status().isDefined()) {
if (si.isExecutable()) {
try {
- value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
+ value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
value = si.subKind().hasValue()
? expunge(value)
: "";
- } catch (EvalException ex) {
+ } catch (ResolutionException ex) {
+ DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(ex.id());
+ exception = new UnresolvedReferenceException(sn, ex.getStackTrace());
+ } catch (UserException ex) {
exception = translateExecutionException(ex);
- } catch (JShellException ex) {
- // UnresolvedReferenceException
- exception = ex;
+ } catch (RunException ex) {
+ // StopException - no-op
+ } catch (InternalException ex) {
+ state.debug(ex, "invoke");
+ } catch (EngineTerminationException ex) {
+ state.closeDown();
}
} else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
switch (((VarSnippet) si).typeName()) {
@@ -700,15 +714,25 @@
/**
* If there are classes to load, loads by calling the execution engine.
- * @param classnames names of the classes to load.
+ * @param classbytecoes names of the classes to load.
*/
- private void load(Collection<String> classnames) {
- if (!classnames.isEmpty()) {
- state.executionControl().load(classnames);
+ private void load(Collection<ClassBytecodes> classbytecoes) {
+ if (!classbytecoes.isEmpty()) {
+ ClassBytecodes[] cbcs = classbytecoes.toArray(new ClassBytecodes[classbytecoes.size()]);
+ try {
+ state.executionControl().load(cbcs);
+ state.classTracker.markLoaded(cbcs);
+ } catch (ClassInstallException ex) {
+ state.classTracker.markLoaded(cbcs, ex.installed());
+ } catch (NotImplementedException ex) {
+ state.debug(ex, "Seriously?!? load not implemented");
+ } catch (EngineTerminationException ex) {
+ state.closeDown();
+ }
}
}
- private EvalException translateExecutionException(EvalException ex) {
+ private EvalException translateExecutionException(UserException ex) {
StackTraceElement[] raw = ex.getStackTrace();
int last = raw.length;
do {
@@ -739,7 +763,7 @@
if (msg.equals("<none>")) {
msg = null;
}
- return new EvalException(msg, ex.getExceptionClassName(), elems);
+ return new EvalException(msg, ex.causeExceptionClass(), elems);
}
private boolean isWrap(StackTraceElement ste) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java Wed Jul 27 13:33:55 2016 +0000
@@ -44,13 +44,15 @@
import java.util.function.Supplier;
import jdk.internal.jshell.debug.InternalDebugControl;
-import jdk.internal.jshell.jdi.FailOverExecutionControl;
+import jdk.jshell.Snippet.Status;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
+import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toList;
import static jdk.jshell.Util.expunge;
-import jdk.jshell.Snippet.Status;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
/**
* The JShell evaluation state engine. This is the central class in the JShell
@@ -90,17 +92,17 @@
final BiFunction<Snippet, Integer, String> idGenerator;
final List<String> extraRemoteVMOptions;
final List<String> extraCompilerOptions;
- final ExecutionControl executionControl;
+ final ExecutionControl.Generator executionControlGenerator;
private int nextKeyIndex = 1;
final Eval eval;
- private final Map<String, byte[]> classnameToBytes = new HashMap<>();
+ final ClassTracker classTracker;
private final Map<Subscription, Consumer<JShell>> shutdownListeners = new HashMap<>();
private final Map<Subscription, Consumer<SnippetEvent>> keyStatusListeners = new HashMap<>();
private boolean closed = false;
- private boolean executionControlLaunched = false;
+ private ExecutionControl executionControl = null;
private SourceCodeAnalysisImpl sourceCodeAnalysis = null;
private static final String L10N_RB_NAME = "jdk.jshell.resources.l10n";
@@ -114,17 +116,18 @@
this.idGenerator = b.idGenerator;
this.extraRemoteVMOptions = b.extraRemoteVMOptions;
this.extraCompilerOptions = b.extraCompilerOptions;
- this.executionControl = b.executionControl==null
- ? new FailOverExecutionControl(
- new JDIExecutionControl(),
- new JDIExecutionControl(false))
- : b.executionControl;
+ this.executionControlGenerator = b.executionControlGenerator==null
+ ? failOverExecutionControlGenerator(
+ JDIDefaultExecutionControl.launch(),
+ JDIDefaultExecutionControl.listen())
+ : b.executionControlGenerator;
this.maps = new SnippetMaps(this);
this.keyMap = new KeyMap(this);
this.outerMap = new OuterWrapMap(this);
this.taskFactory = new TaskFactory(this);
this.eval = new Eval(this);
+ this.classTracker = new ClassTracker();
}
/**
@@ -154,7 +157,7 @@
BiFunction<Snippet, Integer, String> idGenerator = null;
List<String> extraRemoteVMOptions = new ArrayList<>();
List<String> extraCompilerOptions = new ArrayList<>();
- ExecutionControl executionControl;
+ ExecutionControl.Generator executionControlGenerator;
Builder() { }
@@ -310,12 +313,12 @@
* Sets the custom engine for execution. Snippet execution will be
* provided by the specified {@link ExecutionControl} instance.
*
- * @param execEngine the execution engine
+ * @param executionControlGenerator the execution engine generator
* @return the {@code Builder} instance (for use in chained
* initialization)
*/
- public Builder executionEngine(ExecutionControl execEngine) {
- this.executionControl = execEngine;
+ public Builder executionEngine(ExecutionControl.Generator executionControlGenerator) {
+ this.executionControlGenerator = executionControlGenerator;
return this;
}
@@ -397,7 +400,8 @@
* be an event showing its status changed to OVERWRITTEN, this will not
* occur for dropped, rejected, or already overwritten declarations.
* <p>
- * The execution environment is out of process. If the evaluated code
+ * If execution environment is out of process, as is the default case, then
+ * if the evaluated code
* causes the execution environment to terminate, this {@code JShell}
* instance will be closed but the calling process and VM remain valid.
* @param input The input String to evaluate
@@ -447,8 +451,14 @@
* @param path the path to add to the classpath.
*/
public void addToClasspath(String path) {
- taskFactory.addToClasspath(path); // Compiler
- executionControl().addToClasspath(path); // Runtime
+ // Compiler
+ taskFactory.addToClasspath(path);
+ // Runtime
+ try {
+ executionControl().addToClasspath(path);
+ } catch (ExecutionControlException ex) {
+ debug(ex, "on addToClasspath(" + path + ")");
+ }
if (sourceCodeAnalysis != null) {
sourceCodeAnalysis.classpathChanged();
}
@@ -468,8 +478,13 @@
* catching the {@link ThreadDeath} exception.
*/
public void stop() {
- if (executionControl != null)
- executionControl.stop();
+ if (executionControl != null) {
+ try {
+ executionControl.stop();
+ } catch (ExecutionControlException ex) {
+ debug(ex, "on stop()");
+ }
+ }
}
/**
@@ -622,7 +637,15 @@
throw new IllegalArgumentException(
messageFormat("jshell.exc.var.not.valid", snippet, snippet.status()));
}
- String value = executionControl().varValue(snippet.classFullName(), snippet.name());
+ String value;
+ try {
+ value = executionControl().varValue(snippet.classFullName(), snippet.name());
+ } catch (EngineTerminationException ex) {
+ throw new IllegalStateException(ex.getMessage());
+ } catch (ExecutionControlException ex) {
+ debug(ex, "In varValue()");
+ return "[" + ex.getMessage() + "]";
+ }
return expunge(value);
}
@@ -696,43 +719,22 @@
}
@Override
- public JShell state() {
- return JShell.this;
- }
-
- @Override
public List<String> extraRemoteVMOptions() {
return extraRemoteVMOptions;
}
@Override
- public byte[] getClassBytes(String classname) {
- return classnameToBytes.get(classname);
- }
-
- @Override
- public EvalException createEvalException(String message, String exceptionClass, StackTraceElement[] stackElements) {
- return new EvalException(message, exceptionClass, stackElements);
- }
-
- @Override
- public UnresolvedReferenceException createUnresolvedReferenceException(int id, StackTraceElement[] stackElements) {
- DeclarationSnippet sn = (DeclarationSnippet) maps.getSnippetDeadOrAlive(id);
- return new UnresolvedReferenceException(sn, stackElements);
- }
-
- @Override
public void closeDown() {
JShell.this.closeDown();
}
+
}
// --- private / package-private implementation support ---
ExecutionControl executionControl() {
- if (!executionControlLaunched) {
+ if (executionControl == null) {
try {
- executionControlLaunched = true;
- executionControl.start(new ExecutionEnvImpl());
+ executionControl = executionControlGenerator.generate(new ExecutionEnvImpl());
} catch (Throwable ex) {
throw new InternalError("Launching execution engine threw: " + ex.getMessage(), ex);
}
@@ -740,10 +742,6 @@
return executionControl;
}
- void setClassnameToBytes(String classname, byte[] bytes) {
- classnameToBytes.put(classname, bytes);
- }
-
void debug(int flags, String format, Object... args) {
InternalDebugControl.debug(this, err, flags, format, args);
}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Jul 27 13:33:55 2016 +0000
@@ -82,7 +82,7 @@
throw new UnsupportedOperationException("Compiler not available, must be run with full JDK 9.");
}
Version current = Version.parse(System.getProperty("java.specification.version"));
- if (INITIAL_SUPPORTED_VER.compareToIgnoreOpt(current) > 0) {
+ if (INITIAL_SUPPORTED_VER.compareToIgnoreOptional(current) > 0) {
throw new UnsupportedOperationException("Wrong compiler, must be run with full JDK 9.");
}
this.fileManager = new MemoryFileManager(
@@ -223,7 +223,6 @@
new WrapSourceHandler(),
Util.join(new String[] {
"-Xshouldstop:at=FLOW", "-Xlint:unchecked",
- "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED",
"-proc:none"
}, extraArgs));
}
@@ -267,7 +266,7 @@
CompileTask(final Collection<OuterWrap> wraps) {
super(wraps.stream(), new WrapSourceHandler(),
- "-Xlint:unchecked", "-XaddExports:jdk.jshell/jdk.internal.jshell.remote=ALL-UNNAMED", "-proc:none", "-parameters");
+ "-Xlint:unchecked", "-proc:none", "-parameters");
}
boolean compile() {
@@ -286,7 +285,7 @@
}
List<String> list = new ArrayList<>();
for (OutputMemoryJavaFileObject fo : l) {
- state.setClassnameToBytes(fo.getName(), fo.getBytes());
+ state.classTracker.setCurrentBytes(fo.getName(), fo.getBytes());
list.add(fo.getName());
}
return list;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java Wed Jul 27 13:33:55 2016 +0000
@@ -32,11 +32,16 @@
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
+import jdk.jshell.ClassTracker.ClassInfo;
import jdk.jshell.Snippet.Kind;
import jdk.jshell.Snippet.Status;
import jdk.jshell.Snippet.SubKind;
import jdk.jshell.TaskFactory.AnalyzeTask;
import jdk.jshell.TaskFactory.CompileTask;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_EVNT;
@@ -75,7 +80,7 @@
private SnippetEvent replaceOldEvent;
private List<SnippetEvent> secondaryEvents;
private boolean isAttemptingCorral;
- private List<String> toRedefine;
+ private List<ClassInfo> toRedefine;
private boolean dependenciesNeeded;
Unit(JShell state, Snippet si, Snippet causalSnippet,
@@ -261,30 +266,29 @@
}
/**
- * Process the class information from the last compile.
- * Requires loading of returned list.
+ * Process the class information from the last compile. Requires loading of
+ * returned list.
+ *
* @return the list of classes to load
*/
- Stream<String> classesToLoad(List<String> classnames) {
+ Stream<ClassBytecodes> classesToLoad(List<String> classnames) {
toRedefine = new ArrayList<>();
- List<String> toLoad = new ArrayList<>();
+ List<ClassBytecodes> toLoad = new ArrayList<>();
if (status.isDefined() && !isImport()) {
// Classes should only be loaded/redefined if the compile left them
// in a defined state. Imports do not have code and are not loaded.
for (String cn : classnames) {
- switch (state.executionControl().getClassStatus(cn)) {
- case UNKNOWN:
- // If not loaded, add to the list of classes to load.
- toLoad.add(cn);
- dependenciesNeeded = true;
- break;
- case NOT_CURRENT:
- // If loaded but out of date, add to the list of classes to attempt redefine.
- toRedefine.add(cn);
- break;
- case CURRENT:
- // Loaded and current, so nothing to do
- break;
+ ClassInfo ci = state.classTracker.get(cn);
+ if (ci.isLoaded()) {
+ if (ci.isCurrent()) {
+ // nothing to do
+ } else {
+ toRedefine.add(ci);
+ }
+ } else {
+ // If not loaded, add to the list of classes to load.
+ toLoad.add(ci.toClassBytecodes());
+ dependenciesNeeded = true;
}
}
}
@@ -292,14 +296,30 @@
}
/**
- * Redefine classes needing redefine.
- * classesToLoad() must be called first.
+ * Redefine classes needing redefine. classesToLoad() must be called first.
+ *
* @return true if all redefines succeeded (can be vacuously true)
*/
boolean doRedefines() {
- return toRedefine.isEmpty()
- ? true
- : state.executionControl().redefine(toRedefine);
+ if (toRedefine.isEmpty()) {
+ return true;
+ }
+ ClassBytecodes[] cbcs = toRedefine.stream()
+ .map(ci -> ci.toClassBytecodes())
+ .toArray(size -> new ClassBytecodes[size]);
+ try {
+ state.executionControl().redefine(cbcs);
+ state.classTracker.markLoaded(cbcs);
+ return true;
+ } catch (ClassInstallException ex) {
+ state.classTracker.markLoaded(cbcs, ex.installed());
+ return false;
+ } catch (EngineTerminationException ex) {
+ state.closeDown();
+ return false;
+ } catch (NotImplementedException ex) {
+ return false;
+ }
}
void markForReplacement() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DefaultLoaderDelegate.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.util.Map;
+import java.util.TreeMap;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+
+/**
+ * The standard implementation of {@link LoaderDelegate} using
+ * a {@link URLClassLoader}.
+ *
+ * @author Robert Field
+ */
+class DefaultLoaderDelegate implements LoaderDelegate {
+
+ private final RemoteClassLoader loader;
+ private final Map<String, Class<?>> klasses = new TreeMap<>();
+
+ class RemoteClassLoader extends URLClassLoader {
+
+ private final Map<String, byte[]> classObjects = new TreeMap<>();
+
+ RemoteClassLoader() {
+ super(new URL[0]);
+ }
+
+ void delare(String name, byte[] bytes) {
+ classObjects.put(name, bytes);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ byte[] b = classObjects.get(name);
+ if (b == null) {
+ return super.findClass(name);
+ }
+ return super.defineClass(name, b, 0, b.length, (CodeSource) null);
+ }
+
+ @Override
+ public void addURL(URL url) {
+ super.addURL(url);
+ }
+
+ }
+
+ public DefaultLoaderDelegate() {
+ this.loader = new RemoteClassLoader();
+ }
+
+ @Override
+ public void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, EngineTerminationException {
+ boolean[] loaded = new boolean[cbcs.length];
+ try {
+ for (ClassBytecodes cbc : cbcs) {
+ loader.delare(cbc.name(), cbc.bytecodes());
+ }
+ for (int i = 0; i < cbcs.length; ++i) {
+ ClassBytecodes cbc = cbcs[i];
+ Class<?> klass = loader.loadClass(cbc.name());
+ klasses.put(cbc.name(), klass);
+ loaded[i] = true;
+ // Get class loaded to the point of, at least, preparation
+ klass.getDeclaredMethods();
+ }
+ } catch (Throwable ex) {
+ throw new ClassInstallException("load: " + ex.getMessage(), loaded);
+ }
+ }
+
+
+ @Override
+ public void addToClasspath(String cp)
+ throws EngineTerminationException, InternalException {
+ try {
+ for (String path : cp.split(File.pathSeparator)) {
+ loader.addURL(new File(path).toURI().toURL());
+ }
+ } catch (Exception ex) {
+ throw new InternalException(ex.toString());
+ }
+ }
+
+ @Override
+ public void setClasspath(String path)
+ throws EngineTerminationException, InternalException {
+ throw new NotImplementedException("setClasspath: Not supported yet.");
+ }
+
+ @Override
+ public Class<?> findClass(String name) throws ClassNotFoundException {
+ Class<?> klass = klasses.get(name);
+ if (klass == null) {
+ throw new ClassNotFoundException(name + " not found");
+ } else {
+ return klass;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DemultiplexInput.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+/**
+ * Read from an InputStream which has been packetized and write its contents
+ * to the named OutputStreams.
+ *
+ * @author Jan Lahoda
+ * @see Util#demultiplexInput(java.io.InputStream, java.io.OutputStream, java.io.OutputStream, java.io.OutputStream...)
+ */
+class DemultiplexInput extends Thread {
+
+ private final DataInputStream delegate;
+ private final PipeInputStream command;
+ private final Map<String, OutputStream> io;
+
+ DemultiplexInput(InputStream input, PipeInputStream command,
+ Map<String, OutputStream> io) {
+ super("output reader");
+ this.delegate = new DataInputStream(input);
+ this.command = command;
+ this.io = io;
+ }
+
+ @Override
+ public void run() {
+ try {
+ while (true) {
+ int nameLen = delegate.read();
+ if (nameLen == (-1)) {
+ break;
+ }
+ byte[] name = new byte[nameLen];
+ DemultiplexInput.this.delegate.readFully(name);
+ int dataLen = delegate.read();
+ byte[] data = new byte[dataLen];
+ DemultiplexInput.this.delegate.readFully(data);
+ String chan = new String(name, "UTF-8");
+ if (chan.equals("command")) {
+ for (byte b : data) {
+ command.write(Byte.toUnsignedInt(b));
+ }
+ } else {
+ OutputStream out = io.get(chan);
+ if (out == null) {
+ debug("Unexpected channel name: %s", chan);
+ } else {
+ out.write(data);
+ }
+ }
+ }
+ } catch (IOException ex) {
+ debug(ex, "Failed reading output");
+ } finally {
+ command.close();
+ }
+ }
+
+ /**
+ * Log debugging information. Arguments as for {@code printf}.
+ *
+ * @param format a format string as described in Format string syntax
+ * @param args arguments referenced by the format specifiers in the format
+ * string.
+ */
+ private void debug(String format, Object... args) {
+ // Reserved for future logging
+ }
+
+ /**
+ * Log a serious unexpected internal exception.
+ *
+ * @param ex the exception
+ * @param where a description of the context of the exception
+ */
+ private void debug(Throwable ex, String where) {
+ // Reserved for future logging
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.SPIResolutionException;
+
+/**
+ * An {@link ExecutionControl} implementation that runs in the current process.
+ * May be used directly, or over a channel with
+ * {@link Util#forwardExecutionControl(ExecutionControl, java.io.ObjectInput, java.io.ObjectOutput) }.
+ *
+ * @author Robert Field
+ * @author Jan Lahoda
+ */
+public class DirectExecutionControl implements ExecutionControl {
+
+ private final LoaderDelegate loaderDelegate;
+
+ /**
+ * Creates an instance, delegating loader operations to the specified
+ * delegate.
+ *
+ * @param loaderDelegate the delegate to handle loading classes
+ */
+ public DirectExecutionControl(LoaderDelegate loaderDelegate) {
+ this.loaderDelegate = loaderDelegate;
+ }
+
+ /**
+ * Create an instance using the default class loading.
+ */
+ public DirectExecutionControl() {
+ this(new DefaultLoaderDelegate());
+ }
+
+ @Override
+ public void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException {
+ loaderDelegate.load(cbcs);
+ }
+
+ @Override
+ public void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException {
+ throw new NotImplementedException("redefine not supported");
+ }
+
+ @Override
+ public String invoke(String className, String methodName)
+ throws RunException, InternalException, EngineTerminationException {
+ Method doitMethod;
+ try {
+ Class<?> klass = findClass(className);
+ doitMethod = klass.getDeclaredMethod(methodName, new Class<?>[0]);
+ doitMethod.setAccessible(true);
+ } catch (Throwable ex) {
+ throw new InternalException(ex.toString());
+ }
+
+ try {
+ clientCodeEnter();
+ String result = invoke(doitMethod);
+ System.out.flush();
+ return result;
+ } catch (RunException | InternalException | EngineTerminationException ex) {
+ throw ex;
+ } catch (SPIResolutionException ex) {
+ return throwConvertedInvocationException(ex);
+ } catch (InvocationTargetException ex) {
+ return throwConvertedInvocationException(ex.getCause());
+ } catch (Throwable ex) {
+ return throwConvertedOtherException(ex);
+ } finally {
+ clientCodeLeave();
+ }
+ }
+
+ @Override
+ public String varValue(String className, String varName)
+ throws RunException, EngineTerminationException, InternalException {
+ Object val;
+ try {
+ Class<?> klass = findClass(className);
+ Field var = klass.getDeclaredField(varName);
+ var.setAccessible(true);
+ val = var.get(null);
+ } catch (Throwable ex) {
+ throw new InternalException(ex.toString());
+ }
+
+ try {
+ clientCodeEnter();
+ return valueString(val);
+ } catch (Throwable ex) {
+ return throwConvertedInvocationException(ex);
+ } finally {
+ clientCodeLeave();
+ }
+ }
+
+ @Override
+ public void addToClasspath(String cp)
+ throws EngineTerminationException, InternalException {
+ loaderDelegate.addToClasspath(cp);
+ }
+
+ @Override
+ public void setClasspath(String path)
+ throws EngineTerminationException, InternalException {
+ loaderDelegate.setClasspath(path);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Not supported.
+ */
+ @Override
+ public void stop()
+ throws EngineTerminationException, InternalException {
+ throw new NotImplementedException("stop: Not supported.");
+ }
+
+ @Override
+ public Object extensionCommand(String command, Object arg)
+ throws RunException, EngineTerminationException, InternalException {
+ throw new NotImplementedException("Unknown command: " + command);
+ }
+
+ @Override
+ public void close() {
+ }
+
+ /**
+ * Finds the class with the specified binary name.
+ *
+ * @param name the binary name of the class
+ * @return the Class Object
+ * @throws ClassNotFoundException if the class could not be found
+ */
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ return loaderDelegate.findClass(name);
+ }
+
+ /**
+ * Invoke the specified "doit-method", a static method with no parameters.
+ * The {@link DirectExecutionControl#invoke(java.lang.String, java.lang.String) }
+ * in this class will call this to invoke.
+ *
+ * @param doitMethod the Method to invoke
+ * @return the value or null
+ * @throws Exception any exceptions thrown by
+ * {@link java.lang.reflect.Method#invoke(Object, Object...) }
+ * or any {@link ExecutionControl.ExecutionControlException}
+ * to pass-through.
+ */
+ protected String invoke(Method doitMethod) throws Exception {
+ Object res = doitMethod.invoke(null, new Object[0]);
+ return valueString(res);
+ }
+
+ /**
+ * Converts the {@code Object} value from
+ * {@link ExecutionControl#invoke(String, String) } or
+ * {@link ExecutionControl#varValue(String, String) } to {@code String}.
+ *
+ * @param value the value to convert
+ * @return the {@code String} representation
+ */
+ protected static String valueString(Object value) {
+ if (value == null) {
+ return "null";
+ } else if (value instanceof String) {
+ return "\"" + (String) value + "\"";
+ } else if (value instanceof Character) {
+ return "'" + value + "'";
+ } else {
+ return value.toString();
+ }
+ }
+
+ /**
+ * Converts incoming exceptions in user code into instances of subtypes of
+ * {@link ExecutionControl.ExecutionControlException} and throws the
+ * converted exception.
+ *
+ * @param cause the exception to convert
+ * @return never returns as it always throws
+ * @throws ExecutionControl.RunException for normal exception occurrences
+ * @throws ExecutionControl.InternalException for internal problems
+ */
+ protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
+ if (cause instanceof SPIResolutionException) {
+ SPIResolutionException spire = (SPIResolutionException) cause;
+ throw new ResolutionException(spire.id(), spire.getStackTrace());
+ } else {
+ throw new UserException(cause.getMessage(), cause.getClass().getName(), cause.getStackTrace());
+ }
+ }
+
+ /**
+ * Converts incoming exceptions in agent code into instances of subtypes of
+ * {@link ExecutionControl.ExecutionControlException} and throws the
+ * converted exception.
+ *
+ * @param ex the exception to convert
+ * @return never returns as it always throws
+ * @throws ExecutionControl.RunException for normal exception occurrences
+ * @throws ExecutionControl.InternalException for internal problems
+ */
+ protected String throwConvertedOtherException(Throwable ex) throws RunException, InternalException {
+ throw new InternalException(ex.toString());
+ }
+
+ /**
+ * Marks entry into user code.
+ *
+ * @throws ExecutionControl.InternalException in unexpected failure cases
+ */
+ protected void clientCodeEnter() throws InternalException {
+ }
+
+ /**
+ * Marks departure from user code.
+ *
+ * @throws ExecutionControl.InternalException in unexpected failure cases
+ */
+ protected void clientCodeLeave() throws InternalException {
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/ExecutionControlForwarder.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+import jdk.jshell.spi.ExecutionControl.ResolutionException;
+import jdk.jshell.spi.ExecutionControl.StoppedException;
+import jdk.jshell.spi.ExecutionControl.UserException;
+import static jdk.jshell.execution.RemoteCodes.*;
+
+/**
+ * Forwards commands from the input to the specified {@link ExecutionControl}
+ * instance, then responses back on the output.
+ */
+class ExecutionControlForwarder {
+
+ private final ExecutionControl ec;
+ private final ObjectInput in;
+ private final ObjectOutput out;
+
+ ExecutionControlForwarder(ExecutionControl ec, ObjectInput in, ObjectOutput out) {
+ this.ec = ec;
+ this.in = in;
+ this.out = out;
+ }
+
+ private boolean writeSuccess() throws IOException {
+ writeStatus(RESULT_SUCCESS);
+ flush();
+ return true;
+ }
+
+ private boolean writeSuccessAndResult(String result) throws IOException {
+ writeStatus(RESULT_SUCCESS);
+ writeUTF(result);
+ flush();
+ return true;
+ }
+
+ private boolean writeSuccessAndResult(Object result) throws IOException {
+ writeStatus(RESULT_SUCCESS);
+ writeObject(result);
+ flush();
+ return true;
+ }
+
+ private void writeStatus(int status) throws IOException {
+ out.writeInt(status);
+ }
+
+ private void writeObject(Object o) throws IOException {
+ out.writeObject(o);
+ }
+
+ private void writeInt(int i) throws IOException {
+ out.writeInt(i);
+ }
+
+ private void writeUTF(String s) throws IOException {
+ if (s == null) {
+ s = "";
+ }
+ out.writeUTF(s);
+ }
+
+ private void flush() throws IOException {
+ out.flush();
+ }
+
+ private boolean processCommand() throws IOException {
+ try {
+ int prefix = in.readInt();
+ if (prefix != COMMAND_PREFIX) {
+ throw new EngineTerminationException("Invalid command prefix: " + prefix);
+ }
+ String cmd = in.readUTF();
+ switch (cmd) {
+ case CMD_LOAD: {
+ // Load a generated class file over the wire
+ ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject();
+ ec.load(cbcs);
+ return writeSuccess();
+ }
+ case CMD_REDEFINE: {
+ // Load a generated class file over the wire
+ ClassBytecodes[] cbcs = (ClassBytecodes[]) in.readObject();
+ ec.redefine(cbcs);
+ return writeSuccess();
+ }
+ case CMD_INVOKE: {
+ // Invoke executable entry point in loaded code
+ String className = in.readUTF();
+ String methodName = in.readUTF();
+ String res = ec.invoke(className, methodName);
+ return writeSuccessAndResult(res);
+ }
+ case CMD_VAR_VALUE: {
+ // Retrieve a variable value
+ String className = in.readUTF();
+ String varName = in.readUTF();
+ String res = ec.varValue(className, varName);
+ return writeSuccessAndResult(res);
+ }
+ case CMD_ADD_CLASSPATH: {
+ // Append to the claspath
+ String cp = in.readUTF();
+ ec.addToClasspath(cp);
+ return writeSuccess();
+ }
+ case CMD_SET_CLASSPATH: {
+ // Set the claspath
+ String cp = in.readUTF();
+ ec.setClasspath(cp);
+ return writeSuccess();
+ }
+ case CMD_STOP: {
+ // Stop the current execution
+ try {
+ ec.stop();
+ } catch (Throwable ex) {
+ // JShell-core not waiting for a result, ignore
+ }
+ return true;
+ }
+ case CMD_CLOSE: {
+ // Terminate this process
+ try {
+ ec.close();
+ } catch (Throwable ex) {
+ // JShell-core not waiting for a result, ignore
+ }
+ return true;
+ }
+ default: {
+ Object arg = in.readObject();
+ Object res = ec.extensionCommand(cmd, arg);
+ return writeSuccessAndResult(res);
+ }
+ }
+ } catch (IOException ex) {
+ // handled by the outer level
+ throw ex;
+ } catch (EngineTerminationException ex) {
+ writeStatus(RESULT_TERMINATED);
+ writeUTF(ex.getMessage());
+ flush();
+ return false;
+ } catch (NotImplementedException ex) {
+ writeStatus(RESULT_NOT_IMPLEMENTED);
+ writeUTF(ex.getMessage());
+ flush();
+ return true;
+ } catch (InternalException ex) {
+ writeStatus(RESULT_INTERNAL_PROBLEM);
+ writeUTF(ex.getMessage());
+ flush();
+ return true;
+ } catch (ClassInstallException ex) {
+ writeStatus(RESULT_CLASS_INSTALL_EXCEPTION);
+ writeUTF(ex.getMessage());
+ writeObject(ex.installed());
+ flush();
+ return true;
+ } catch (UserException ex) {
+ writeStatus(RESULT_USER_EXCEPTION);
+ writeUTF(ex.getMessage());
+ writeUTF(ex.causeExceptionClass());
+ writeObject(ex.getStackTrace());
+ flush();
+ return true;
+ } catch (ResolutionException ex) {
+ writeStatus(RESULT_CORRALLED);
+ writeInt(ex.id());
+ writeObject(ex.getStackTrace());
+ flush();
+ return true;
+ } catch (StoppedException ex) {
+ writeStatus(RESULT_STOPPED);
+ flush();
+ return true;
+ } catch (Throwable ex) {
+ writeStatus(RESULT_TERMINATED);
+ writeUTF(ex.getMessage());
+ flush();
+ return false;
+ }
+ }
+
+ void commandLoop() {
+ try {
+ while (processCommand()) {
+ // condition is loop action
+ }
+ } catch (IOException ex) {
+ // drop out of loop
+ }
+ }
+
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Internal.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.jshell.execution;
-
-/**
- * Temp class needed so the package exists.
- */
-class Internal {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIDefaultExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import com.sun.jdi.BooleanValue;
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.Field;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.StackFrame;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.remoteInput;
+
+/**
+ * The implementation of {@link jdk.jshell.spi.ExecutionControl} that the
+ * JShell-core uses by default.
+ * Launches a remote process -- the "remote agent".
+ * Interfaces to the remote agent over a socket and via JDI.
+ * Designed to work with {@link RemoteExecutionControl}.
+ *
+ * @author Robert Field
+ * @author Jan Lahoda
+ */
+public class JDIDefaultExecutionControl extends JDIExecutionControl {
+
+ private static final String REMOTE_AGENT = RemoteExecutionControl.class.getName();
+
+ private VirtualMachine vm;
+ private Process process;
+
+ private final Object STOP_LOCK = new Object();
+ private boolean userCodeRunning = false;
+
+ /**
+ * Creates an ExecutionControl instance based on a JDI
+ * {@code LaunchingConnector}.
+ *
+ * @return the generator
+ */
+ public static ExecutionControl.Generator launch() {
+ return env -> create(env, true);
+ }
+
+ /**
+ * Creates an ExecutionControl instance based on a JDI
+ * {@code ListeningConnector}.
+ *
+ * @return the generator
+ */
+ public static ExecutionControl.Generator listen() {
+ return env -> create(env, false);
+ }
+
+ /**
+ * Creates an ExecutionControl instance based on a JDI
+ * {@code ListeningConnector} or {@code LaunchingConnector}.
+ *
+ * Initialize JDI and use it to launch the remote JVM. Set-up a socket for
+ * commands and results. This socket also transports the user
+ * input/output/error.
+ *
+ * @param env the context passed by
+ * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
+ * @return the channel
+ * @throws IOException if there are errors in set-up
+ */
+ private static JDIDefaultExecutionControl create(ExecutionEnv env, boolean isLaunch) throws IOException {
+ try (final ServerSocket listener = new ServerSocket(0)) {
+ // timeout after 60 seconds
+ listener.setSoTimeout(60000);
+ int port = listener.getLocalPort();
+
+ // Set-up the JDI connection
+ JDIInitiator jdii = new JDIInitiator(port,
+ env.extraRemoteVMOptions(), REMOTE_AGENT, isLaunch);
+ VirtualMachine vm = jdii.vm();
+ Process process = jdii.process();
+
+ // Forward input to the remote agent
+ Util.forwardInputToRemote(env.userIn(), process.getOutputStream(),
+ ex -> debug(ex, "input forwarding failure"));
+
+ List<Consumer<String>> deathListeners = new ArrayList<>();
+ deathListeners.add(s -> env.closeDown());
+ Util.detectJDIExitEvent(vm, s -> {
+ for (Consumer<String> h : deathListeners) {
+ h.accept(s);
+ }
+ });
+
+ // Set-up the commands/reslts on the socket. Piggy-back snippet
+ // output.
+ Socket socket = listener.accept();
+ // out before in -- match remote creation so we don't hang
+ ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream());
+ Map<String, OutputStream> io = new HashMap<>();
+ io.put("out", env.userOut());
+ io.put("err", env.userErr());
+ ObjectInput cmdin = remoteInput(socket.getInputStream(), io);
+ return new JDIDefaultExecutionControl(cmdout, cmdin, vm, process, deathListeners);
+ }
+ }
+
+ /**
+ * Create an instance.
+ *
+ * @param cmdout the output for commands
+ * @param cmdin the input for responses
+ */
+ private JDIDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin,
+ VirtualMachine vm, Process process, List<Consumer<String>> deathListeners) {
+ super(cmdout, cmdin);
+ this.vm = vm;
+ this.process = process;
+ deathListeners.add(s -> disposeVM());
+ }
+
+ @Override
+ public String invoke(String classname, String methodname)
+ throws RunException,
+ EngineTerminationException, InternalException {
+ String res;
+ synchronized (STOP_LOCK) {
+ userCodeRunning = true;
+ }
+ try {
+ res = super.invoke(classname, methodname);
+ } finally {
+ synchronized (STOP_LOCK) {
+ userCodeRunning = false;
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Interrupts a running remote invoke by manipulating remote variables
+ * and sending a stop via JDI.
+ *
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ @Override
+ public void stop() throws EngineTerminationException, InternalException {
+ synchronized (STOP_LOCK) {
+ if (!userCodeRunning) {
+ return;
+ }
+
+ vm().suspend();
+ try {
+ OUTER:
+ for (ThreadReference thread : vm().allThreads()) {
+ // could also tag the thread (e.g. using name), to find it easier
+ for (StackFrame frame : thread.frames()) {
+ if (REMOTE_AGENT.equals(frame.location().declaringType().name()) &&
+ ( "invoke".equals(frame.location().method().name())
+ || "varValue".equals(frame.location().method().name()))) {
+ ObjectReference thiz = frame.thisObject();
+ Field inClientCode = thiz.referenceType().fieldByName("inClientCode");
+ Field expectingStop = thiz.referenceType().fieldByName("expectingStop");
+ Field stopException = thiz.referenceType().fieldByName("stopException");
+ if (((BooleanValue) thiz.getValue(inClientCode)).value()) {
+ thiz.setValue(expectingStop, vm().mirrorOf(true));
+ ObjectReference stopInstance = (ObjectReference) thiz.getValue(stopException);
+
+ vm().resume();
+ debug("Attempting to stop the client code...\n");
+ thread.stop(stopInstance);
+ thiz.setValue(expectingStop, vm().mirrorOf(false));
+ }
+
+ break OUTER;
+ }
+ }
+ }
+ } catch (ClassNotLoadedException | IncompatibleThreadStateException | InvalidTypeException ex) {
+ throw new InternalException("Exception on remote stop: " + ex);
+ } finally {
+ vm().resume();
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ disposeVM();
+ }
+
+ private synchronized void disposeVM() {
+ try {
+ if (vm != null) {
+ vm.dispose(); // This could NPE, so it is caught below
+ vm = null;
+ }
+ } catch (VMDisconnectedException ex) {
+ // Ignore if already closed
+ } catch (Throwable ex) {
+ debug(ex, "disposeVM");
+ } finally {
+ if (process != null) {
+ process.destroy();
+ process = null;
+ }
+ }
+ }
+
+ @Override
+ protected synchronized VirtualMachine vm() throws EngineTerminationException {
+ if (vm == null) {
+ throw new EngineTerminationException("VM closed");
+ } else {
+ return vm;
+ }
+ }
+
+ /**
+ * Log debugging information. Arguments as for {@code printf}.
+ *
+ * @param format a format string as described in Format string syntax
+ * @param args arguments referenced by the format specifiers in the format
+ * string.
+ */
+ private static void debug(String format, Object... args) {
+ // Reserved for future logging
+ }
+
+ /**
+ * Log a serious unexpected internal exception.
+ *
+ * @param ex the exception
+ * @param where a description of the context of the exception
+ */
+ private static void debug(Throwable ex, String where) {
+ // Reserved for future logging
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIEventHandler.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+import java.util.function.Consumer;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+
+/**
+ * Handler of Java Debug Interface events.
+ * Adapted from jdb EventHandler.
+ * Only exit and disconnect events processed.
+ */
+class JDIEventHandler implements Runnable {
+
+ private final Thread thread;
+ private volatile boolean connected = true;
+ private boolean completed = false;
+ private final VirtualMachine vm;
+ private final Consumer<String> reportVMExit;
+
+ /**
+ * Creates an event handler. Start with {@code start()}.
+ *
+ * @param vm the virtual machine for which to handle events
+ * @param reportVMExit callback to report exit/disconnect
+ * (passed true if the VM has died)
+ */
+ JDIEventHandler(VirtualMachine vm, Consumer<String> reportVMExit) {
+ this.vm = vm;
+ this.reportVMExit = reportVMExit;
+ this.thread = new Thread(this, "event-handler");
+ }
+
+ /**
+ * Starts the event handler.
+ */
+ void start() {
+ thread.start();
+ }
+
+ synchronized void shutdown() {
+ connected = false; // force run() loop termination
+ thread.interrupt();
+ while (!completed) {
+ try {wait();} catch (InterruptedException exc) {}
+ }
+ }
+
+ @Override
+ public void run() {
+ EventQueue queue = vm.eventQueue();
+ while (connected) {
+ try {
+ EventSet eventSet = queue.remove();
+ boolean resumeStoppedApp = false;
+ EventIterator it = eventSet.eventIterator();
+ while (it.hasNext()) {
+ resumeStoppedApp |= handleEvent(it.nextEvent());
+ }
+
+ if (resumeStoppedApp) {
+ eventSet.resume();
+ }
+ } catch (InterruptedException exc) {
+ // Do nothing. Any changes will be seen at top of loop.
+ } catch (VMDisconnectedException discExc) {
+ handleDisconnectedException();
+ break;
+ }
+ }
+ synchronized (this) {
+ completed = true;
+ notifyAll();
+ }
+ }
+
+ private boolean handleEvent(Event event) {
+ handleExitEvent(event);
+ return true;
+ }
+
+ private void handleExitEvent(Event event) {
+ if (event instanceof VMDeathEvent) {
+ reportVMExit.accept("VM Died");
+ } else if (event instanceof VMDisconnectEvent) {
+ connected = false;
+ reportVMExit.accept("VM Disconnected");
+ } else {
+ // ignore everything else
+ }
+ }
+
+ private synchronized void handleDisconnectedException() {
+ /*
+ * A VMDisconnectedException has happened while dealing with
+ * another event. We need to flush the event queue, dealing only
+ * with exit events (VMDeath, VMDisconnect) so that we terminate
+ * correctly.
+ */
+ EventQueue queue = vm.eventQueue();
+ while (connected) {
+ try {
+ EventSet eventSet = queue.remove();
+ EventIterator iter = eventSet.eventIterator();
+ while (iter.hasNext()) {
+ handleExitEvent(iter.next());
+ }
+ } catch (InterruptedException exc) {
+ // ignore
+ } catch (InternalError exc) {
+ // ignore
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+import static java.util.stream.Collectors.toMap;
+
+/**
+ * Abstract JDI implementation of {@link jdk.jshell.spi.ExecutionControl}
+ */
+public abstract class JDIExecutionControl extends StreamingExecutionControl implements ExecutionControl {
+
+ /**
+ * Mapping from class names to JDI {@link ReferenceType}.
+ */
+ private final Map<String, ReferenceType> toReferenceType = new HashMap<>();
+
+ /**
+ * Create an instance.
+ * @param out the output from the remote agent
+ * @param in the input to the remote agent
+ */
+ protected JDIExecutionControl(ObjectOutput out, ObjectInput in) {
+ super(out, in);
+ }
+
+ /**
+ * Returns the JDI {@link VirtualMachine} instance.
+ *
+ * @return the virtual machine
+ * @throws EngineTerminationException if the VM is dead/disconnected
+ */
+ protected abstract VirtualMachine vm() throws EngineTerminationException;
+
+ /**
+ * Redefine the specified classes. Where 'redefine' is, as in JDI and JVMTI,
+ * an in-place replacement of the classes (preserving class identity) --
+ * that is, existing references to the class do not need to be recompiled.
+ * This implementation uses JDI
+ * {@link com.sun.jdi.VirtualMachine#redefineClasses(java.util.Map) }.
+ * It will be unsuccessful if
+ * the signature of the class has changed (see the JDI spec). The
+ * JShell-core is designed to adapt to unsuccessful redefine.
+ */
+ @Override
+ public void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, EngineTerminationException {
+ try {
+ // Convert to the JDI ReferenceType to class bytes map form needed
+ // by JDI.
+ VirtualMachine vm = vm();
+ Map<ReferenceType, byte[]> rmp = Stream.of(cbcs)
+ .collect(toMap(
+ cbc -> referenceType(vm, cbc.name()),
+ cbc -> cbc.bytecodes()));
+ // Attempt redefine. Throws exceptions on failure.
+ vm().redefineClasses(rmp);
+ } catch (EngineTerminationException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new ClassInstallException("redefine: " + ex.getMessage(), new boolean[cbcs.length]);
+ }
+ }
+
+ /**
+ * Returns the JDI {@link ReferenceType} corresponding to the specified
+ * class name.
+ *
+ * @param vm the current JDI {@link VirtualMachine} as returned by
+ * {@code vm()}
+ * @param name the class name to look-up
+ * @return the corresponding {@link ReferenceType}
+ */
+ protected ReferenceType referenceType(VirtualMachine vm, String name) {
+ return toReferenceType.computeIfAbsent(name, n -> nameToRef(vm, n));
+ }
+
+ private static ReferenceType nameToRef(VirtualMachine vm, String name) {
+ List<ReferenceType> rtl = vm.classesByName(name);
+ if (rtl.size() != 1) {
+ return null;
+ }
+ return rtl.get(0);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JDIInitiator.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import com.sun.jdi.Bootstrap;
+import com.sun.jdi.VirtualMachine;
+import com.sun.jdi.connect.Connector;
+import com.sun.jdi.connect.LaunchingConnector;
+import com.sun.jdi.connect.ListeningConnector;
+
+/**
+ * Sets up a JDI connection, providing the resulting JDI {@link VirtualMachine}
+ * and the {@link Process} the remote agent is running in.
+ */
+public class JDIInitiator {
+
+ private VirtualMachine vm;
+ private Process process = null;
+ private final Connector connector;
+ private final String remoteAgent;
+ private final Map<String, com.sun.jdi.connect.Connector.Argument> connectorArgs;
+
+ /**
+ * Start the remote agent and establish a JDI connection to it.
+ *
+ * @param port the socket port for (non-JDI) commands
+ * @param remoteVMOptions any user requested VM options
+ * @param remoteAgent full class name of remote agent to launch
+ * @param isLaunch does JDI do the launch? That is, LaunchingConnector,
+ * otherwise we start explicitly and use ListeningConnector
+ */
+ public JDIInitiator(int port, List<String> remoteVMOptions,
+ String remoteAgent, boolean isLaunch) {
+ this.remoteAgent = remoteAgent;
+ String connectorName
+ = isLaunch
+ ? "com.sun.jdi.CommandLineLaunch"
+ : "com.sun.jdi.SocketListen";
+ this.connector = findConnector(connectorName);
+ if (connector == null) {
+ throw new IllegalArgumentException("No connector named: " + connectorName);
+ }
+ Map<String, String> argumentName2Value
+ = isLaunch
+ ? launchArgs(port, String.join(" ", remoteVMOptions))
+ : new HashMap<>();
+ this.connectorArgs = mergeConnectorArgs(connector, argumentName2Value);
+ this.vm = isLaunch
+ ? launchTarget()
+ : listenTarget(port, remoteVMOptions);
+
+ }
+
+ /**
+ * Returns the resulting {@code VirtualMachine} instance.
+ *
+ * @return the virtual machine
+ */
+ public VirtualMachine vm() {
+ return vm;
+ }
+
+ /**
+ * Returns the launched process.
+ *
+ * @return the remote agent process
+ */
+ public Process process() {
+ return process;
+ }
+
+ /* launch child target vm */
+ private VirtualMachine launchTarget() {
+ LaunchingConnector launcher = (LaunchingConnector) connector;
+ try {
+ VirtualMachine new_vm = launcher.launch(connectorArgs);
+ process = new_vm.process();
+ return new_vm;
+ } catch (Exception ex) {
+ reportLaunchFail(ex, "launch");
+ }
+ return null;
+ }
+
+ /**
+ * Directly launch the remote agent and connect JDI to it with a
+ * ListeningConnector.
+ */
+ private VirtualMachine listenTarget(int port, List<String> remoteVMOptions) {
+ ListeningConnector listener = (ListeningConnector) connector;
+ try {
+ // Start listening, get the JDI connection address
+ String addr = listener.startListening(connectorArgs);
+ debug("Listening at address: " + addr);
+
+ // Launch the RemoteAgent requesting a connection on that address
+ String javaHome = System.getProperty("java.home");
+ List<String> args = new ArrayList<>();
+ args.add(javaHome == null
+ ? "java"
+ : javaHome + File.separator + "bin" + File.separator + "java");
+ args.add("-agentlib:jdwp=transport=" + connector.transport().name() +
+ ",address=" + addr);
+ args.addAll(remoteVMOptions);
+ args.add(remoteAgent);
+ args.add("" + port);
+ ProcessBuilder pb = new ProcessBuilder(args);
+ process = pb.start();
+
+ // Forward out, err, and in
+ // Accept the connection from the remote agent
+ vm = listener.accept(connectorArgs);
+ listener.stopListening(connectorArgs);
+ return vm;
+ } catch (Exception ex) {
+ reportLaunchFail(ex, "listen");
+ }
+ return null;
+ }
+
+ private Connector findConnector(String name) {
+ for (Connector cntor
+ : Bootstrap.virtualMachineManager().allConnectors()) {
+ if (cntor.name().equals(name)) {
+ return cntor;
+ }
+ }
+ return null;
+ }
+
+ private Map<String, Connector.Argument> mergeConnectorArgs(Connector connector, Map<String, String> argumentName2Value) {
+ Map<String, Connector.Argument> arguments = connector.defaultArguments();
+
+ for (Entry<String, String> argumentEntry : argumentName2Value.entrySet()) {
+ String name = argumentEntry.getKey();
+ String value = argumentEntry.getValue();
+ Connector.Argument argument = arguments.get(name);
+
+ if (argument == null) {
+ throw new IllegalArgumentException("Argument is not defined for connector:" +
+ name + " -- " + connector.name());
+ }
+
+ argument.setValue(value);
+ }
+
+ return arguments;
+ }
+
+ /**
+ * The JShell specific Connector args for the LaunchingConnector.
+ *
+ * @param portthe socket port for (non-JDI) commands
+ * @param remoteVMOptions any user requested VM options
+ * @return the argument map
+ */
+ private Map<String, String> launchArgs(int port, String remoteVMOptions) {
+ Map<String, String> argumentName2Value = new HashMap<>();
+ argumentName2Value.put("main", remoteAgent + " " + port);
+ argumentName2Value.put("options", remoteVMOptions);
+ return argumentName2Value;
+ }
+
+ private void reportLaunchFail(Exception ex, String context) {
+ throw new InternalError("Failed remote " + context + ": " + connector +
+ " -- " + connectorArgs, ex);
+ }
+
+ /**
+ * Log debugging information. Arguments as for {@code printf}.
+ *
+ * @param format a format string as described in Format string syntax
+ * @param args arguments referenced by the format specifiers in the format
+ * string.
+ */
+ private void debug(String format, Object... args) {
+ // Reserved for future logging
+ }
+
+ /**
+ * Log a serious unexpected internal exception.
+ *
+ * @param ex the exception
+ * @param where a description of the context of the exception
+ */
+ private void debug(Throwable ex, String where) {
+ // Reserved for future logging
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/LoaderDelegate.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
+import jdk.jshell.spi.ExecutionControl.ClassInstallException;
+import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
+import jdk.jshell.spi.ExecutionControl.InternalException;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+
+/**
+ * This interface specifies the loading specific subset of
+ * {@link jdk.jshell.spi.ExecutionControl}. For use in encapsulating the
+ * {@link java.lang.ClassLoader} implementation.
+ */
+public interface LoaderDelegate {
+
+ /**
+ * Attempts to load new classes.
+ *
+ * @param cbcs the class name and bytecodes to load
+ * @throws ClassInstallException exception occurred loading the classes,
+ * some or all were not loaded
+ * @throws NotImplementedException if not implemented
+ * @throws EngineTerminationException the execution engine has terminated
+ */
+ void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+ /**
+ * Adds the path to the execution class path.
+ *
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ void addToClasspath(String path)
+ throws EngineTerminationException, InternalException;
+
+ /**
+ * Sets the execution class path to the specified path.
+ *
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ void setClasspath(String path)
+ throws EngineTerminationException, InternalException;
+
+ /**
+ * Finds the class with the specified binary name.
+ *
+ * @param name the binary name of the class
+ * @return the Class Object
+ * @throws ClassNotFoundException if the class could not be found
+ */
+ Class<?> findClass(String name) throws ClassNotFoundException;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/LocalExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.concurrent.atomic.AtomicReference;
+import jdk.jshell.spi.ExecutionControl;
+
+/**
+ * An implementation of {@link jdk.jshell.spi.ExecutionControl} which executes
+ * in the same JVM as the JShell-core.
+ *
+ * @author Grigory Ptashko
+ */
+public class LocalExecutionControl extends DirectExecutionControl {
+
+ private final Object STOP_LOCK = new Object();
+ private boolean userCodeRunning = false;
+ private ThreadGroup execThreadGroup;
+
+ /**
+ * Creates a local ExecutionControl instance.
+ *
+ * @return the generator
+ */
+ public static ExecutionControl.Generator create() {
+ return env -> new LocalExecutionControl();
+ }
+
+ /**
+ * Creates an instance, delegating loader operations to the specified
+ * delegate.
+ *
+ * @param loaderDelegate the delegate to handle loading classes
+ */
+ public LocalExecutionControl(LoaderDelegate loaderDelegate) {
+ super(loaderDelegate);
+ }
+
+ /**
+ * Create an instance using the default class loading.
+ */
+ public LocalExecutionControl() {
+ }
+
+ @Override
+ protected String invoke(Method doitMethod) throws Exception {
+ execThreadGroup = new ThreadGroup("JShell process local execution");
+
+ AtomicReference<InvocationTargetException> iteEx = new AtomicReference<>();
+ AtomicReference<IllegalAccessException> iaeEx = new AtomicReference<>();
+ AtomicReference<NoSuchMethodException> nmeEx = new AtomicReference<>();
+ AtomicReference<Boolean> stopped = new AtomicReference<>(false);
+
+ Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
+ if (e instanceof InvocationTargetException) {
+ if (e.getCause() instanceof ThreadDeath) {
+ stopped.set(true);
+ } else {
+ iteEx.set((InvocationTargetException) e);
+ }
+ } else if (e instanceof IllegalAccessException) {
+ iaeEx.set((IllegalAccessException) e);
+ } else if (e instanceof NoSuchMethodException) {
+ nmeEx.set((NoSuchMethodException) e);
+ } else if (e instanceof ThreadDeath) {
+ stopped.set(true);
+ }
+ });
+
+ final Object[] res = new Object[1];
+ Thread snippetThread = new Thread(execThreadGroup, () -> {
+ try {
+ res[0] = doitMethod.invoke(null, new Object[0]);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof ThreadDeath) {
+ stopped.set(true);
+ } else {
+ iteEx.set(e);
+ }
+ } catch (IllegalAccessException e) {
+ iaeEx.set(e);
+ } catch (ThreadDeath e) {
+ stopped.set(true);
+ }
+ });
+
+ snippetThread.start();
+ Thread[] threadList = new Thread[execThreadGroup.activeCount()];
+ execThreadGroup.enumerate(threadList);
+ for (Thread thread : threadList) {
+ if (thread != null) {
+ thread.join();
+ }
+ }
+
+ if (stopped.get()) {
+ throw new StoppedException();
+ }
+
+ if (iteEx.get() != null) {
+ throw iteEx.get();
+ } else if (nmeEx.get() != null) {
+ throw nmeEx.get();
+ } else if (iaeEx.get() != null) {
+ throw iaeEx.get();
+ }
+
+ return valueString(res[0]);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void stop() throws EngineTerminationException, InternalException {
+ synchronized (STOP_LOCK) {
+ if (!userCodeRunning) {
+ return;
+ }
+ if (execThreadGroup == null) {
+ throw new InternalException("Process-local code snippets thread group is null. Aborting stop.");
+ }
+
+ execThreadGroup.stop();
+ }
+ }
+
+ @Override
+ protected void clientCodeEnter() {
+ synchronized (STOP_LOCK) {
+ userCodeRunning = true;
+ }
+ }
+
+ @Override
+ protected void clientCodeLeave() {
+ synchronized (STOP_LOCK) {
+ userCodeRunning = false;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/MultiplexingOutputStream.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Packetize an OutputStream, dividing it into named channels.
+ *
+ * @author Jan Lahoda
+ */
+class MultiplexingOutputStream extends OutputStream {
+
+ private static final int PACKET_SIZE = 127;
+ private final byte[] name;
+ private final OutputStream delegate;
+
+ MultiplexingOutputStream(String name, OutputStream delegate) {
+ try {
+ this.name = name.getBytes("UTF-8");
+ this.delegate = delegate;
+ } catch (UnsupportedEncodingException ex) {
+ throw new IllegalStateException(ex); //should not happen
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ synchronized (delegate) {
+ delegate.write(name.length); //assuming the len is small enough to fit into byte
+ delegate.write(name);
+ delegate.write(1);
+ delegate.write(b);
+ delegate.flush();
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ synchronized (delegate) {
+ int i = 0;
+ while (len > 0) {
+ int size = Math.min(PACKET_SIZE, len);
+ delegate.write(name.length); //assuming the len is small enough to fit into byte
+ delegate.write(name);
+ delegate.write(size);
+ delegate.write(b, off + i, size);
+ i += size;
+ len -= size;
+ }
+ delegate.flush();
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ delegate.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ delegate.close();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/PipeInputStream.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.InputStream;
+
+/**
+ *
+ * @author Jan Lahoda
+ */
+class PipeInputStream extends InputStream {
+
+ private static final int INITIAL_SIZE = 128;
+ private int[] buffer = new int[INITIAL_SIZE];
+ private int start;
+ private int end;
+ private boolean closed;
+
+ @Override
+ public synchronized int read() {
+ while (start == end) {
+ if (closed) {
+ return -1;
+ }
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ //ignore
+ }
+ }
+ try {
+ return buffer[start];
+ } finally {
+ start = (start + 1) % buffer.length;
+ }
+ }
+
+ public synchronized void write(int b) {
+ if (closed) {
+ throw new IllegalStateException("Already closed.");
+ }
+ int newEnd = (end + 1) % buffer.length;
+ if (newEnd == start) {
+ //overflow:
+ int[] newBuffer = new int[buffer.length * 2];
+ int rightPart = (end > start ? end : buffer.length) - start;
+ int leftPart = end > start ? 0 : start - 1;
+ System.arraycopy(buffer, start, newBuffer, 0, rightPart);
+ System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart);
+ buffer = newBuffer;
+ start = 0;
+ end = rightPart + leftPart;
+ newEnd = end + 1;
+ }
+ buffer[end] = b;
+ end = newEnd;
+ notifyAll();
+ }
+
+ @Override
+ public synchronized void close() {
+ closed = true;
+ notifyAll();
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteCodes.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell.execution;
+
+/**
+ * Communication constants shared between the main process and the remote
+ * execution process. These are not enums to allow for future expansion, and
+ * remote/local of different versions.
+ *
+ * @author Robert Field
+ */
+class RemoteCodes {
+
+ /**
+ * Command prefix markers.
+ */
+ static final int COMMAND_PREFIX = 0xC03DC03D;
+
+ // Command codes
+
+ /**
+ * Exit the the agent.
+ */
+ static final String CMD_CLOSE = "CMD_CLOSE";
+ /**
+ * Load classes.
+ */
+ static final String CMD_LOAD = "CMD_LOAD";
+ /**
+ * Redefine classes.
+ */
+ static final String CMD_REDEFINE = "CMD_REDEFINE";
+ /**
+ * Invoke a method.
+ */
+ static final String CMD_INVOKE = "CMD_INVOKE";
+ /**
+ * Retrieve the value of a variable.
+ */
+ static final String CMD_VAR_VALUE = "CMD_VAR_VALUE";
+ /**
+ * Add to the class-path.
+ */
+ static final String CMD_ADD_CLASSPATH = "CMD_ADD_CLASSPATH";
+ /**
+ * Set the class-path.
+ */
+ static final String CMD_SET_CLASSPATH = "CMD_SET_CLASSPATH";
+ /**
+ * Stop an invoke.
+ */
+ static final String CMD_STOP = "CMD_STOP";
+
+ // Return result codes
+
+ /**
+ * The command succeeded.
+ */
+ static final int RESULT_SUCCESS = 100;
+ /**
+ * Unbidden execution engine termination.
+ */
+ static final int RESULT_TERMINATED = 101;
+ /**
+ * Command not implemented.
+ */
+ static final int RESULT_NOT_IMPLEMENTED = 102;
+ /**
+ * The command failed.
+ */
+ static final int RESULT_INTERNAL_PROBLEM = 103;
+ /**
+ * User exception encountered.
+ */
+ static final int RESULT_USER_EXCEPTION = 104;
+ /**
+ * Corralled code exception encountered.
+ */
+ static final int RESULT_CORRALLED = 105;
+ /**
+ * Exception encountered during class load/redefine.
+ */
+ static final int RESULT_CLASS_INSTALL_EXCEPTION = 106;
+ /**
+ * The invoke has been stopped.
+ */
+ static final int RESULT_STOPPED = 107;
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/RemoteExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import jdk.jshell.spi.ExecutionControl;
+import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
+
+/**
+ * The remote agent runs in the execution process (separate from the main JShell
+ * process). This agent loads code over a socket from the main JShell process,
+ * executes the code, and other misc, Specialization of
+ * {@link DirectExecutionControl} which adds stop support controlled by
+ * an external process. Designed to work with {@link JDIDefaultExecutionControl}.
+ *
+ * @author Jan Lahoda
+ * @author Robert Field
+ */
+public class RemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
+
+ /**
+ * Launch the agent, connecting to the JShell-core over the socket specified
+ * in the command-line argument.
+ *
+ * @param args standard command-line arguments, expectation is the socket
+ * number is the only argument
+ * @throws Exception any unexpected exception
+ */
+ public static void main(String[] args) throws Exception {
+ String loopBack = null;
+ Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
+ InputStream inStream = socket.getInputStream();
+ OutputStream outStream = socket.getOutputStream();
+ Map<String, Consumer<OutputStream>> chans = new HashMap<>();
+ chans.put("out", st -> System.setOut(new PrintStream(st, true)));
+ chans.put("err", st -> System.setErr(new PrintStream(st, true)));
+ forwardExecutionControlAndIO(new RemoteExecutionControl(), inStream, outStream, chans);
+ }
+
+ // These three variables are used by the main JShell process in interrupting
+ // the running process. Access is via JDI, so the reference is not visible
+ // to code inspection.
+ private boolean inClientCode; // Queried by the main process (in superclass)
+ private boolean expectingStop; // Set by the main process
+// Set by the main process
+
+ // thrown by the main process via JDI:
+ private final StopExecutionException stopException = new StopExecutionException();
+
+ /**
+ * Creates an instance, delegating loader operations to the specified
+ * delegate.
+ *
+ * @param loaderDelegate the delegate to handle loading classes
+ */
+ public RemoteExecutionControl(LoaderDelegate loaderDelegate) {
+ super(loaderDelegate);
+ }
+
+ /**
+ * Create an instance using the default class loading.
+ */
+ public RemoteExecutionControl() {
+ }
+
+ @Override
+ public void stop() throws EngineTerminationException, InternalException {
+ // handled by JDI
+ }
+
+ // Overridden only so this stack frame is seen
+ @Override
+ protected String invoke(Method doitMethod) throws Exception {
+ return super.invoke(doitMethod);
+ }
+
+ // Overridden only so this stack frame is seen
+ @Override
+ public String varValue(String className, String varName) throws RunException, EngineTerminationException, InternalException {
+ return super.varValue(className, varName);
+ }
+
+ @Override
+ protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
+ if (cause instanceof StopExecutionException) {
+ expectingStop = false;
+ throw new StoppedException();
+ } else {
+ return super.throwConvertedInvocationException(cause);
+ }
+ }
+
+ @Override
+ protected String throwConvertedOtherException(Throwable ex) throws RunException, InternalException {
+ if (ex instanceof StopExecutionException ||
+ ex.getCause() instanceof StopExecutionException) {
+ expectingStop = false;
+ throw new StoppedException();
+ }
+ return super.throwConvertedOtherException(ex);
+ }
+
+ @Override
+ protected void clientCodeEnter() {
+ expectingStop = false;
+ inClientCode = true;
+ }
+
+ @Override
+ protected void clientCodeLeave() throws InternalException {
+ inClientCode = false;
+ while (expectingStop) {
+ try {
+ Thread.sleep(0);
+ } catch (InterruptedException ex) {
+ throw new InternalException("*** Sleep interrupted while waiting for stop exception: " + ex);
+ }
+ }
+ }
+
+ @SuppressWarnings("serial") // serialVersionUID intentionally omitted
+ private class StopExecutionException extends ThreadDeath {
+
+ @Override
+ public synchronized Throwable fillInStackTrace() {
+ return this;
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/StreamingExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import jdk.jshell.JShellException;
+import jdk.jshell.spi.ExecutionControl;
+import static jdk.jshell.execution.RemoteCodes.*;
+
+/**
+ * An implementation of the {@link jdk.jshell.spi.ExecutionControl}
+ * execution engine SPI which streams requests to a remote agent where
+ * execution takes place.
+ *
+ * @author Robert Field
+ */
+public class StreamingExecutionControl implements ExecutionControl {
+
+ private final ObjectOutput out;
+ private final ObjectInput in;
+
+ /**
+ * Creates an instance.
+ *
+ * @param out the output for commands
+ * @param in the input for command responses
+ */
+ public StreamingExecutionControl(ObjectOutput out, ObjectInput in) {
+ this.out = out;
+ this.in = in;
+ }
+
+ @Override
+ public void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException {
+ try {
+ // Send a load command to the remote agent.
+ writeCommand(CMD_LOAD);
+ out.writeObject(cbcs);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportClassInstallResult();
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote load: " + ex);
+ }
+ }
+
+ @Override
+ public void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException {
+ try {
+ // Send a load command to the remote agent.
+ writeCommand(CMD_REDEFINE);
+ out.writeObject(cbcs);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportClassInstallResult();
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote redefine: " + ex);
+ }
+ }
+
+ @Override
+ public String invoke(String classname, String methodname)
+ throws RunException, EngineTerminationException, InternalException {
+ try {
+ // Send the invoke command to the remote agent.
+ writeCommand(CMD_INVOKE);
+ out.writeUTF(classname);
+ out.writeUTF(methodname);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportExecutionResult();
+ String result = in.readUTF();
+ return result;
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote invoke: " + ex);
+ }
+ }
+
+ @Override
+ public String varValue(String classname, String varname)
+ throws RunException, EngineTerminationException, InternalException {
+ try {
+ // Send the variable-value command to the remote agent.
+ writeCommand(CMD_VAR_VALUE);
+ out.writeUTF(classname);
+ out.writeUTF(varname);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportExecutionResult();
+ String result = in.readUTF();
+ return result;
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote varValue: " + ex);
+ }
+ }
+
+
+ @Override
+ public void addToClasspath(String path)
+ throws EngineTerminationException, InternalException {
+ try {
+ // Send the classpath addition command to the remote agent.
+ writeCommand(CMD_ADD_CLASSPATH);
+ out.writeUTF(path);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportClassSimpleResult();
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote add to classpath: " + ex);
+ }
+ }
+
+ @Override
+ public void setClasspath(String path)
+ throws EngineTerminationException, InternalException {
+ try {
+ // Send the classpath addition command to the remote agent.
+ writeCommand(CMD_SET_CLASSPATH);
+ out.writeUTF(path);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportClassSimpleResult();
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote set classpath: " + ex);
+ }
+ }
+
+ @Override
+ public void stop()
+ throws EngineTerminationException, InternalException {
+ try {
+ // Send the variable-value command to the remote agent.
+ writeCommand(CMD_STOP);
+ out.flush();
+ } catch (IOException ex) {
+ throw new EngineTerminationException("Exception writing remote stop: " + ex);
+ }
+ }
+
+ @Override
+ public Object extensionCommand(String command, Object arg)
+ throws RunException, EngineTerminationException, InternalException {
+ try {
+ writeCommand(command);
+ out.writeObject(arg);
+ out.flush();
+ // Retrieve and report results from the remote agent.
+ readAndReportExecutionResult();
+ Object result = in.readObject();
+ return result;
+ } catch (IOException | ClassNotFoundException ex) {
+ throw new EngineTerminationException("Exception transmitting remote extensionCommand: "
+ + command + " -- " + ex);
+ }
+ }
+
+ /**
+ * Closes the execution engine. Send an exit command to the remote agent.
+ */
+ @Override
+ public void close() {
+ try {
+ writeCommand(CMD_CLOSE);
+ out.flush();
+ } catch (IOException ex) {
+ // ignore;
+ }
+ }
+
+ private void writeCommand(String cmd) throws IOException {
+ out.writeInt(COMMAND_PREFIX);
+ out.writeUTF(cmd);
+ }
+
+ /**
+ * Reports results from a remote agent command that does not expect
+ * exceptions.
+ */
+ private void readAndReportClassSimpleResult() throws EngineTerminationException, InternalException {
+ try {
+ int status = in.readInt();
+ switch (status) {
+ case RESULT_SUCCESS:
+ return;
+ case RESULT_NOT_IMPLEMENTED: {
+ String message = in.readUTF();
+ throw new NotImplementedException(message);
+ }
+ case RESULT_INTERNAL_PROBLEM: {
+ String message = in.readUTF();
+ throw new InternalException(message);
+ }
+ case RESULT_TERMINATED: {
+ String message = in.readUTF();
+ throw new EngineTerminationException(message);
+ }
+ default: {
+ throw new EngineTerminationException("Bad remote result code: " + status);
+ }
+ }
+ } catch (IOException ex) {
+ throw new EngineTerminationException(ex.toString());
+ }
+ }
+
+ /**
+ * Reports results from a remote agent command that does not expect
+ * exceptions.
+ */
+ private void readAndReportClassInstallResult() throws ClassInstallException,
+ NotImplementedException, EngineTerminationException {
+ try {
+ int status = in.readInt();
+ switch (status) {
+ case RESULT_SUCCESS:
+ return;
+ case RESULT_NOT_IMPLEMENTED: {
+ String message = in.readUTF();
+ throw new NotImplementedException(message);
+ }
+ case RESULT_CLASS_INSTALL_EXCEPTION: {
+ String message = in.readUTF();
+ boolean[] loaded = (boolean[]) in.readObject();
+ throw new ClassInstallException(message, loaded);
+ }
+ case RESULT_TERMINATED: {
+ String message = in.readUTF();
+ throw new EngineTerminationException(message);
+ }
+ default: {
+ throw new EngineTerminationException("Bad remote result code: " + status);
+ }
+ }
+ } catch (IOException | ClassNotFoundException ex) {
+ throw new EngineTerminationException(ex.toString());
+ }
+ }
+
+ /**
+ * Reports results from a remote agent command that expects runtime
+ * exceptions.
+ *
+ * @return true if successful
+ * @throws IOException if the connection has dropped
+ * @throws JShellException {@link jdk.jshell.EvalException}, if a user
+ * exception was encountered on invoke;
+ * {@link jdk.jshell.UnresolvedReferenceException}, if an unresolved
+ * reference was encountered
+ * @throws java.lang.ClassNotFoundException
+ */
+ private void readAndReportExecutionResult() throws RunException,
+ EngineTerminationException, InternalException {
+ try {
+ int status = in.readInt();
+ switch (status) {
+ case RESULT_SUCCESS:
+ return;
+ case RESULT_NOT_IMPLEMENTED: {
+ String message = in.readUTF();
+ throw new NotImplementedException(message);
+ }
+ case RESULT_USER_EXCEPTION: {
+ // A user exception was encountered.
+ String message = in.readUTF();
+ String exceptionClassName = in.readUTF();
+ StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
+ throw new UserException(message, exceptionClassName, elems);
+ }
+ case RESULT_CORRALLED: {
+ // An unresolved reference was encountered.
+ int id = in.readInt();
+ StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
+ ResolutionException re = new ResolutionException(id, elems);
+ throw re;
+ }
+ case RESULT_STOPPED: {
+ // Execution was aborted by the stop()
+ throw new StoppedException();
+ }
+ case RESULT_INTERNAL_PROBLEM: {
+ // An internal error has occurred.
+ String message = in.readUTF();
+ throw new InternalException(message);
+ }
+ case RESULT_TERMINATED: {
+ String message = in.readUTF();
+ throw new EngineTerminationException(message);
+ }
+ default: {
+ throw new EngineTerminationException("Bad remote result code: " + status);
+ }
+ }
+ } catch (IOException | ClassNotFoundException ex) {
+ throw new EngineTerminationException(ex.toString());
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/Util.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.jshell.execution;
+
+import jdk.jshell.spi.ExecutionEnv;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.spi.ExecutionControl;
+
+
+/**
+ * Miscellaneous utility methods for setting-up implementations of
+ * {@link ExecutionControl}. Particularly implementations with remote
+ * execution.
+ *
+ * @author Jan Lahoda
+ * @author Robert Field
+ */
+public class Util {
+
+ // never instanciated
+ private Util() {}
+
+ /**
+ * Create a composite {@link ExecutionControl.Generator} instance that, when
+ * generating, will try each specified generator until successfully creating
+ * an {@link ExecutionControl} instance, or, if all fail, will re-throw the
+ * first exception.
+ *
+ * @param gec0 the first instance to try
+ * @param gecs the second through Nth instance to try
+ * @return the fail-over generator
+ */
+ public static ExecutionControl.Generator failOverExecutionControlGenerator(
+ ExecutionControl.Generator gec0, ExecutionControl.Generator... gecs) {
+ return (ExecutionEnv env) -> {
+ Throwable thrown;
+ try {
+ return gec0.generate(env);
+ } catch (Throwable ex) {
+ thrown = ex;
+ }
+ for (ExecutionControl.Generator gec : gecs) {
+ try {
+ return gec.generate(env);
+ } catch (Throwable ignore) {
+ // only care about the first, and only if they all fail
+ }
+ }
+ throw thrown;
+ };
+ }
+
+ /**
+ * Forward commands from the input to the specified {@link ExecutionControl}
+ * instance, then responses back on the output.
+ * @param ec the direct instance of {@link ExecutionControl} to process commands
+ * @param in the command input
+ * @param out the command response output
+ */
+ public static void forwardExecutionControl(ExecutionControl ec,
+ ObjectInput in, ObjectOutput out) {
+ new ExecutionControlForwarder(ec, in, out).commandLoop();
+ }
+
+ /**
+ * Forward commands from the input to the specified {@link ExecutionControl}
+ * instance, then responses back on the output.
+ * @param ec the direct instance of {@link ExecutionControl} to process commands
+ * @param inStream the stream from which to create the command input
+ * @param outStream the stream that will carry {@code System.out},
+ * {@code System.err}, any specified auxiliary channels, and the
+ * command response output.
+ * @param streamMap a map between names of additional streams to carry and setters
+ * for the stream
+ * @throws IOException if there are errors using the passed streams
+ */
+ public static void forwardExecutionControlAndIO(ExecutionControl ec,
+ InputStream inStream, OutputStream outStream,
+ Map<String, Consumer<OutputStream>> streamMap) throws IOException {
+ ObjectInputStream cmdIn = new ObjectInputStream(inStream);
+ for (Entry<String, Consumer<OutputStream>> e : streamMap.entrySet()) {
+ e.getValue().accept(multiplexingOutputStream(e.getKey(), outStream));
+ }
+ ObjectOutputStream cmdOut = new ObjectOutputStream(multiplexingOutputStream("command", outStream));
+ forwardExecutionControl(ec, cmdIn, cmdOut);
+ }
+
+ static OutputStream multiplexingOutputStream(String label, OutputStream outputStream) {
+ return new MultiplexingOutputStream(label, outputStream);
+ }
+
+ /**
+ * Reads from an InputStream which has been packetized and write its contents
+ * to the out and err OutputStreams; Copies the command stream.
+ * @param input the packetized input stream
+ * @param streamMap a map between stream names and the output streams to forward
+ * @return the command stream
+ * @throws IOException if setting up the streams raised an exception
+ */
+ public static ObjectInput remoteInput(InputStream input,
+ Map<String, OutputStream> streamMap) throws IOException {
+ PipeInputStream commandIn = new PipeInputStream();
+ new DemultiplexInput(input, commandIn, streamMap).start();
+ return new ObjectInputStream(commandIn);
+ }
+
+ /**
+ * Monitor the JDI event stream for {@link com.sun.jdi.event.VMDeathEvent}
+ * and {@link com.sun.jdi.event.VMDisconnectEvent}. If encountered, invokes
+ * {@code unbiddenExitHandler}.
+ *
+ * @param vm the virtual machine to check
+ * @param unbiddenExitHandler the handler, which will accept the exit
+ * information
+ */
+ public static void detectJDIExitEvent(VirtualMachine vm, Consumer<String> unbiddenExitHandler) {
+ if (vm.canBeModified()) {
+ new JDIEventHandler(vm, unbiddenExitHandler).start();
+ }
+ }
+
+ /**
+ * Creates a Thread that will ship all input to the remote agent.
+ *
+ * @param inputStream the user input
+ * @param outStream the input to the remote agent
+ * @param handler a failure handler
+ */
+ public static void forwardInputToRemote(final InputStream inputStream,
+ final OutputStream outStream, final Consumer<Exception> handler) {
+ Thread thr = new Thread("input reader") {
+ @Override
+ public void run() {
+ try {
+ byte[] buf = new byte[256];
+ int cnt;
+ while ((cnt = inputStream.read(buf)) != -1) {
+ outStream.write(buf, 0, cnt);
+ outStream.flush();
+ }
+ } catch (Exception ex) {
+ handler.accept(ex);
+ }
+ }
+ };
+ thr.setPriority(Thread.MAX_PRIORITY - 1);
+ thr.start();
+ }
+
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionControl.java Wed Jul 27 13:33:55 2016 +0000
@@ -22,62 +22,152 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
-
package jdk.jshell.spi;
-import java.util.Collection;
-import jdk.jshell.JShellException;
+import java.io.Serializable;
/**
- * This interface specifies the functionality that must provided to implement
- * a pluggable JShell execution engine.
+ * This interface specifies the functionality that must provided to implement a
+ * pluggable JShell execution engine.
* <p>
- * The audience for this Service Provider Interface is engineers
- * wishing to implement their own version of the execution engine in support
- * of the JShell API. This is NOT a part of the JShell API.
+ * The audience for this Service Provider Interface is engineers wishing to
+ * implement their own version of the execution engine in support of the JShell
+ * API.
* <p>
- * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution
- * engine is used by the core JShell implementation to load and, for
- * executable Snippets, execute the Snippet.
+ * A Snippet is compiled into code wrapped in a 'wrapper class'. The execution
+ * engine is used by the core JShell implementation to load and, for executable
+ * Snippets, execute the Snippet.
* <p>
* Methods defined in this interface should only be called by the core JShell
* implementation.
* <p>
- * To install an instance of ExecutionControl, it is passed to
- * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }.
+ * To install an {@code ExecutionControl}, its {@code Generator} is passed to
+ * {@link jdk.jshell.JShell.Builder#executionEngine(ExecutionControl.Generator) }.
*/
public interface ExecutionControl {
/**
- * Represents the current status of a class in the execution engine.
+ * Defines a functional interface for creating {@link ExecutionControl}
+ * instances.
*/
- public enum ClassStatus {
- /**
- * Class is not known to the execution engine (not loaded).
- */
- UNKNOWN,
-
- /**
- * Class is loaded, but the loaded/redefined bytes do not match those
- * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
- */
- NOT_CURRENT,
+ public interface Generator {
/**
- * Class is loaded and loaded/redefined bytes match those
- * returned by {@link ExecutionEnv#getClassBytes(java.lang.String) }.
+ * Generates an execution engine, given an execution environment.
+ *
+ * @param env the context in which the {@link ExecutionControl} is to
+ * be created
+ * @return the created instance
+ * @throws Throwable if problems occurred
*/
- CURRENT
- };
+ ExecutionControl generate(ExecutionEnv env) throws Throwable;
+ }
+
+ /**
+ * Attempts to load new classes.
+ *
+ * @param cbcs the class name and bytecodes to load
+ * @throws ClassInstallException exception occurred loading the classes,
+ * some or all were not loaded
+ * @throws NotImplementedException if not implemented
+ * @throws EngineTerminationException the execution engine has terminated
+ */
+ void load(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+ /**
+ * Attempts to redefine previously loaded classes.
+ *
+ * @param cbcs the class name and bytecodes to redefine
+ * @throws ClassInstallException exception occurred redefining the classes,
+ * some or all were not redefined
+ * @throws NotImplementedException if not implemented
+ * @throws EngineTerminationException the execution engine has terminated
+ */
+ void redefine(ClassBytecodes[] cbcs)
+ throws ClassInstallException, NotImplementedException, EngineTerminationException;
+
+ /**
+ * Invokes an executable Snippet by calling a method on the specified
+ * wrapper class. The method must have no arguments and return String.
+ *
+ * @param className the class whose method should be invoked
+ * @param methodName the name of method to invoke
+ * @return the result of the execution or null if no result
+ * @throws UserException the invoke raised a user exception
+ * @throws ResolutionException the invoke attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the {@code invoke()} was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String invoke(String className, String methodName)
+ throws RunException, EngineTerminationException, InternalException;
/**
- * Initializes the instance. No methods in this interface can be called
- * before this.
+ * Returns the value of a variable.
+ *
+ * @param className the name of the wrapper class of the variable
+ * @param varName the name of the variable
+ * @return the value of the variable
+ * @throws UserException formatting the value raised a user exception
+ * @throws ResolutionException formatting the value attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the formatting the value was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ String varValue(String className, String varName)
+ throws RunException, EngineTerminationException, InternalException;
+
+ /**
+ * Adds the path to the execution class path.
+ *
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ void addToClasspath(String path)
+ throws EngineTerminationException, InternalException;
+
+ /**
+ * Sets the execution class path to the specified path.
*
- * @param env the execution environment information provided by JShell
- * @throws Exception if the instance is unable to initialize
+ * @param path the path to add
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
+ */
+ void setClasspath(String path)
+ throws EngineTerminationException, InternalException;
+
+ /**
+ * Interrupts a running invoke.
+ *
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws InternalException an internal problem occurred
*/
- void start(ExecutionEnv env) throws Exception;
+ void stop()
+ throws EngineTerminationException, InternalException;
+
+ /**
+ * Run a non-standard command (or a standard command from a newer version).
+ *
+ * @param command the non-standard command
+ * @param arg the commands argument
+ * @return the commands return value
+ * @throws UserException the command raised a user exception
+ * @throws ResolutionException the command attempted to directly or
+ * indirectly invoke an unresolved snippet
+ * @throws StoppedException if the command was canceled by
+ * {@link ExecutionControl#stop}
+ * @throws EngineTerminationException the execution engine has terminated
+ * @throws NotImplementedException if not implemented
+ * @throws InternalException an internal problem occurred
+ */
+ Object extensionCommand(String command, Object arg)
+ throws RunException, EngineTerminationException, InternalException;
/**
* Shuts down this execution engine. Implementation should free all
@@ -88,67 +178,206 @@
void close();
/**
- * Adds the path to the execution class path.
- *
- * @param path the path to add
- * @return true if successful
+ * Bundles class name with class bytecodes.
*/
- boolean addToClasspath(String path);
+ public static final class ClassBytecodes implements Serializable {
+
+ private static final long serialVersionUID = 0xC1A55B47EC0DE5L;
+ private final String name;
+ private final byte[] bytecodes;
+
+ /**
+ * Creates a name/bytecode pair.
+ * @param name the class name
+ * @param bytecodes the class bytecodes
+ */
+ public ClassBytecodes(String name, byte[] bytecodes) {
+ this.name = name;
+ this.bytecodes = bytecodes;
+ }
+
+ /**
+ * The bytecodes for the class.
+ *
+ * @return the bytecodes
+ */
+ public byte[] bytecodes() {
+ return bytecodes;
+ }
+
+ /**
+ * The class name.
+ *
+ * @return the class name
+ */
+ public String name() {
+ return name;
+ }
+ }
/**
- * Invokes an executable Snippet by calling a method on the specified
- * wrapper class. The method must have no arguments and return String.
- *
- * @param classname the class whose method should be invoked
- * @param methodname the name of method to invoke
- * @return the result of the execution or null if no result
- * @throws JShellException if a user exception if thrown,
- * {@link jdk.jshell.EvalException EvalException} will be thrown; if an
- * unresolved reference is encountered,
- * {@link jdk.jshell.UnresolvedReferenceException UnresolvedReferenceException}
- * will be thrown
+ * The abstract base of all {@code ExecutionControl} exceptions.
*/
- String invoke(String classname, String methodname) throws JShellException;
+ public static abstract class ExecutionControlException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public ExecutionControlException(String message) {
+ super(message);
+ }
+ }
/**
- * Attempts to load new classes. Class bytes are retrieved from
- * {@link ExecutionEnv#getClassBytes(java.lang.String) }
- *
- * @param classes list of class names to load
- * @return true if load succeeded
+ * Unbidden execution engine termination has occurred.
+ */
+ public static class EngineTerminationException extends ExecutionControlException {
+
+ private static final long serialVersionUID = 1L;
+
+ public EngineTerminationException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * The command is not implemented.
*/
- boolean load(Collection<String> classes);
+ public static class NotImplementedException extends InternalException {
+
+ private static final long serialVersionUID = 1L;
+
+ public NotImplementedException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * An internal problem has occurred.
+ */
+ public static class InternalException extends ExecutionControlException {
+
+ private static final long serialVersionUID = 1L;
+
+ public InternalException(String message) {
+ super(message);
+ }
+ }
/**
- * Attempts to redefine previously loaded classes. Class bytes are retrieved
- * from {@link ExecutionEnv#getClassBytes(java.lang.String) }
- *
- * @param classes list of class names to redefine
- * @return true if redefine succeeded
+ * A class install (load or redefine) encountered a problem.
*/
- boolean redefine(Collection<String> classes);
+ public static class ClassInstallException extends ExecutionControlException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final boolean[] installed;
+
+ public ClassInstallException(String message, boolean[] installed) {
+ super(message);
+ this.installed = installed;
+ }
+
+ /**
+ * Indicates which of the passed classes were successfully
+ * loaded/redefined.
+ * @return a one-to-one array with the {@link ClassBytecodes}{@code[]}
+ * array -- {@code true} if installed
+ */
+ public boolean[] installed() {
+ return installed;
+ }
+ }
+
+ /**
+ * The abstract base of of exceptions specific to running user code.
+ */
+ public static abstract class RunException extends ExecutionControlException {
+
+ private static final long serialVersionUID = 1L;
+
+ private RunException(String message) {
+ super(message);
+ }
+ }
/**
- * Queries if the class is loaded and the class bytes are current.
- *
- * @param classname name of the wrapper class to query
- * @return {@code UNKNOWN} if the class is not loaded; {@code CURRENT} if
- * the loaded/redefined bytes are equal to the most recent bytes for this
- * wrapper class; otherwise {@code NOT_CURRENT}
+ * A 'normal' user exception occurred.
*/
- ClassStatus getClassStatus(String classname);
+ public static class UserException extends RunException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String causeExceptionClass;
+
+ public UserException(String message, String causeExceptionClass, StackTraceElement[] stackElements) {
+ super(message);
+ this.causeExceptionClass = causeExceptionClass;
+ this.setStackTrace(stackElements);
+ }
+
+ /**
+ * Returns the class of the user exception.
+ * @return the name of the user exception class
+ */
+ public String causeExceptionClass() {
+ return causeExceptionClass;
+ }
+ }
/**
- * Interrupt a running invoke.
+ * An exception indicating that a {@code DeclarationSnippet} with unresolved
+ * references has been encountered.
+ * <p>
+ * Contrast this with the initiating {@link SPIResolutionException}
+ * (a {@code RuntimeException}) which is embedded in generated corralled
+ * code. Also, contrast this with
+ * {@link jdk.jshell.UnresolvedReferenceException} the high-level
+ * exception (with {@code DeclarationSnippet} reference) provided in the
+ * main API.
*/
- void stop();
+ public static class ResolutionException extends RunException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final int id;
+
+ /**
+ * Constructs an exception indicating that a {@code DeclarationSnippet}
+ * with unresolved references has been encountered.
+ *
+ * @param id An internal identifier of the specific method
+ * @param stackElements the stack trace
+ */
+ public ResolutionException(int id, StackTraceElement[] stackElements) {
+ super("resolution exception: " + id);
+ this.id = id;
+ this.setStackTrace(stackElements);
+ }
+
+ /**
+ * Retrieves the internal identifier of the unresolved identifier.
+ *
+ * @return the internal identifier
+ */
+ public int id() {
+ return id;
+ }
+ }
/**
- * Returns the value of a variable.
- *
- * @param classname the name of the wrapper class of the variable
- * @param varname the name of the variable
- * @return the value of the variable
+ * An exception indicating that an
+ * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
+ * (or theoretically a
+ * {@link ExecutionControl#varValue(java.lang.String, java.lang.String) })
+ * has been interrupted by a {@link ExecutionControl#stop() }.
*/
- String varValue(String classname, String varname);
+ public static class StoppedException extends RunException {
+
+ private static final long serialVersionUID = 1L;
+
+ public StoppedException() {
+ super("stopped by stop()");
+ }
+ }
+
}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionEnv.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/ExecutionEnv.java Wed Jul 27 13:33:55 2016 +0000
@@ -28,14 +28,11 @@
import java.io.InputStream;
import java.io.PrintStream;
import java.util.List;
-import jdk.jshell.EvalException;
import jdk.jshell.JShell;
-import jdk.jshell.UnresolvedReferenceException;
/**
* Functionality made available to a pluggable JShell execution engine. It is
- * provided to the execution engine by the core JShell implementation calling
- * {@link ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }.
+ * provided to the execution engine by the core JShell implementation.
* <p>
* This interface is designed to provide the access to core JShell functionality
* needed to implement ExecutionControl.
@@ -66,11 +63,6 @@
PrintStream userErr();
/**
- * @return the JShell instance
- */
- JShell state();
-
- /**
* Returns the additional VM options to be used when launching the remote
* JVM. This is advice to the execution engine.
* <p>
@@ -81,47 +73,8 @@
List<String> extraRemoteVMOptions();
/**
- * Retrieves the class file bytes for the specified wrapper class.
- *
- * @param className the name of the wrapper class
- * @return the current class file bytes as a byte array
- */
- byte[] getClassBytes(String className);
-
- /**
- * Creates an {@code EvalException} corresponding to a user exception. An
- * user exception thrown during
- * {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
- * should be converted to an {@code EvalException} using this method.
- *
- * @param message the exception message to use (from the user exception)
- * @param exceptionClass the class name of the user exception
- * @param stackElements the stack trace elements to install
- * @return a user API EvalException for the user exception
- */
- EvalException createEvalException(String message, String exceptionClass,
- StackTraceElement[] stackElements);
-
- /**
- * Creates an {@code UnresolvedReferenceException} for the Snippet identifed
- * by the specified identifier. An {@link SPIResolutionException} thrown
- * during {@link ExecutionControl#invoke(java.lang.String, java.lang.String) }
- * should be converted to an {@code UnresolvedReferenceException} using
- * this method.
- * <p>
- * The identifier is an internal id, different from the id in the API. This
- * internal id is returned by {@link SPIResolutionException#id()}.
- *
- * @param id the internal integer identifier
- * @param stackElements the stack trace elements to install
- * @return an {@code UnresolvedReferenceException} for the unresolved
- * reference
- */
- UnresolvedReferenceException createUnresolvedReferenceException(int id,
- StackTraceElement[] stackElements);
-
- /**
* Reports that the execution engine has shutdown.
*/
void closeDown();
+
}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/SPIResolutionException.java Wed Jul 27 13:33:55 2016 +0000
@@ -33,9 +33,6 @@
* <p>
* This exception is seen by the execution engine, but not seen by
* the end user nor through the JShell API.
- *
- * @see ExecutionEnv#createUnresolvedReferenceException(int,
- * java.lang.StackTraceElement[])
*/
@SuppressWarnings("serial") // serialVersionUID intentionally omitted
public class SPIResolutionException extends RuntimeException {
@@ -57,11 +54,9 @@
}
/**
- * Retrieves the internal identifer of the unresolved identifer.
+ * Retrieves the internal identifier of the unresolved identifier.
*
- * @return the internal identifer
- * @see ExecutionEnv#createUnresolvedReferenceException(int,
- * java.lang.StackTraceElement[])
+ * @return the internal identifier
*/
public int id() {
return id;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/package-info.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/spi/package-info.java Wed Jul 27 13:33:55 2016 +0000
@@ -31,9 +31,9 @@
* implementation includes a default execution engine (currently a remote
* process which is JDI controlled). By implementing the
* {@link jdk.jshell.spi.ExecutionControl} interface and installing it with
- * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl) }
+ * {@link jdk.jshell.JShell.Builder#executionEngine(jdk.jshell.spi.ExecutionControl.Generator) }
* other execution engines can be used.
*
- * @see jdk.jshell.execution jdk.jshell.execution for execution implementation support
+ * @see jdk.jshell.execution for execution implementation support
*/
package jdk.jshell.spi;
--- a/langtools/test/jdk/jshell/ComputeFQNsTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/jdk/jshell/ComputeFQNsTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -76,7 +76,7 @@
assertInferredFQNs("class X { ArrayList", "ArrayList".length(), false, "java.util.ArrayList");
}
- @Test
+ @Test(enabled = false) //TODO 8161165
public void testSuspendIndexing() throws Throwable {
compiler.compile(outDir, "package test; public class FQNTest { }");
String jarName = "test.jar";
--- a/langtools/test/jdk/jshell/FailOverExecutionControlTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/jdk/jshell/FailOverExecutionControlTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -23,23 +23,20 @@
/*
* @test
- * @bug 8131029
- * @summary Test that fail-over works for FailOverExecutionControl
- * @modules jdk.jshell/jdk.internal.jshell.jdi
+ * @bug 8131029 8160127 8159935
+ * @summary Test that fail-over works for fail-over ExecutionControl generators.
+ * @modules jdk.jshell/jdk.jshell.execution
* jdk.jshell/jdk.jshell.spi
* @build KullaTesting ExecutionControlTestBase
* @run testng FailOverExecutionControlTest
*/
-
-import java.util.Collection;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
-import jdk.internal.jshell.jdi.FailOverExecutionControl;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
-import jdk.jshell.JShellException;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
import jdk.jshell.spi.ExecutionControl;
import jdk.jshell.spi.ExecutionEnv;
+import static jdk.jshell.execution.Util.failOverExecutionControlGenerator;
@Test
public class FailOverExecutionControlTest extends ExecutionControlTestBase {
@@ -47,56 +44,16 @@
@BeforeMethod
@Override
public void setUp() {
- setUp(new FailOverExecutionControl(
- new AlwaysFailingExecutionControl(),
- new AlwaysFailingExecutionControl(),
- new JDIExecutionControl()));
+ setUp(builder -> builder.executionEngine(failOverExecutionControlGenerator(
+ new AlwaysFailingGenerator(),
+ new AlwaysFailingGenerator(),
+ JDIDefaultExecutionControl.launch())));
}
- class AlwaysFailingExecutionControl implements ExecutionControl {
-
- @Override
- public void start(ExecutionEnv env) throws Exception {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public void close() {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public boolean addToClasspath(String path) {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
+ class AlwaysFailingGenerator implements ExecutionControl.Generator {
@Override
- public String invoke(String classname, String methodname) throws JShellException {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public boolean load(Collection<String> classes) {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public boolean redefine(Collection<String> classes) {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public ClassStatus getClassStatus(String classname) {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public void stop() {
- throw new UnsupportedOperationException("This operation intentionally broken.");
- }
-
- @Override
- public String varValue(String classname, String varname) {
+ public ExecutionControl generate(ExecutionEnv env) throws UnsupportedOperationException {
throw new UnsupportedOperationException("This operation intentionally broken.");
}
--- a/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/jdk/jshell/JDIListeningExecutionControlTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -23,9 +23,9 @@
/*
* @test
- * @bug 8131029
+ * @bug 8131029 8159935 8160127
* @summary Tests for alternate JDI connector -- listening
- * @modules jdk.jshell/jdk.internal.jshell.jdi
+ * @modules jdk.jshell/jdk.jshell.execution
* @build KullaTesting ExecutionControlTestBase
* @run testng JDIListeningExecutionControlTest
*/
@@ -33,7 +33,7 @@
import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
-import jdk.internal.jshell.jdi.JDIExecutionControl;
+import jdk.jshell.execution.JDIDefaultExecutionControl;
@Test
public class JDIListeningExecutionControlTest extends ExecutionControlTestBase {
@@ -41,6 +41,6 @@
@BeforeMethod
@Override
public void setUp() {
- setUp(new JDIExecutionControl(false));
+ setUp(builder -> builder.executionEngine(JDIDefaultExecutionControl.listen()));
}
}
--- a/langtools/test/jdk/jshell/KullaTesting.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/jdk/jshell/KullaTesting.java Wed Jul 27 13:33:55 2016 +0000
@@ -73,7 +73,6 @@
import static jdk.jshell.Snippet.Status.*;
import static org.testng.Assert.*;
import static jdk.jshell.Snippet.SubKind.METHOD_SUBKIND;
-import jdk.jshell.spi.ExecutionControl;
public class KullaTesting {
@@ -158,10 +157,6 @@
setUp(b -> {});
}
- public void setUp(ExecutionControl ec) {
- setUp(b -> b.executionEngine(ec));
- }
-
public void setUp(Consumer<JShell.Builder> bc) {
inStream = new TestingInputStream();
outStream = new ByteArrayOutputStream();
--- a/langtools/test/jdk/jshell/LocalExecutionControl.java Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import jdk.jshell.spi.ExecutionControl;
-import jdk.jshell.spi.ExecutionEnv;
-import jdk.jshell.spi.SPIResolutionException;
-import jdk.jshell.EvalException;
-import jdk.jshell.UnresolvedReferenceException;
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * An implementation of ExecutionControl which executes in the same JVM as the
- * JShell core.
- *
- * @author Grigory Ptashko
- */
-class LocalExecutionControl implements ExecutionControl {
- private class REPLClassLoader extends URLClassLoader {
- REPLClassLoader() {
- super(new URL[0]);
- }
-
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- debug("findClass %s\n", name);
- byte[] b = execEnv.getClassBytes(name);
- if (b == null) {
- return super.findClass(name);
- }
- return super.defineClass(name, b, 0, b.length, (CodeSource)null);
- }
-
- @Override
- public void addURL(URL url) {
- super.addURL(url);
- }
- }
-
- private ExecutionEnv execEnv;
- private final Object STOP_LOCK = new Object();
- private boolean userCodeRunning = false;
- private REPLClassLoader loader = new REPLClassLoader();
- private final Map<String, Class<?>> klasses = new TreeMap<>();
- private final Map<String, byte[]> classBytes = new HashMap<>();
- private ThreadGroup execThreadGroup;
-
- @Override
- public void start(ExecutionEnv execEnv) throws Exception {
- this.execEnv = execEnv;
-
- debug("Process-local code snippets execution control started");
- }
-
- @Override
- public void close() {
- }
-
- @Override
- public boolean load(Collection<String> classes) {
- try {
- loadLocal(classes);
-
- return true;
- } catch (ClassNotFoundException | ClassCastException ex) {
- debug(ex, "Exception on load operation");
- }
-
- return false;
- }
-
- @Override
- public String invoke(String classname, String methodname) throws EvalException, UnresolvedReferenceException {
- try {
- synchronized (STOP_LOCK) {
- userCodeRunning = true;
- }
-
- // Invoke executable entry point in loaded code
- Class<?> klass = klasses.get(classname);
- if (klass == null) {
- debug("Invoke failure: no such class loaded %s\n", classname);
-
- return "";
- }
-
- Method doitMethod;
- try {
- this.getClass().getModule().addReads(klass.getModule());
- this.getClass().getModule().addExports(SPIResolutionException.class.getPackage()
- .getName(), klass.getModule());
- doitMethod = klass.getDeclaredMethod(methodname, new Class<?>[0]);
- doitMethod.setAccessible(true);
-
- execThreadGroup = new ThreadGroup("JShell process local execution");
-
- AtomicReference<InvocationTargetException> iteEx = new AtomicReference<>();
- AtomicReference<IllegalAccessException> iaeEx = new AtomicReference<>();
- AtomicReference<NoSuchMethodException> nmeEx = new AtomicReference<>();
- AtomicReference<Boolean> stopped = new AtomicReference<>(false);
-
- Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
- if (e instanceof InvocationTargetException) {
- if (e.getCause() instanceof ThreadDeath) {
- stopped.set(true);
- } else {
- iteEx.set((InvocationTargetException)e);
- }
- } else if (e instanceof IllegalAccessException) {
- iaeEx.set((IllegalAccessException)e);
- } else if (e instanceof NoSuchMethodException) {
- nmeEx.set((NoSuchMethodException)e);
- } else if (e instanceof ThreadDeath) {
- stopped.set(true);
- }
- });
-
- final Object[] res = new Object[1];
- Thread snippetThread = new Thread(execThreadGroup, () -> {
- try {
- res[0] = doitMethod.invoke(null, new Object[0]);
- } catch (InvocationTargetException e) {
- if (e.getCause() instanceof ThreadDeath) {
- stopped.set(true);
- } else {
- iteEx.set(e);
- }
- } catch (IllegalAccessException e) {
- iaeEx.set(e);
- } catch (ThreadDeath e) {
- stopped.set(true);
- }
- });
-
- snippetThread.start();
- Thread[] threadList = new Thread[execThreadGroup.activeCount()];
- execThreadGroup.enumerate(threadList);
- for (Thread thread : threadList) {
- if (thread != null)
- thread.join();
- }
-
- if (stopped.get()) {
- debug("Killed.");
-
- return "";
- }
-
- if (iteEx.get() != null) {
- throw iteEx.get();
- } else if (nmeEx.get() != null) {
- throw nmeEx.get();
- } else if (iaeEx.get() != null) {
- throw iaeEx.get();
- }
-
- return valueString(res[0]);
- } catch (InvocationTargetException ex) {
- Throwable cause = ex.getCause();
- StackTraceElement[] elems = cause.getStackTrace();
- if (cause instanceof SPIResolutionException) {
- int id = ((SPIResolutionException)cause).id();
-
- throw execEnv.createUnresolvedReferenceException(id, elems);
- } else {
- throw execEnv.createEvalException(cause.getMessage() == null ?
- "<none>" : cause.getMessage(), cause.getClass().getName(), elems);
- }
- } catch (NoSuchMethodException | IllegalAccessException | InterruptedException ex) {
- debug(ex, "Invoke failure");
- }
- } finally {
- synchronized (STOP_LOCK) {
- userCodeRunning = false;
- }
- }
-
- return "";
- }
-
- @Override
- @SuppressWarnings("deprecation")
- public void stop() {
- synchronized (STOP_LOCK) {
- if (!userCodeRunning)
- return;
-
- if (execThreadGroup == null) {
- debug("Process-local code snippets thread group is null. Aborting stop.");
-
- return;
- }
-
- execThreadGroup.stop();
- }
- }
-
- @Override
- public String varValue(String classname, String varname) {
- Class<?> klass = klasses.get(classname);
- if (klass == null) {
- debug("Var value failure: no such class loaded %s\n", classname);
-
- return "";
- }
- try {
- this.getClass().getModule().addReads(klass.getModule());
- Field var = klass.getDeclaredField(varname);
- var.setAccessible(true);
- Object res = var.get(null);
-
- return valueString(res);
- } catch (Exception ex) {
- debug("Var value failure: no such field %s.%s\n", classname, varname);
- }
-
- return "";
- }
-
- @Override
- public boolean addToClasspath(String cp) {
- // Append to the claspath
- for (String path : cp.split(File.pathSeparator)) {
- try {
- loader.addURL(new File(path).toURI().toURL());
- } catch (MalformedURLException e) {
- throw new InternalError("Classpath addition failed: " + cp, e);
- }
- }
-
- return true;
- }
-
- @Override
- public boolean redefine(Collection<String> classes) {
- return false;
- }
-
- @Override
- public ClassStatus getClassStatus(String classname) {
- if (!classBytes.containsKey(classname)) {
- return ClassStatus.UNKNOWN;
- } else if (!Arrays.equals(classBytes.get(classname), execEnv.getClassBytes(classname))) {
- return ClassStatus.NOT_CURRENT;
- } else {
- return ClassStatus.CURRENT;
- }
- }
-
- private void loadLocal(Collection<String> classes) throws ClassNotFoundException {
- for (String className : classes) {
- Class<?> klass = loader.loadClass(className);
- klasses.put(className, klass);
- classBytes.put(className, execEnv.getClassBytes(className));
- klass.getDeclaredMethods();
- }
- }
-
- private void debug(String format, Object... args) {
- //debug(execEnv.state(), execEnv.userErr(), flags, format, args);
- }
-
- private void debug(Exception ex, String where) {
- //debug(execEnv.state(), execEnv.userErr(), ex, where);
- }
-
- private static String valueString(Object value) {
- if (value == null) {
- return "null";
- } else if (value instanceof String) {
- return "\"" + (String)value + "\"";
- } else if (value instanceof Character) {
- return "'" + value + "'";
- } else {
- return value.toString();
- }
- }
-}
--- a/langtools/test/jdk/jshell/UserExecutionControlTest.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/jdk/jshell/UserExecutionControlTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -23,13 +23,14 @@
/*
* @test
- * @bug 8156101
+ * @bug 8156101 8159935 8159122
* @summary Tests for ExecutionControl SPI
- * @build KullaTesting LocalExecutionControl ExecutionControlTestBase
+ * @build KullaTesting ExecutionControlTestBase
* @run testng UserExecutionControlTest
*/
+import jdk.jshell.execution.LocalExecutionControl;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.BeforeMethod;
@@ -40,7 +41,7 @@
@BeforeMethod
@Override
public void setUp() {
- setUp(new LocalExecutionControl());
+ setUp(builder -> builder.executionEngine(LocalExecutionControl.create()));
}
public void verifyLocal() throws ClassNotFoundException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/jshell/UserJDIUserRemoteTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8160128 8159935
+ * @summary Tests for Aux channel, custom remote agents, custom JDI implementations.
+ * @build KullaTesting ExecutionControlTestBase
+ * @run testng UserJDIUserRemoteTest
+ */
+import java.io.ByteArrayOutputStream;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import jdk.jshell.Snippet;
+import static jdk.jshell.Snippet.Status.OVERWRITTEN;
+import static jdk.jshell.Snippet.Status.VALID;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.List;
+import com.sun.jdi.VMDisconnectedException;
+import com.sun.jdi.VirtualMachine;
+import jdk.jshell.VarSnippet;
+import jdk.jshell.execution.DirectExecutionControl;
+import jdk.jshell.execution.JDIExecutionControl;
+import jdk.jshell.execution.JDIInitiator;
+import jdk.jshell.execution.Util;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import jdk.jshell.spi.ExecutionControl;
+import jdk.jshell.spi.ExecutionControl.ExecutionControlException;
+import jdk.jshell.spi.ExecutionEnv;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+import static jdk.jshell.execution.Util.forwardExecutionControlAndIO;
+import static jdk.jshell.execution.Util.remoteInput;
+
+@Test
+public class UserJDIUserRemoteTest extends ExecutionControlTestBase {
+
+ ExecutionControl currentEC;
+ ByteArrayOutputStream auxStream;
+
+ @BeforeMethod
+ @Override
+ public void setUp() {
+ auxStream = new ByteArrayOutputStream();
+ setUp(builder -> builder.executionEngine(MyExecutionControl.create(this)));
+ }
+
+ public void testVarValue() {
+ VarSnippet dv = varKey(assertEval("double aDouble = 1.5;"));
+ String vd = getState().varValue(dv);
+ assertEquals(vd, "1.5");
+ assertEquals(auxStream.toString(), "aDouble");
+ }
+
+ public void testExtension() throws ExecutionControlException {
+ assertEval("42;");
+ Object res = currentEC.extensionCommand("FROG", "test");
+ assertEquals(res, "ribbit");
+ }
+
+ public void testRedefine() {
+ Snippet vx = varKey(assertEval("int x;"));
+ Snippet mu = methodKey(assertEval("int mu() { return x * 4; }"));
+ Snippet c = classKey(assertEval("class C { String v() { return \"#\" + mu(); } }"));
+ assertEval("C c0 = new C();");
+ assertEval("c0.v();", "\"#0\"");
+ assertEval("int x = 10;", "10",
+ ste(MAIN_SNIPPET, VALID, VALID, false, null),
+ ste(vx, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+ assertEval("c0.v();", "\"#40\"");
+ assertEval("C c = new C();");
+ assertEval("c.v();", "\"#40\"");
+ assertEval("int mu() { return x * 3; }",
+ ste(MAIN_SNIPPET, VALID, VALID, false, null),
+ ste(mu, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+ assertEval("c.v();", "\"#30\"");
+ assertEval("class C { String v() { return \"@\" + mu(); } }",
+ ste(MAIN_SNIPPET, VALID, VALID, false, null),
+ ste(c, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
+ assertEval("c0.v();", "\"@30\"");
+ assertEval("c = new C();");
+ assertEval("c.v();", "\"@30\"");
+ assertActiveKeys();
+ }
+}
+
+class MyExecutionControl extends JDIExecutionControl {
+
+ private static final String REMOTE_AGENT = MyRemoteExecutionControl.class.getName();
+
+ private VirtualMachine vm;
+ private Process process;
+
+ /**
+ * Creates an ExecutionControl instance based on a JDI
+ * {@code LaunchingConnector}.
+ *
+ * @return the generator
+ */
+ public static ExecutionControl.Generator create(UserJDIUserRemoteTest test) {
+ return env -> make(env, test);
+ }
+
+ /**
+ * Creates an ExecutionControl instance based on a JDI
+ * {@code ListeningConnector} or {@code LaunchingConnector}.
+ *
+ * Initialize JDI and use it to launch the remote JVM. Set-up a socket for
+ * commands and results. This socket also transports the user
+ * input/output/error.
+ *
+ * @param env the context passed by
+ * {@link jdk.jshell.spi.ExecutionControl#start(jdk.jshell.spi.ExecutionEnv) }
+ * @return the channel
+ * @throws IOException if there are errors in set-up
+ */
+ static MyExecutionControl make(ExecutionEnv env, UserJDIUserRemoteTest test) throws IOException {
+ try (final ServerSocket listener = new ServerSocket(0)) {
+ // timeout after 60 seconds
+ listener.setSoTimeout(60000);
+ int port = listener.getLocalPort();
+
+ // Set-up the JDI connection
+ List<String> opts = new ArrayList<>(env.extraRemoteVMOptions());
+ opts.add("-classpath");
+ opts.add(System.getProperty("java.class.path")
+ + System.getProperty("path.separator")
+ + System.getProperty("user.dir"));
+ JDIInitiator jdii = new JDIInitiator(port,
+ opts, REMOTE_AGENT, true);
+ VirtualMachine vm = jdii.vm();
+ Process process = jdii.process();
+
+ List<Consumer<String>> deathListeners = new ArrayList<>();
+ deathListeners.add(s -> env.closeDown());
+ Util.detectJDIExitEvent(vm, s -> {
+ for (Consumer<String> h : deathListeners) {
+ h.accept(s);
+ }
+ });
+
+ // Set-up the commands/reslts on the socket. Piggy-back snippet
+ // output.
+ Socket socket = listener.accept();
+ // out before in -- match remote creation so we don't hang
+ ObjectOutput cmdout = new ObjectOutputStream(socket.getOutputStream());
+ Map<String, OutputStream> io = new HashMap<>();
+ io.put("out", env.userOut());
+ io.put("err", env.userErr());
+ io.put("aux", test.auxStream);
+ ObjectInput cmdin = remoteInput(socket.getInputStream(), io);
+ MyExecutionControl myec = new MyExecutionControl(cmdout, cmdin, vm, process, deathListeners);
+ test.currentEC = myec;
+ return myec;
+ }
+ }
+
+ /**
+ * Create an instance.
+ *
+ * @param out the output for commands
+ * @param in the input for responses
+ */
+ private MyExecutionControl(ObjectOutput out, ObjectInput in,
+ VirtualMachine vm, Process process,
+ List<Consumer<String>> deathListeners) {
+ super(out, in);
+ this.vm = vm;
+ this.process = process;
+ deathListeners.add(s -> disposeVM());
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ disposeVM();
+ }
+
+ private synchronized void disposeVM() {
+ try {
+ if (vm != null) {
+ vm.dispose(); // This could NPE, so it is caught below
+ vm = null;
+ }
+ } catch (VMDisconnectedException ex) {
+ // Ignore if already closed
+ } catch (Throwable e) {
+ fail("disposeVM threw: " + e);
+ } finally {
+ if (process != null) {
+ process.destroy();
+ process = null;
+ }
+ }
+ }
+
+ @Override
+ protected synchronized VirtualMachine vm() throws EngineTerminationException {
+ if (vm == null) {
+ throw new EngineTerminationException("VM closed");
+ } else {
+ return vm;
+ }
+ }
+
+}
+
+class MyRemoteExecutionControl extends DirectExecutionControl implements ExecutionControl {
+
+ static PrintStream auxPrint;
+
+ /**
+ * Launch the agent, connecting to the JShell-core over the socket specified
+ * in the command-line argument.
+ *
+ * @param args standard command-line arguments, expectation is the socket
+ * number is the only argument
+ * @throws Exception any unexpected exception
+ */
+ public static void main(String[] args) throws Exception {
+ try {
+ String loopBack = null;
+ Socket socket = new Socket(loopBack, Integer.parseInt(args[0]));
+ InputStream inStream = socket.getInputStream();
+ OutputStream outStream = socket.getOutputStream();
+ Map<String, Consumer<OutputStream>> chans = new HashMap<>();
+ chans.put("out", st -> System.setOut(new PrintStream(st, true)));
+ chans.put("err", st -> System.setErr(new PrintStream(st, true)));
+ chans.put("aux", st -> { auxPrint = new PrintStream(st, true); });
+ forwardExecutionControlAndIO(new MyRemoteExecutionControl(), inStream, outStream, chans);
+ } catch (Throwable ex) {
+ throw ex;
+ }
+ }
+
+ @Override
+ public String varValue(String className, String varName)
+ throws RunException, EngineTerminationException, InternalException {
+ auxPrint.print(varName);
+ return super.varValue(className, varName);
+ }
+
+ @Override
+ public Object extensionCommand(String className, Object arg)
+ throws RunException, EngineTerminationException, InternalException {
+ if (!arg.equals("test")) {
+ throw new InternalException("expected extensionCommand arg to be 'test' got: " + arg);
+ }
+ return "ribbit";
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985a.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,28 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8161985
+ * @summary Spurious override of Object.getClass leads to NPE
+ * @compile/fail/ref=T8161985a.out -XDrawDiagnostics T8161985a.java
+ */
+
+class T8161985 {
+ public static void main(String [] arg) {
+ T8161985 t = new T8161985();
+ t.getClass();
+
+ }
+ public void getClass() {
+ Fred1 f = new Fred1();
+ System.out.println( "fred classname: " + f.getClassName());
+ }
+
+
+ abstract class Fred {
+ public String getClassName() {
+ return this.getClass().getSimpleName();
+ }
+ }
+
+ class Fred1 extends Fred {
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985a.out Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,2 @@
+T8161985a.java:14:17: compiler.err.override.meth: (compiler.misc.cant.override: getClass(), T8161985, getClass(), java.lang.Object), final
+1 error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985b.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8161985
+ * @summary Spurious override of Object.getClass leads to NPE
+ * @compile/fail/ref=T8161985b.out -XDrawDiagnostics T8161985b.java
+ */
+
+class T8161985b {
+ public String getClass() { return ""; }
+
+ void test() {
+ this.getClass().getSimpleName();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/8161985/T8161985b.out Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,3 @@
+T8161985b.java:9:18: compiler.err.override.meth: (compiler.misc.cant.override: getClass(), T8161985b, getClass(), java.lang.Object), final
+T8161985b.java:12:22: compiler.err.cant.resolve.location.args: kindname.method, getSimpleName, , , (compiler.misc.location: kindname.class, java.lang.String, null)
+2 errors
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234a.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234a.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,8 +3,8 @@
* @bug 6722234
* @summary javac diagnostics need better integration with the type-system
* @author mcimadamore
- * @compile/fail/ref=T6722234a_1.out -XDrawDiagnostics -XDdiags=disambiguateTvars T6722234a.java
- * @compile/fail/ref=T6722234a_2.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6722234a.java
+ * @compile/fail/ref=T6722234a_1.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars T6722234a.java
+ * @compile/fail/ref=T6722234a_2.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6722234a.java
*/
class T6722234a<T extends String> {
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234b.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234b.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,8 +3,8 @@
* @bug 6722234 8078024
* @summary javac diagnostics need better integration with the type-system
* @author mcimadamore
- * @compile/fail/ref=T6722234b_1.out -XDrawDiagnostics -XDdiags=simpleNames T6722234b.java
- * @compile/fail/ref=T6722234b_2.out -XDrawDiagnostics -XDdiags=simpleNames,where T6722234b.java
+ * @compile/fail/ref=T6722234b_1.out -XDrawDiagnostics -diags:formatterOptions=simpleNames T6722234b.java
+ * @compile/fail/ref=T6722234b_2.out -XDrawDiagnostics -diags:formatterOptions=simpleNames,where T6722234b.java
*/
import java.util.*;
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234c.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234c.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 6722234
* @summary javac diagnostics need better integration with the type-system
* @author mcimadamore
- * @compile/fail/ref=T6722234c.out -XDrawDiagnostics -XDdiags=simpleNames T6722234c.java
+ * @compile/fail/ref=T6722234c.out -XDrawDiagnostics -diags:formatterOptions=simpleNames T6722234c.java
*/
class T6722234c {
--- a/langtools/test/tools/javac/Diagnostics/6722234/T6722234d.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6722234/T6722234d.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,8 +3,8 @@
* @bug 6722234 8078024
* @summary javac diagnostics need better integration with the type-system
* @author mcimadamore
- * @compile/fail/ref=T6722234d_1.out -XDrawDiagnostics -XDdiags=where T6722234d.java
- * @compile/fail/ref=T6722234d_2.out -XDrawDiagnostics -XDdiags=where,simpleNames T6722234d.java
+ * @compile/fail/ref=T6722234d_1.out -XDrawDiagnostics -diags:formatterOptions=where T6722234d.java
+ * @compile/fail/ref=T6722234d_2.out -XDrawDiagnostics -diags:formatterOptions=where,simpleNames T6722234d.java
*/
class T6722234d {
--- a/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6769027/T6769027.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,8 +59,8 @@
enum CaretKind {
DEFAULT("", ""),
- SHOW("showCaret","true"),
- HIDE("showCaret","false");
+ SHOW("diags.showCaret","true"),
+ HIDE("diags.showCaret","false");
String key;
String value;
@@ -81,8 +81,8 @@
enum SourceLineKind {
DEFAULT("", ""),
- AFTER_SUMMARY("sourcePosition", "top"),
- BOTTOM("sourcePosition", "bottom");
+ AFTER_SUMMARY("diags.sourcePosition", "top"),
+ BOTTOM("diags.sourcePosition", "bottom");
String key;
String value;
@@ -110,9 +110,9 @@
void init(Options opts) {
if (this != DEFAULT) {
- String flags = opts.get("diags");
+ String flags = opts.get("diags.formatterOptions");
flags = flags == null ? flag : flags + "," + flag;
- opts.put("diags", flags);
+ opts.put("diags.formatterOptions", flags);
}
}
@@ -136,9 +136,9 @@
void init(Options opts) {
if (this != DEFAULT) {
- String flags = opts.get("diags");
+ String flags = opts.get("diags.formatterOptions");
flags = flags == null ? flag : flags + "," + flag;
- opts.put("diags", flags);
+ opts.put("diags.formatterOptions", flags);
}
}
@@ -243,11 +243,11 @@
}
enum MultilinePolicy {
- ENABLED(0, "multilinePolicy", "enabled"),
- DISABLED(1, "multilinePolicy", "disabled"),
- LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"),
- LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"),
- LIMIT_BOTH(4, "multilinePolicy", "limit:1:1");
+ ENABLED(0, "diags.multilinePolicy", "enabled"),
+ DISABLED(1, "diags.multilinePolicy", "disabled"),
+ LIMIT_LENGTH(2, "diags.multilinePolicy", "limit:1:*"),
+ LIMIT_DEPTH(3, "diags.multilinePolicy", "limit:*:1"),
+ LIMIT_BOTH(4, "diags.multilinePolicy", "limit:1:1");
String name;
String value;
@@ -371,7 +371,7 @@
indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0";
indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
- options.put("diagsIndentation", indentString);
+ options.put("diags.indent", indentString);
MyLog log = new MyLog(ctx);
JavacMessages messages = JavacMessages.instance(ctx);
messages.add(locale -> ResourceBundle.getBundle("tester", locale));
--- a/langtools/test/tools/javac/Diagnostics/6862608/T6862608a.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6862608/T6862608a.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 6862608
* @summary rich diagnostic sometimes contain wrong type variable numbering
* @author mcimadamore
- * @compile/fail/ref=T6862608a.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6862608a.java
+ * @compile/fail/ref=T6862608a.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6862608a.java
*/
--- a/langtools/test/tools/javac/Diagnostics/6862608/T6862608b.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/6862608/T6862608b.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 6862608
* @summary rich diagnostic sometimes contain wrong type variable numbering
* @author mcimadamore
- * @compile/fail/ref=T6862608b.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T6862608b.java
+ * @compile/fail/ref=T6862608b.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T6862608b.java
*/
class T66862608b<T extends String, S> {
--- a/langtools/test/tools/javac/Diagnostics/7010608/Test.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/7010608/Test.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,9 +46,9 @@
try {
test(Arrays.<String>asList(),
"myfo://test:1: error: cannot find symbol");
- test(Arrays.asList("-XDdiagsFormat=OLD"),
+ test(Arrays.asList("-diags:layout=OLD"),
"myfo://test:1: cannot find symbol");
- test(Arrays.asList("-XDoldDiags"),
+ test(Arrays.asList("-diags:legacy"),
"myfo://test:1: cannot find symbol");
} finally {
Locale.setDefault(prev);
--- a/langtools/test/tools/javac/Diagnostics/8010387/T8010387.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/Diagnostics/8010387/T8010387.java Wed Jul 27 13:33:55 2016 +0000
@@ -2,7 +2,7 @@
* @test /nodynamiccopyright/
* @bug 8010387
* @summary rich diagnostic sometimes contain wrong type variable numbering
- * @compile/fail/ref=T8010387.out -XDrawDiagnostics -XDdiags=disambiguateTvars,where T8010387.java
+ * @compile/fail/ref=T8010387.out -XDrawDiagnostics -diags:formatterOptions=disambiguateTvars,where T8010387.java
*/
abstract class T8010387<X> {
--- a/langtools/test/tools/javac/InterfaceMemberClassModifiers.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/InterfaceMemberClassModifiers.java Wed Jul 27 13:33:55 2016 +0000
@@ -4,7 +4,7 @@
* @summary Verify that invalid access modifiers on interface members don't cause crash.
* @author maddox
*
- * @compile/fail/ref=InterfaceMemberClassModifiers.out -XDdiags=%b:%l:%_%m InterfaceMemberClassModifiers.java
+ * @compile/fail/ref=InterfaceMemberClassModifiers.out -diags:layout=%b:%l:%_%m InterfaceMemberClassModifiers.java
*/
public interface InterfaceMemberClassModifiers {
--- a/langtools/test/tools/javac/T5003235/T5003235a.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/T5003235/T5003235a.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 5003235
* @summary Private inner class accessible from subclasses
* @author Peter von der Ah\u00e9
- * @compile/fail/ref=T5003235a.out -XDdiags=%b:%l:%_%m T5003235a.java
+ * @compile/fail/ref=T5003235a.out -diags:layout=%b:%l:%_%m T5003235a.java
*/
class Super {
--- a/langtools/test/tools/javac/T5003235/T5003235b.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/T5003235/T5003235b.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 5003235
* @summary Accessibility of private inner class
* @author Peter von der Ah\u00e9
- * @compile/fail/ref=T5003235b.out -XDdiags=%b:%l:%_%m T5003235b.java
+ * @compile/fail/ref=T5003235b.out -diags:layout=%b:%l:%_%m T5003235b.java
*/
class Outer {
--- a/langtools/test/tools/javac/T6214885.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/T6214885.java Wed Jul 27 13:33:55 2016 +0000
@@ -2,8 +2,8 @@
* @test /nodynamiccopyright/
* @bug 6214885
* @summary This test exercises features provided by the new internal Diagnostics API
- * @compile/fail/ref=T6214885a.out -XDdiags=%b:%l%_%t%m|%p%m T6214885.java
- * @compile/fail/ref=T6214885b.out -XDdiags=%b:%l:%c%_%t%m|%p%m T6214885.java
+ * @compile/fail/ref=T6214885a.out -diags:layout=%b:%l%_%t%m|%p%m T6214885.java
+ * @compile/fail/ref=T6214885b.out -diags:layout=%b:%l:%c%_%t%m|%p%m T6214885.java
*/
class T6214885
{
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/T8161383/LookingForOperatorSymbolsAtWrongPlaceTest.java Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,18 @@
+/**
+ * @test /nodynamiccopyright/
+ * @bug 8161383
+ * @summary javac is looking for operator symbols at the wrong place
+ * @compile LookingForOperatorSymbolsAtWrongPlaceTest.java
+ */
+
+public class LookingForOperatorSymbolsAtWrongPlaceTest {
+ class Base {
+ protected int i = 1;
+ }
+
+ class Sub extends Base {
+ void func(){
+ Sub.super.i += 10;
+ }
+ }
+}
--- a/langtools/test/tools/javac/api/6731573/T6731573.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/api/6731573/T6731573.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,8 +62,8 @@
enum SourceLine {
STANDARD(null),
- ENABLED("-XDshowSource=true"),
- DISABLED("-XDshowSource=false");
+ ENABLED("-diags:showSource=true"),
+ DISABLED("-diags:showSource=false");
String optValue;
--- a/langtools/test/tools/javac/diags/CheckResourceKeys.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/CheckResourceKeys.java Wed Jul 27 13:33:55 2016 +0000
@@ -263,6 +263,9 @@
// ignore shouldstop flag names
if (cs.startsWith("shouldstop."))
continue;
+ // ignore diagsformat flag names
+ if (cs.startsWith("diags."))
+ continue;
// explicit known exceptions
if (noResourceRequired.contains(cs))
continue;
--- a/langtools/test/tools/javac/diags/examples/WhereCaptured.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereCaptured.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
// key: compiler.err.cant.apply.symbol
// key: compiler.misc.incompatible.eq.bounds
// key: compiler.misc.captured.type
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
// run: simple
import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereCaptured1.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereCaptured1.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
// key: compiler.misc.incompatible.eq.bounds
// key: compiler.misc.captured.type
// key: compiler.misc.type.null
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
// run: simple
import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereFreshTvar.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereFreshTvar.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
// key: compiler.misc.where.description.typevar
// key: compiler.err.prob.found.req
// key: compiler.misc.inconvertible.types
-// options: -XDdiags=where,simpleNames
+// options: -diags:formatterOptions=where,simpleNames
// run: simple
import java.util.*;
--- a/langtools/test/tools/javac/diags/examples/WhereIntersection.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereIntersection.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
// key: compiler.misc.where.description.intersection.1
// key: compiler.misc.where.intersection
// key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
// run: simple
class WhereIntersection {
--- a/langtools/test/tools/javac/diags/examples/WhereIntersection2.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereIntersection2.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
// key: compiler.misc.where.description.intersection
// key: compiler.misc.where.intersection
// key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
// run: simple
class WhereIntersection2 {
--- a/langtools/test/tools/javac/diags/examples/WhereTypeVar.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereTypeVar.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@
// key: compiler.err.cant.apply.symbol
// key: compiler.misc.no.conforming.assignment.exists
// key: compiler.misc.inconvertible.types
-// options: -XDdiags=where,disambiguateTvars
+// options: -diags:formatterOptions=where,disambiguateTvars
// run: simple
class WhereTypeVar<T extends String> {
--- a/langtools/test/tools/javac/diags/examples/WhereTypeVar2.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/diags/examples/WhereTypeVar2.java Wed Jul 27 13:33:55 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
// key: compiler.misc.where.description.typevar
// key: compiler.misc.where.typevar
// key: compiler.err.prob.found.req
-// options: -XDdiags=where
+// options: -diags:formatterOptions=where
// run: simple
class WhereTypeVar2 {
--- a/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/missingSuperRecovery/MissingSuperRecovery.java Wed Jul 27 13:33:55 2016 +0000
@@ -5,7 +5,7 @@
* class is no longer available during a subsequent compilation.
* @author maddox
* @build impl
- * @compile/fail/ref=MissingSuperRecovery.out -XDdiags=%b:%l:%_%m MissingSuperRecovery.java
+ * @compile/fail/ref=MissingSuperRecovery.out -diags:layout=%b:%l:%_%m MissingSuperRecovery.java
*/
// Requires "golden" class file 'impl.class', which contains
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess2.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess2.java Wed Jul 27 13:33:55 2016 +0000
@@ -4,7 +4,7 @@
* @summary Verify correct implementation of JLS2e 6.6.2.1
* @author maddox
*
- * @compile/fail/ref=ProtectedMemberAccess2.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess2.java
+ * @compile/fail/ref=ProtectedMemberAccess2.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess2.java
*/
// 71 errors expected.
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess3.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess3.java Wed Jul 27 13:33:55 2016 +0000
@@ -4,7 +4,7 @@
* @summary Verify correct implementation of JLS2e 6.6.2.1
* @author maddox
*
- * @compile/fail/ref=ProtectedMemberAccess3.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess3.java
+ * @compile/fail/ref=ProtectedMemberAccess3.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess3.java
*/
// 46 errors expected.
--- a/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess4.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/protectedAccess/ProtectedMemberAccess4.java Wed Jul 27 13:33:55 2016 +0000
@@ -4,7 +4,7 @@
* @summary Verify correct implementation of JLS2e 6.6.2.1
* @author maddox
*
- * @compile/fail/ref=ProtectedMemberAccess4.out -XDdiags=-simpleNames -XDdiagsFormat=%b:%l:%_%m ProtectedMemberAccess4.java
+ * @compile/fail/ref=ProtectedMemberAccess4.out -diags:formatterOptions=-simpleNames;layout=%b:%l:%_%m ProtectedMemberAccess4.java
*/
// 33 errors expected.
--- a/langtools/test/tools/javac/unicode/UnicodeNewline.java Wed Jul 27 08:33:15 2016 -0400
+++ b/langtools/test/tools/javac/unicode/UnicodeNewline.java Wed Jul 27 13:33:55 2016 +0000
@@ -3,7 +3,7 @@
* @bug 4739428 4785453
* @summary when \u000a is used, diagnostics are reported on the wrong line.
*
- * @compile/fail/ref=UnicodeNewline.out -XDdiags=%b:%l:%_%m UnicodeNewline.java
+ * @compile/fail/ref=UnicodeNewline.out -diags:layout=%b:%l:%_%m UnicodeNewline.java
*/
class UnicodeNewline {
--- a/nashorn/.hgtags Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/.hgtags Wed Jul 27 13:33:55 2016 +0000
@@ -361,3 +361,4 @@
a32d419d73fe881a935b567c57dab9bfe3ed5f92 jdk-9+125
ee90c69a18409533df8f7b602044bf966a28381a jdk-9+126
ff07be6106fa56b72c163244f45a3ecb4c995564 jdk-9+127
+5a189c5b396c353786343b590f6c19a5d929f01d jdk-9+128
--- a/nashorn/make/build-nasgen.xml Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/make/build-nasgen.xml Wed Jul 27 13:33:55 2016 +0000
@@ -43,14 +43,14 @@
</java>
</target>
- <target name="run-nasgen-eclipse">
+ <target name="run-nasgen-eclipse" depends="load-properties">
<mkdir dir="${basedir}/build/eclipse/.nasgentmp"/>
<java classname="jdk.nashorn.internal.tools.nasgen.Main" fork="true" failonerror="true">
<classpath>
<pathelement location="${basedir}/buildtools/nasgen/dist/nasgen.jar"/>
</classpath>
- <jvmarg value="-Xbootclasspath/p:${basedir}/build/eclipse"/>
+ <jvmarg line="${nasgen.module.imports}"/>
<arg value="${basedir}/build/eclipse"/>
<arg value="jdk.nashorn.internal.objects"/>
<arg value="${basedir}/build/eclipse/.nasgentmp"/>
--- a/nashorn/make/build.xml Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/make/build.xml Wed Jul 27 13:33:55 2016 +0000
@@ -27,11 +27,14 @@
<import file="build-nasgen.xml"/>
<import file="code_coverage.xml"/>
- <target name="init-conditions">
+ <target name="load-properties">
<!-- loading locally defined resources and properties. NB they owerwrite default ones defined later -->
<property file="${user.home}/.nashorn.project.local.properties"/>
<loadproperties srcFile="make/project.properties"/>
+ </target>
+
+ <target name="init-conditions" depends="load-properties">
<path id="nashorn.jar.path">
<pathelement location="${nashorn.jar}"/>
</path>
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java Wed Jul 27 13:33:55 2016 +0000
@@ -108,15 +108,19 @@
* language's objects to Java interfaces and classes by generating adapters
* for them.
* <p>
- * The type of the invocation is {@code targetType(sourceType)}, while the
- * type of the guard is {@code boolean(sourceType)}. You are allowed to
+ * The type of the invocation is <tt>(sourceType)→targetType</tt>, while the
+ * type of the guard is <tt>(sourceType)→boolean</tt>. You are allowed to
* return unconditional invocations (with no guard) if the source type is
* specific to your runtime and your runtime only.
- * <p>Note that this method will never be invoked for type conversions
- * allowed by the JLS 5.3 "Method Invocation Conversion", see
- * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for
- * details. An implementation can assume it is never requested to produce a
- * converter for these conversions.
+ * <p>Note that this method will never be invoked for
+ * {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method
+ * invocation conversions} as those can be automatically applied by
+ * {@link java.lang.invoke.MethodHandle#asType(MethodType)}.
+ * An implementation can assume it is never requested to produce a
+ * converter for those conversions. If a language runtime needs to customize
+ * method invocation conversions, it should
+ * {@link jdk.dynalink.DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)
+ * set an autoconversion strategy in the dynamic linker factory} instead.
* <p>Dynalink is at liberty to either cache some of the returned converters
* or to repeatedly request the converter factory to create the same
* conversion.
@@ -127,6 +131,9 @@
* on whose behalf a type converter is requested. When a converter is
* requested as part of linking an {@code invokedynamic} instruction the
* supplier will return the lookup passed to the bootstrap method, otherwise
+ * if the method is invoked from within a
+ * {@link LinkerServices#getWithLookup(Supplier, jdk.dynalink.SecureLookupSupplier)}
+ * it will delegate to the secure lookup supplier. In any other case,
* it will return the public lookup. A typical case where the lookup might
* be needed is when the converter creates a Java adapter class on the fly
* (e.g. to convert some object from the dynamic language into a Java
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/package-info.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/package-info.java Wed Jul 27 13:33:55 2016 +0000
@@ -96,10 +96,8 @@
* language-specific manner if no other linker managed to handle the operation.)
* </p><p>
* A language runtime that wishes to make at least some of its linkers available
- * to other language runtimes for interoperability will need to declare the
- * class names of those linkers in
- * {@code /META-INF/services/jdk.dynalink.linker.GuardingDynamicLinker} file in
- * its distribution (typically, JAR file).
+ * to other language runtimes for interoperability will need to use a
+ * {@link jdk.dynalink.linker.GuardingDynamicLinkerExporter}.
* </p><p>
* Most language runtimes will be able to implement their own linking logic by
* implementing {@link jdk.dynalink.linker.TypeBasedGuardingDynamicLinker}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java Wed Jul 27 13:33:55 2016 +0000
@@ -138,7 +138,7 @@
* Determines whether one type can be converted to another type using a method invocation conversion, as per JLS 5.3
* "Method Invocation Conversion". This is basically all conversions allowed by subtyping (see
* {@link #isSubtype(Class, Class)}) as well as boxing conversion (JLS 5.1.7) optionally followed by widening
- * reference conversion and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
+ * reference conversion, and unboxing conversion (JLS 5.1.8) optionally followed by widening primitive conversion.
*
* @param sourceType the type being converted from (call site type for parameter types, method type for return types)
* @param targetType the parameter type being converted to (method type for parameter types, call site type for return types)
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java Wed Jul 27 13:33:55 2016 +0000
@@ -90,9 +90,10 @@
/**
* A relinkable call site that implements monomorphic inline caching strategy,
- * only being linked to a single {@link GuardedInvocation}. If that invocation
- * is invalidated, it will throw it away and ask its associated
- * {@link DynamicLinker} to relink it.
+ * only being linked to a single {@link GuardedInvocation} at any given time.
+ * If the guard of that single invocation fails, or it has an invalidated
+ * switch point, or its invalidating exception triggered, then the call site
+ * will throw it away and ask its associated {@link DynamicLinker} to relink it.
*/
public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite {
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 27 13:33:55 2016 +0000
@@ -1329,30 +1329,31 @@
return ScriptRuntime.UNDEFINED;
}
- final Object start = args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED;
- final Object deleteCount = args.length > 1 ? args[1] : ScriptRuntime.UNDEFINED;
-
- Object[] items;
-
- if (args.length > 2) {
- items = new Object[args.length - 2];
- System.arraycopy(args, 2, items, 0, items.length);
- } else {
- items = ScriptRuntime.EMPTY_ARRAY;
- }
-
- final ScriptObject sobj = (ScriptObject)obj;
- final long len = JSType.toUint32(sobj.getLength());
- final long relativeStart = JSType.toLong(start);
+ final ScriptObject sobj = (ScriptObject)obj;
+ final long len = JSType.toUint32(sobj.getLength());
+ final long relativeStart = JSType.toLong(args.length > 0 ? args[0] : ScriptRuntime.UNDEFINED);
final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
- final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart);
+ final long actualDeleteCount;
+ Object[] items = ScriptRuntime.EMPTY_ARRAY;
+
+ if (args.length == 0) {
+ actualDeleteCount = 0;
+ } else if (args.length == 1) {
+ actualDeleteCount = len - actualStart;
+ } else {
+ actualDeleteCount = Math.min(Math.max(JSType.toLong(args[1]), 0), len - actualStart);
+ if (args.length > 2) {
+ items = new Object[args.length - 2];
+ System.arraycopy(args, 2, items, 0, items.length);
+ }
+ }
NativeArray returnValue;
if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) {
try {
- returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
+ returnValue = new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
// Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements
int k = (int) actualStart;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Wed Jul 27 13:33:55 2016 +0000
@@ -127,7 +127,7 @@
// Fold an accessor getter into the method handle of a user accessor property.
private MethodHandle insertAccessorsGetter(final UserAccessorProperty uap, final LinkRequest request, final MethodHandle mh) {
MethodHandle superGetter = uap.getAccessorsGetter();
- if (isInherited()) {
+ if (!isSelf()) {
superGetter = ScriptObject.addProtoFilter(superGetter, getProtoChainLength());
}
if (request != null && !(request.getReceiver() instanceof ScriptObject)) {
@@ -183,11 +183,12 @@
}
/**
- * Check if the property found was inherited, i.e. not directly in the self
- * @return true if inherited property
+ * Check if the property found was inherited from a prototype and it is an ordinary
+ * property (one that has no accessor function).
+ * @return true if the found property is an inherited ordinary property
*/
- public boolean isInherited() {
- return self != prototype;
+ public boolean isInheritedOrdinaryProperty() {
+ return !isSelf() && !getProperty().isAccessorProperty();
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Wed Jul 27 13:33:55 2016 +0000
@@ -796,7 +796,7 @@
* @param start the object on which the lookup was originally initiated
* @return FindPropertyData or null if not found.
*/
- protected FindProperty findProperty(final Object key, final boolean deep, boolean isScope, final ScriptObject start) {
+ protected FindProperty findProperty(final Object key, final boolean deep, final boolean isScope, final ScriptObject start) {
final PropertyMap selfMap = getMap();
final Property property = selfMap.findProperty(key);
@@ -1108,7 +1108,7 @@
*
* @return value of property as a MethodHandle or null.
*/
- protected MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
+ protected static MethodHandle getCallMethodHandle(final FindProperty find, final MethodType type, final String bindName) {
return getCallMethodHandle(find.getObjectValue(), type, bindName);
}
@@ -1121,7 +1121,7 @@
*
* @return value of property as a MethodHandle or null.
*/
- protected static MethodHandle getCallMethodHandle(final Object value, final MethodType type, final String bindName) {
+ private static MethodHandle getCallMethodHandle(final Object value, final MethodType type, final String bindName) {
return value instanceof ScriptFunction ? ((ScriptFunction)value).getCallMethodHandle(type, bindName) : null;
}
@@ -2107,13 +2107,13 @@
* @param desc call site descriptor
* @return method handle for getter
*/
- protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
+ private static MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
if (!returnType.isPrimitive()) {
- return findOwnMH_V(getClass(), name, returnType, elementType);
+ return findOwnMH_V(name, returnType, elementType);
}
return MH.insertArguments(
- findOwnMH_V(getClass(), name, returnType, elementType, int.class),
+ findOwnMH_V(name, returnType, elementType, int.class),
2,
NashornCallSiteDescriptor.isOptimistic(desc) ?
NashornCallSiteDescriptor.getProgramPoint(desc) :
@@ -2184,7 +2184,7 @@
FindProperty find = findProperty(name, true, NashornCallSiteDescriptor.isScope(desc), this);
// If it's not a scope search, then we don't want any inherited properties except those with user defined accessors.
- if (find != null && find.isInherited() && !find.getProperty().isAccessorProperty()) {
+ if (find != null && find.isInheritedOrdinaryProperty()) {
// We should still check if inherited data property is not writable
if (isExtensible() && !find.getProperty().isWritable()) {
return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
@@ -2257,11 +2257,11 @@
}
}
- private GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
+ private static GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
Context.getContextTrusted().getLogger(ObjectClassGenerator.class).warning("Megamorphic setter: ", desc, " ", name);
final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
//never bother with ClassCastExceptionGuard for megamorphic callsites
- final GuardedInvocation inv = findSetIndexMethod(getClass(), desc, false, type);
+ final GuardedInvocation inv = findSetIndexMethod(desc, false, type);
return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
}
@@ -2284,25 +2284,24 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
- return findSetIndexMethod(getClass(), desc, explicitInstanceOfCheck(desc, request), desc.getMethodType());
+ return findSetIndexMethod(desc, explicitInstanceOfCheck(desc, request), desc.getMethodType());
}
/**
* Find the appropriate SETINDEX method for an invoke dynamic call.
*
- * @param clazz the receiver class
* @param desc the call site descriptor
* @param explicitInstanceOfCheck add an explicit instanceof check?
* @param callType the method type at the call site
*
* @return GuardedInvocation to be invoked at call site.
*/
- private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final MethodType callType) {
+ private static GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final MethodType callType) {
assert callType.parameterCount() == 3;
final Class<?> keyClass = callType.parameterType(1);
final Class<?> valueClass = callType.parameterType(2);
- MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, int.class);
+ MethodHandle methodHandle = findOwnMH_V("set", void.class, keyClass, valueClass, int.class);
methodHandle = MH.insertArguments(methodHandle, 3, NashornCallSiteDescriptor.getFlags(desc));
return new GuardedInvocation(methodHandle, getScriptObjectGuard(callType, explicitInstanceOfCheck), (SwitchPoint)null, explicitInstanceOfCheck ? null : ClassCastException.class);
@@ -2953,18 +2952,6 @@
return false;
}
- private boolean doesNotHaveCheckArrayKeys(final long longIndex, final long value, final int callSiteFlags) {
- if (getMap().containsArrayKeys()) {
- final String key = JSType.toString(longIndex);
- final FindProperty find = findProperty(key, true);
- if (find != null) {
- setObject(find, callSiteFlags, key, value);
- return true;
- }
- }
- return false;
- }
-
private boolean doesNotHaveCheckArrayKeys(final long longIndex, final double value, final int callSiteFlags) {
if (getMap().containsArrayKeys()) {
final String key = JSType.toString(longIndex);
@@ -3044,7 +3031,7 @@
invalidateGlobalConstant(key);
- if (f != null && f.isInherited() && !f.getProperty().isAccessorProperty()) {
+ if (f != null && f.isInheritedOrdinaryProperty()) {
final boolean isScope = isScopeFlag(callSiteFlags);
// If the start object of the find is not this object it means the property was found inside a
// 'with' statement expression (see WithObject.findProperty()). In this case we forward the 'set'
@@ -3467,15 +3454,10 @@
return this;
}
- private static MethodHandle findOwnMH_V(final Class<? extends ScriptObject> clazz, final String name, final Class<?> rtype, final Class<?>... types) {
- // TODO: figure out how can it work for NativeArray$Prototype etc.
+ private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findVirtual(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
}
- private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
- return findOwnMH_V(ScriptObject.class, name, rtype, types);
- }
-
private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), ScriptObject.class, name, MH.type(rtype, types));
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Jul 27 13:33:55 2016 +0000
@@ -170,7 +170,7 @@
assert property != null;
final MethodHandle boundHandle;
- if (!property.isAccessorProperty() && find.isInherited()) {
+ if (find.isInheritedOrdinaryProperty()) {
boundHandle = ScriptObject.addProtoFilter(methodHandle, find.getProtoChainLength());
} else {
boundHandle = methodHandle;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed Jul 27 08:33:15 2016 -0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Wed Jul 27 13:33:55 2016 +0000
@@ -117,7 +117,7 @@
return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
}
- if (find.isInherited() && !(find.getProperty().isAccessorProperty())) {
+ if (find.isInheritedOrdinaryProperty()) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8068972.js Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8068972: Array.splice should follow the ES6 specification
+ *
+ * @test
+ * @run
+ */
+
+
+function assertEqualArrays(a, b) {
+ Assert.assertTrue(Array.isArray(a));
+ Assert.assertTrue(Array.isArray(b));
+ Assert.assertTrue(a.length === b.length);
+ Assert.assertTrue(a.every(function(v, j) {
+ return v === b[j];
+ }));
+}
+
+var array = [1, 2, 3, 4, 5, 6, 7];
+
+var result = array.splice();
+assertEqualArrays(array, [1, 2, 3, 4, 5, 6, 7]);
+assertEqualArrays(result, []);
+
+result = array.splice(4);
+assertEqualArrays(array, [1, 2, 3, 4]);
+assertEqualArrays(result, [5, 6, 7]);
+
+result = array.splice(1, 2, -2, -3);
+assertEqualArrays(array, [1, -2, -3, 4]);
+assertEqualArrays(result, [2, 3]);
--- a/nashorn/test/script/currently-failing/logcoverage.js Wed Jul 27 08:33:15 2016 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * 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.
- */
-
-/**
- * mh_coverage.js
- * Screen scrape various logs to ensure that we cover enough functionality,
- * e.g. method handle instrumentation
- *
- * @test
- * @run
- */
-
-/*
- * creates new script engine initialized with given options and
- * runs given code on it. Returns standard output captured.
- */
-
-function runScriptEngine(opts, name) {
- var imports = new JavaImporter(
- Packages.jdk.nashorn.api.scripting,
- java.io, java.lang, java.util);
-
- with(imports) {
- var fac = new NashornScriptEngineFactory();
- // get current System.err
- var oldErr = System.err;
- var oldOut = System.out;
- var baosErr = new ByteArrayOutputStream();
- var newErr = new PrintStream(baosErr);
- var baosOut = new ByteArrayOutputStream();
- var newOut = new PrintStream(baosOut);
- try {
- // set new standard err
- System.setErr(newErr);
- System.setOut(newOut);
- var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]"));
- var reader = new java.io.FileReader(name);
- engine.eval(reader);
- newErr.flush();
- newOut.flush();
- return new java.lang.String(baosErr.toByteArray());
- } finally {
- // restore System.err to old value
- System.setErr(oldErr);
- System.setOut(oldOut);
- }
- }
-}
-
-var str;
-
-var methodsCalled = [
- 'asCollector',
- 'asType',
- 'bindTo',
- 'dropArguments',
- 'explicitCastArguments',
- 'filterArguments',
- 'filterReturnValue',
- 'findStatic',
- 'findVirtual',
- 'foldArguments',
- 'getter',
- 'guardWithTest',
- 'insertArguments',
- 'methodType',
- 'setter'
-];
-
-function check(str, strs) {
- for each (s in strs) {
- if (str.indexOf(s) !== -1) {
- continue;
- }
- print(s + " not found");
- return;
- }
- print("check ok!");
-}
-
-str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js");
-str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js");
-
-check(str, methodsCalled);
-check(str, ['return', 'get', 'set', '[fields]']);
-check(str, ['codegen']);
-
-print("hello, world!");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/logcoverage.js Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Screen scrape various logs to ensure that we cover enough functionality,
+ * e.g. method handle instrumentation
+ *
+ * @test
+ * @fork
+ * @option -Dnashorn.debug=true
+ */
+
+/*
+ * creates new script engine initialized with given options and
+ * runs given code on it. Returns standard output captured.
+ */
+
+function runScriptEngine(opts, name) {
+ var imports = new JavaImporter(
+ Packages.jdk.nashorn.api.scripting,
+ java.io, java.lang, java.util);
+
+ with (imports) {
+ var fac = new NashornScriptEngineFactory();
+ // get current System.err
+ var oldErr = System.err;
+ var oldOut = System.out;
+ var baosErr = new ByteArrayOutputStream();
+ var newErr = new PrintStream(baosErr);
+ var baosOut = new ByteArrayOutputStream();
+ var newOut = new PrintStream(baosOut);
+ try {
+ // set new standard err
+ System.setErr(newErr);
+ System.setOut(newOut);
+ var engine = fac.getScriptEngine(Java.to(opts, "java.lang.String[]"));
+ var reader = new java.io.FileReader(name);
+ engine.eval(reader);
+ newErr.flush();
+ newOut.flush();
+ return new java.lang.String(baosErr.toByteArray());
+ } finally {
+ // restore System.err to old value
+ System.setErr(oldErr);
+ System.setOut(oldOut);
+ }
+ }
+}
+
+var str;
+
+var methodsCalled = [
+ 'asCollector',
+ 'asType',
+ 'bindTo',
+ 'dropArguments',
+ 'explicitCastArguments',
+ 'filterArguments',
+ 'filterReturnValue',
+ 'findStatic',
+ 'findVirtual',
+ 'foldArguments',
+ 'getter',
+ 'guardWithTest',
+ 'insertArguments',
+ 'methodType',
+ 'setter'
+];
+
+function check(str, strs) {
+ for each (s in strs) {
+ if (str.indexOf(s) !== -1) {
+ continue;
+ }
+ print(s + " not found");
+ return;
+ }
+ print("check ok!");
+}
+
+str = runScriptEngine(["--log=codegen,compiler=finest,methodhandles=finest,fields=finest"], __DIR__ + "../basic/NASHORN-19.js");
+str += runScriptEngine(["--log=codegen,compiler=finest,methodhandles=finest,fields=finest"], __DIR__ + "../basic/varargs.js");
+
+check(str, methodsCalled);
+check(str, ['return', 'get', 'set', '[fields]']);
+check(str, ['codegen']);
+
+print("hello, world!");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/nosecurity/logcoverage.js.EXPECTED Wed Jul 27 13:33:55 2016 +0000
@@ -0,0 +1,4 @@
+check ok!
+check ok!
+check ok!
+hello, world!