Merge
This commit is contained in:
commit
eedb3870a2
@ -334,3 +334,4 @@ e8a66c0b05d786a282a7ff1d7eb4989afa30c891 jdk9-b86
|
||||
0d0a63b325592607974612f9cfb48590975aa2d6 jdk9-b89
|
||||
b433e4dfb830fea60e5187e4580791b62cc362d2 jdk9-b90
|
||||
97624df5026a2fb191793697dbd2c604c4d5c66e jdk9-b91
|
||||
6a5c99506f44538b879d8635a3979849ed587130 jdk9-b92
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,8 +45,16 @@ endif
|
||||
#
|
||||
# Import hotspot
|
||||
#
|
||||
|
||||
# Don't import jsig library for static builds
|
||||
ifneq ($(STATIC_BUILD), true)
|
||||
JSIG_IMPORT = jsig.*
|
||||
else
|
||||
JSIG_IMPORT =
|
||||
endif
|
||||
|
||||
HOTSPOT_BASE_IMPORT_FILES := \
|
||||
$(addprefix $(LIBRARY_PREFIX), jvm.* jsig.* jvm_db.* jvm_dtrace.*) \
|
||||
$(addprefix $(LIBRARY_PREFIX), jvm.* $(JSIG_IMPORT) jvm_db.* jvm_dtrace.*) \
|
||||
Xusage.txt \
|
||||
#
|
||||
|
||||
@ -79,32 +87,34 @@ SA_TARGETS := $(COPY_HOTSPOT_SA)
|
||||
|
||||
################################################################################
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
|
||||
$(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
|
||||
else
|
||||
JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
|
||||
$(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
|
||||
endif
|
||||
ifneq ($(STATIC_BUILD), true)
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
|
||||
$(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
|
||||
else
|
||||
JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
|
||||
$(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
|
||||
endif
|
||||
|
||||
ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(JVM_VARIANT_SERVER), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (, $(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
ifneq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(JVM_VARIANT_SERVER), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (, $(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifeq ($(JVM_VARIANT_CLIENT), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (, $(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
ifeq ($(JVM_VARIANT_CLIENT), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (, $(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
ifneq ($(OPENJDK_TARGET_OS), macosx)
|
||||
ifeq ($(JVM_VARIANT_MINIMAL1), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (,$(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
ifneq ($(OPENJDK_TARGET_OS), macosx)
|
||||
ifeq ($(JVM_VARIANT_MINIMAL1), true)
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
|
||||
ifneq (,$(JSIG_DEBUGINFO))
|
||||
BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -50,12 +50,12 @@ public class $NAME_CLZ$ extends Charset
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
initb2c();
|
||||
return new DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$);
|
||||
return new DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$, $ASCIICOMPATIBLE$);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
initc2b();
|
||||
return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex);
|
||||
return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex, $ASCIICOMPATIBLE$);
|
||||
}
|
||||
|
||||
$B2C$
|
||||
|
@ -48,11 +48,11 @@ public class $NAME_CLZ$ extends Charset implements HistoricallyNamedCharset
|
||||
}
|
||||
|
||||
public CharsetDecoder newDecoder() {
|
||||
return new SingleByte.Decoder(this, b2c);
|
||||
return new SingleByte.Decoder(this, b2c, $ASCIICOMPATIBLE$);
|
||||
}
|
||||
|
||||
public CharsetEncoder newEncoder() {
|
||||
return new SingleByte.Encoder(this, c2b, c2bIndex);
|
||||
return new SingleByte.Encoder(this, c2b, c2bIndex, $ASCIICOMPATIBLE$);
|
||||
}
|
||||
|
||||
private final static String b2cTable = $B2CTABLE$
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,15 +38,15 @@ include GensrcExceptions.gmk
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,LIST_RESOURCE_BUNDLE, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/java.base/share/classes/sun/launcher/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/classes/sun/launcher/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupCompileProperties,SUN_UTIL, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/resources)), \
|
||||
sun.util.resources.LocaleNamesBundle))
|
||||
$(eval $(call SetupCompileProperties, SUN_UTIL, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/resources, \
|
||||
CLASS := sun.util.resources.LocaleNamesBundle, \
|
||||
))
|
||||
|
||||
GENSRC_JAVA_BASE += $(LIST_RESOURCE_BUNDLE) $(SUN_UTIL)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -66,11 +66,11 @@ else
|
||||
PROP_SRC_DIRS += $(JDK_TOPDIR)/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources
|
||||
endif
|
||||
|
||||
PROP_SRC_FILES := $(filter-out %cursors.properties, \
|
||||
$(filter %.properties, $(call CacheFind, $(PROP_SRC_DIRS))))
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(PROP_SRC_FILES), ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(PROP_SRC_DIRS), \
|
||||
EXCLUDE := %cursors.properties, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
GENSRC_JAVA_DESKTOP += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,10 +29,10 @@ include GensrcCommon.gmk
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/java.logging/share/classes/sun/util/logging/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/java.logging/share/classes/sun/util/logging/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
TARGETS += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,10 +32,10 @@ $(eval $(call IncludeCustomExtension, jdk, gensrc/Gensrc-java.management.gmk))
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/java.management/share/classes/sun/management/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/java.management/share/classes/sun/management/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
TARGETS += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,11 +29,10 @@ include GensrcCommon.gmk
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, \
|
||||
$(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
TARGETS += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -29,11 +29,10 @@ include GensrcCommon.gmk
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, \
|
||||
$(JDK_TOPDIR)/src/jdk.jartool/share/classes/sun/tools/jar/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jartool/share/classes/sun/tools/jar/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
TARGETS += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@ HEADER_FILE := $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h
|
||||
JAVA_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java
|
||||
|
||||
# Both the header and java file are created using the same recipe. By declaring
|
||||
# this rule and adding header file to dependencies for java file, both are
|
||||
# this rule and adding header file to dependencies for java file, both are
|
||||
# rebuilt if either is missing
|
||||
$(HEADER_FILE): $(JDWP_SPEC_FILE) $(BUILD_TOOLS_JDK)
|
||||
|
||||
@ -90,10 +90,10 @@ endif
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/jdk.jdi/share/classes/com/sun/tools/jdi/resources)), \
|
||||
ListResourceBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jdi/share/classes/com/sun/tools/jdi/resources, \
|
||||
CLASS := ListResourceBundle, \
|
||||
))
|
||||
|
||||
GENSRC_JDK_JDI += $(COMPILE_PROPERTIES)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,10 +35,10 @@ include GensrcCLDR.gmk
|
||||
|
||||
include GensrcProperties.gmk
|
||||
|
||||
$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
|
||||
$(filter %.properties, \
|
||||
$(call CacheFind, $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources)), \
|
||||
sun.util.resources.LocaleNamesBundle))
|
||||
$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
|
||||
SRC_DIRS := $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources, \
|
||||
CLASS := sun.util.resources.LocaleNamesBundle, \
|
||||
))
|
||||
|
||||
# Skip generating zh_HK from zh_TW for this module.
|
||||
GENSRC_JDK_LOCALEDATA += $(filter-out %_zh_HK.java, $(COMPILE_PROPERTIES))
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -49,30 +49,40 @@ define SetupCopy-zh_HK
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
# Creates a rule that runs CompileProperties on a set of properties files.
|
||||
# Param 1 - Variable to add targets to, must not contain space
|
||||
# Param 2 - Properties files to process
|
||||
# Param 3 - The super class for the generated classes
|
||||
# Param 4 - Module path root, defaults to $(JDK_TOPDIR)/src
|
||||
define SetupCompileProperties
|
||||
$1_SRCS := $2
|
||||
$1_CLASS := $3
|
||||
$1_MODULE_PATH_ROOT := $4
|
||||
|
||||
# Setup make rules that runs CompileProperties on a set of properties files.
|
||||
#
|
||||
# Parameter 1 is the name of the rule. This name is used as variable prefix,
|
||||
# and the targets generated are listed in a variable by that name.
|
||||
#
|
||||
# Remaining parameters are named arguments. These include:
|
||||
# SRC_DIRS Directories containing properties files to process.
|
||||
# EXCLUDE Exclude files matching this pattern.
|
||||
# CLASS The super class for the generated classes.
|
||||
# MODULE_PATH_ROOT Module path root, defaults to $(JDK_TOPDIR)/src.
|
||||
SetupCompileProperties = $(NamedParamsMacroTemplate)
|
||||
define SetupCompilePropertiesBody
|
||||
# Set default value unless overridden
|
||||
ifeq ($$($1_MODULE_PATH_ROOT), )
|
||||
$1_MODULE_PATH_ROOT := $(JDK_TOPDIR)/src
|
||||
endif
|
||||
|
||||
# Locate all properties files in the given source dirs.
|
||||
$1_SRC_FILES := $$(filter %.properties, $$(call CacheFind, $$($1_SRC_DIRS)))
|
||||
|
||||
ifneq ($$($1_EXCLUDE), )
|
||||
$1_SRC_FILES := $$(filter-out $$($1_EXCLUDE), $$($1_SRC_FILES))
|
||||
endif
|
||||
|
||||
# Convert .../src/<module>/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties
|
||||
# to .../support/gensrc/<module>/com/sun/tools/javac/resources/javac_zh_CN.java
|
||||
# Strip away prefix and suffix, leaving for example only:
|
||||
# Strip away prefix and suffix, leaving for example only:
|
||||
# "<module>/share/classes/com/sun/tools/javac/resources/javac_zh_CN"
|
||||
$1_JAVAS := $$(patsubst $$($1_MODULE_PATH_ROOT)/%, \
|
||||
$(SUPPORT_OUTPUTDIR)/gensrc/%, \
|
||||
$$(patsubst %.properties, %.java, \
|
||||
$$(subst /$(OPENJDK_TARGET_OS)/classes,, \
|
||||
$$(subst /$(OPENJDK_TARGET_OS_TYPE)/classes,, \
|
||||
$$(subst /share/classes,, $$($1_SRCS))))))
|
||||
$$(subst /share/classes,, $$($1_SRC_FILES))))))
|
||||
|
||||
# Generate the package dirs for the to be generated java files. Sort to remove
|
||||
# duplicates.
|
||||
@ -82,22 +92,22 @@ define SetupCompileProperties
|
||||
# "-compile ...javac_zh_CN.properties ...javac_zh_CN.java java.util.ListResourceBundle"
|
||||
# suitable to be fed into the CompileProperties command.
|
||||
$1_CMDLINE := $$(subst _SPACE_, $(SPACE), \
|
||||
$$(join $$(addprefix -compile_SPACE_, $$($1_SRCS)), \
|
||||
$$(join $$(addprefix -compile_SPACE_, $$($1_SRC_FILES)), \
|
||||
$$(addsuffix _SPACE_$$($1_CLASS), \
|
||||
$$(addprefix _SPACE_, $$($1_JAVAS)))))
|
||||
|
||||
$1_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.done
|
||||
$1_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.marker
|
||||
$1_CMDLINE_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.cmdline
|
||||
|
||||
# Now setup the rule for the generation of the resource bundles.
|
||||
$$($1_TARGET): $$($1_SRCS) $$($1_JAVAS) $(BUILD_TOOLS_JDK)
|
||||
$$($1_TARGET): $$($1_SRC_FILES) $$($1_JAVAS) $(BUILD_TOOLS_JDK)
|
||||
$(MKDIR) -p $$(@D) $$($1_DIRS)
|
||||
$(ECHO) Compiling $$(words $$($1_SRCS)) properties into resource bundles for $(MODULE)
|
||||
$(ECHO) Compiling $$(words $$($1_SRC_FILES)) properties into resource bundles for $(MODULE)
|
||||
$$(eval $$(call ListPathsSafely, $1_CMDLINE, $$($1_CMDLINE_FILE)))
|
||||
$(TOOL_COMPILEPROPERTIES) -quiet @$$($1_CMDLINE_FILE)
|
||||
$(TOUCH) $$@
|
||||
|
||||
$$($1_JAVAS): $$($1_SRCS)
|
||||
$$($1_JAVAS): $$($1_SRC_FILES)
|
||||
|
||||
# Create zh_HK versions of all zh_TW files created above
|
||||
$$(eval $$(call SetupCopy-zh_HK,$1_HK,$$(filter %_zh_TW.java, $$($1_JAVAS))))
|
||||
|
@ -122,8 +122,23 @@ define SetupBuildLauncherBody
|
||||
endif
|
||||
|
||||
$1_CFLAGS += -DPACKAGE_PATH='"$(PACKAGE_PATH)"'
|
||||
$1_LDFLAGS += -Wl,-all_load $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a \
|
||||
$1_LDFLAGS += -Wl,-all_load \
|
||||
-sectcreate __TEXT __info_plist $(MACOSX_PLIST_DIR)/$$($1_PLIST_FILE)
|
||||
ifeq ($(STATIC_BUILD), true)
|
||||
$1_LDFLAGS += -exported_symbols_list \
|
||||
$(SUPPORT_OUTPUTDIR)/build-static/exported.symbols
|
||||
$1_LIBS += \
|
||||
$(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs/java.base -name "*.a") \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libdt_socket.a \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libjdwp.a \
|
||||
$(SUPPORT_OUTPUTDIR)/native/java.base/$(LIBRARY_PREFIX)fdlibm$(STATIC_LIBRARY_SUFFIX) \
|
||||
-framework CoreFoundation \
|
||||
-framework Foundation \
|
||||
-framework SystemConfiguration \
|
||||
-lstdc++ -liconv
|
||||
else
|
||||
$1_LIBS += $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a
|
||||
endif
|
||||
$1_LIBS += -framework Cocoa -framework Security \
|
||||
-framework ApplicationServices
|
||||
endif
|
||||
|
@ -435,10 +435,14 @@ else ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static, \
|
||||
DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a: $(BUILD_LIBJLI_STATIC)
|
||||
ifeq ($(STATIC_BUILD), true)
|
||||
TARGETS += $(BUILD_LIBJLI_STATIC)
|
||||
else
|
||||
$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a: $(BUILD_LIBJLI_STATIC)
|
||||
$(call install-file)
|
||||
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a
|
||||
endif
|
||||
|
||||
else ifeq ($(OPENJDK_TARGET_OS), aix)
|
||||
# AIX also requires a static libjli because the compiler doesn't support '-rpath'
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -33,3 +33,29 @@ include CoreLibraries.gmk
|
||||
include NetworkingLibraries.gmk
|
||||
include NioLibraries.gmk
|
||||
include SecurityLibraries.gmk
|
||||
|
||||
ifeq ($(STATIC_BUILD), true)
|
||||
JAVA_BASE_EXPORT_SYMBOLS_SRC := \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli/$(LIBRARY_PREFIX)jli.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)java.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)net.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)nio.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)verify.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)zip.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)jimage.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server/$(LIBRARY_PREFIX)jvm.symbols \
|
||||
#
|
||||
|
||||
JAVA_BASE_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/java.base.symbols
|
||||
|
||||
$(JAVA_BASE_EXPORT_SYMBOL_FILE): $(JAVA_BASE_EXPORT_SYMBOLS_SRC)
|
||||
$(ECHO) $(LOG_INFO) "Generating java.base.symbols file"
|
||||
$(CAT) $^ > $@
|
||||
|
||||
# The individual symbol files is generated when the respective lib is built
|
||||
$(JAVA_BASE_EXPORT_SYMBOLS_SRC): $(BUILD_LIBJLI) $(BUILD_LIBJAVA) \
|
||||
$(BUILD_LIBNET) $(BUILD_LIBNIO) $(BUILD_LIBVERIFY) $(BUILD_LIBZIP) \
|
||||
$(BUILD_LIBJIMAGE)
|
||||
|
||||
TARGETS += $(JAVA_BASE_EXPORT_SYMBOL_FILE)
|
||||
endif
|
||||
|
@ -102,3 +102,23 @@ $(BUILD_LIBJDWP): $(call FindLib, java.base, java)
|
||||
TARGETS += $(BUILD_LIBJDWP)
|
||||
|
||||
################################################################################
|
||||
|
||||
ifeq ($(STATIC_BUILD), true)
|
||||
JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC := \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/$(LIBRARY_PREFIX)dt_socket.symbols \
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/$(LIBRARY_PREFIX)jdwp.symbols
|
||||
|
||||
JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/jdk.jdwp.agent.symbols
|
||||
|
||||
$(JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE): $(JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC)
|
||||
$(ECHO) $(LOG_INFO) "Generating jdk.jdwp.agent symbols file"
|
||||
$(CAT) $^ > $@
|
||||
|
||||
# The individual symbol files is generated when the respective lib is built
|
||||
$(JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC): $(BUILD_LIBDT_SOCKET) $(BUILD_LIBJDWP)
|
||||
|
||||
TARGETS += $(JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE)
|
||||
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
|
@ -26,38 +26,41 @@
|
||||
include LibCommon.gmk
|
||||
|
||||
ifeq ($(OPENJDK_TARGET_OS), macosx)
|
||||
# JavaNativeFoundation framework not supported in static builds
|
||||
ifneq ($(STATIC_BUILD), true)
|
||||
|
||||
################################################################################
|
||||
|
||||
LIBOSXSECURITY_DIRS := $(JDK_TOPDIR)/src/java.base/macosx/native/libosxsecurity
|
||||
LIBOSXSECURITY_CFLAGS := -I$(LIBOSXSECURITY_DIRS) \
|
||||
$(LIBJAVA_HEADER_FLAGS) \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/java.base \
|
||||
LIBOSXSECURITY_DIRS := $(JDK_TOPDIR)/src/java.base/macosx/native/libosxsecurity
|
||||
LIBOSXSECURITY_CFLAGS := -I$(LIBOSXSECURITY_DIRS) \
|
||||
$(LIBJAVA_HEADER_FLAGS) \
|
||||
-I$(SUPPORT_OUTPUTDIR)/headers/java.base \
|
||||
|
||||
$(eval $(call SetupNativeCompilation,BUILD_LIBOSXSECURITY, \
|
||||
LIBRARY := osxsecurity, \
|
||||
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
||||
SRC := $(LIBOSXSECURITY_DIRS), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(LIBOSXSECURITY_CFLAGS), \
|
||||
DISABLED_WARNINGS_clang := deprecated-declarations, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
-L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN) \
|
||||
-fobjc-link-runtime, \
|
||||
LIBS := \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework CoreServices \
|
||||
-framework Security \
|
||||
$(JDKLIB_LIBS), \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxsecurity, \
|
||||
DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
|
||||
$(eval $(call SetupNativeCompilation,BUILD_LIBOSXSECURITY, \
|
||||
LIBRARY := osxsecurity, \
|
||||
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
||||
SRC := $(LIBOSXSECURITY_DIRS), \
|
||||
OPTIMIZATION := LOW, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) \
|
||||
$(LIBOSXSECURITY_CFLAGS), \
|
||||
DISABLED_WARNINGS_clang := deprecated-declarations, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
-L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN) \
|
||||
-fobjc-link-runtime, \
|
||||
LIBS := \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework CoreServices \
|
||||
-framework Security \
|
||||
$(JDKLIB_LIBS), \
|
||||
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxsecurity, \
|
||||
DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
|
||||
|
||||
$(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA)
|
||||
$(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA)
|
||||
|
||||
TARGETS += $(BUILD_LIBOSXSECURITY)
|
||||
TARGETS += $(BUILD_LIBOSXSECURITY)
|
||||
|
||||
################################################################################
|
||||
|
||||
endif
|
||||
endif
|
||||
|
@ -211,6 +211,7 @@ SUNWprivate_1.1 {
|
||||
Java_java_lang_SecurityManager_getClassContext;
|
||||
Java_java_lang_Shutdown_halt0;
|
||||
Java_java_lang_String_intern;
|
||||
Java_java_lang_StringUTF16_isBigEndian;
|
||||
Java_java_lang_System_identityHashCode;
|
||||
Java_java_lang_System_initProperties;
|
||||
Java_java_lang_System_mapLibraryName;
|
||||
|
@ -57,6 +57,7 @@ text: .text%Java_java_io_UnixFileSystem_list;
|
||||
text: .text%JNU_ClassString;
|
||||
text: .text%JNU_CopyObjectArray;
|
||||
text: .text%Java_java_lang_String_intern;
|
||||
text: .text%Java_java_lang_StringUTF16_isBigEndian;
|
||||
text: .text%Java_java_lang_ClassLoader_findLoadedClass0;
|
||||
text: .text%Java_java_lang_ClassLoader_findBootstrapClass;
|
||||
text: .text%Java_java_lang_Throwable_fillInStackTrace;
|
||||
|
@ -29,6 +29,7 @@ text: .text%Java_sun_reflect_Reflection_getCallerClass__;
|
||||
text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
|
||||
text: .text%Java_java_lang_Class_forName0;
|
||||
text: .text%Java_java_lang_String_intern;
|
||||
text: .text%Java_java_lang_StringUTF16_isBigEndian;
|
||||
text: .text%Java_java_lang_Float_floatToRawIntBits;
|
||||
text: .text%Java_java_lang_Double_doubleToRawLongBits;
|
||||
text: .text%Java_java_lang_ClassLoader_findLoadedClass0;
|
||||
|
@ -31,6 +31,7 @@ text: .text%Java_sun_reflect_Reflection_getCallerClass__;
|
||||
text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
|
||||
text: .text%Java_java_lang_Class_forName0;
|
||||
text: .text%Java_java_lang_String_intern;
|
||||
text: .text%Java_java_lang_StringUTF16_isBigEndian;
|
||||
text: .text%Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0;
|
||||
text: .text%Java_java_lang_Throwable_fillInStackTrace;
|
||||
text: .text%Java_java_lang_System_setOut0;
|
||||
|
@ -75,6 +75,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_nio_ch_IOUtil_makePipe;
|
||||
Java_sun_nio_ch_IOUtil_randomBytes;
|
||||
Java_sun_nio_ch_IOUtil_setfdVal;
|
||||
Java_sun_nio_ch_IOUtil_iovMax;
|
||||
Java_sun_nio_ch_KQueue_kqueue;
|
||||
Java_sun_nio_ch_KQueue_keventRegister;
|
||||
Java_sun_nio_ch_KQueue_keventPoll;
|
||||
|
@ -197,6 +197,7 @@ public class DBCS {
|
||||
.replace("$B1MAX$" , "0x" + Integer.toString(b1Max, 16))
|
||||
.replace("$B2MIN$" , "0x" + Integer.toString(b2Min, 16))
|
||||
.replace("$B2MAX$" , "0x" + Integer.toString(b2Max, 16))
|
||||
.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false")
|
||||
.replace("$B2C$", b2c)
|
||||
.replace("$C2BLENGTH$", "0x" + Integer.toString(c2bOff, 16))
|
||||
.replace("$NONROUNDTRIP_B2C$", b2cNR)
|
||||
|
@ -175,6 +175,9 @@ public class SBCS {
|
||||
else
|
||||
line = " return (cs instanceof " + clzName + ");";
|
||||
}
|
||||
if (line.indexOf("$ASCIICOMPATIBLE$") != -1) {
|
||||
line = line.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false");
|
||||
}
|
||||
if (line.indexOf("$B2CTABLE$") != -1) {
|
||||
line = line.replace("$B2CTABLE$", b2c);
|
||||
}
|
||||
|
@ -841,7 +841,7 @@ public class WrapperGenerator {
|
||||
pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" );
|
||||
|
||||
pw.println("package "+package_name+";\n");
|
||||
pw.println("import sun.misc.*;\n");
|
||||
pw.println("import jdk.internal.misc.Unsafe;\n");
|
||||
pw.println("import sun.util.logging.PlatformLogger;");
|
||||
String baseClass = stp.getBaseClass();
|
||||
if (baseClass == null) {
|
||||
@ -941,7 +941,7 @@ public class WrapperGenerator {
|
||||
pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" );
|
||||
|
||||
pw.println("package "+package_name+";\n");
|
||||
pw.println("import sun.misc.Unsafe;\n");
|
||||
pw.println("import jdk.internal.misc.Unsafe;\n");
|
||||
pw.println("class " + ft.getName() + " {");
|
||||
pw.println("\tprivate static Unsafe unsafe = XlibWrapper.unsafe;");
|
||||
pw.println("\tprivate boolean __executed = false;");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -65,6 +65,51 @@ void deallocate(jvmtiEnv *jvmti, void *ptr);
|
||||
void *allocate(jvmtiEnv *jvmti, jint len);
|
||||
void add_demo_jar_to_bootclasspath(jvmtiEnv *jvmti, char *demo_name);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
/* Macros for handling declaration of static/dynamic
|
||||
* Agent library Load/Attach/Unload functions
|
||||
*
|
||||
* DEF_Agent_OnLoad, DEF_Agent_OnAttach or DEF_Agent_OnUnload
|
||||
* generate the appropriate entrypoint names based on static
|
||||
* versus dynamic builds.
|
||||
*
|
||||
* STATIC_BUILD must be defined to build static versions of these libraries.
|
||||
* LIBRARY_NAME must be set to the name of the library for static builds.
|
||||
*/
|
||||
#define ADD_LIB_NAME3(name, lib) name ## lib
|
||||
#define ADD_LIB_NAME2(name, lib) ADD_LIB_NAME3(name, lib)
|
||||
#define ADD_LIB_NAME(entry) ADD_LIB_NAME2(entry, LIBRARY_NAME)
|
||||
|
||||
#define DEF_Agent_OnLoad \
|
||||
ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) \
|
||||
{ \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)(JavaVM *vm, char *options, void *reserved); \
|
||||
return ADD_LIB_NAME(Agent_OnLoad_dynamic_)(vm, options, reserved); \
|
||||
} \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)
|
||||
|
||||
#define DEF_Agent_OnAttach \
|
||||
ADD_LIB_NAME(Agent_OnAttach_)(JavaVM *vm, char *options, void *reserved) \
|
||||
{ \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)(JavaVM *vm, char *options, void *reserved); \
|
||||
return ADD_LIB_NAME(Agent_OnAttach_dynamic_)(vm, options, reserved); \
|
||||
} \
|
||||
jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)
|
||||
|
||||
#define DEF_Agent_OnUnload \
|
||||
ADD_LIB_NAME(Agent_OnUnload_)(JavaVM *vm) \
|
||||
{ \
|
||||
void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)(JavaVM *vm); \
|
||||
ADD_LIB_NAME(Agent_OnUnload_dynamic_)(vm); \
|
||||
} \
|
||||
void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)
|
||||
|
||||
#else
|
||||
#define DEF_Agent_OnLoad Agent_OnLoad
|
||||
#define DEF_Agent_OnAttach Agent_OnAttach
|
||||
#define DEF_Agent_OnUnload Agent_OnUnload
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -225,7 +225,7 @@ compiled_method_load(jvmtiEnv *jvmti, jmethodID method, jint code_size,
|
||||
* event here.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
@ -272,6 +272,6 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -148,7 +148,7 @@ gc_finish(jvmtiEnv* jvmti_env)
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
@ -193,6 +193,6 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -894,7 +894,7 @@ parse_agent_options(char *options)
|
||||
* loaded. This is the first code executed.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
static GlobalAgentData data;
|
||||
jvmtiEnv *jvmti;
|
||||
@ -1010,7 +1010,7 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
* unloaded. This is the last code executed.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
/* Skip any cleanup, VM is about to die anyway */
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -64,9 +64,4 @@
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Agent library externals to export. */
|
||||
|
||||
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
|
||||
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -235,7 +235,7 @@ vmDeath(jvmtiEnv *jvmti, JNIEnv *env)
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
@ -283,6 +283,6 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -373,7 +373,7 @@ parse_agent_options(char *options)
|
||||
* loaded. This is the first code executed.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
static GlobalAgentData data;
|
||||
jvmtiEnv *jvmti;
|
||||
@ -467,7 +467,7 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
* unloaded. This is the last code executed.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
/* Make sure all malloc/calloc/strdup space is freed */
|
||||
if ( gdata->include != NULL ) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -64,9 +64,4 @@
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Agent library externals to export. */
|
||||
|
||||
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
|
||||
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -697,7 +697,7 @@ parse_agent_options(char *options)
|
||||
* loaded. This is the first code executed.
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
static GlobalAgentData data;
|
||||
jvmtiEnv *jvmti;
|
||||
@ -795,7 +795,7 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
* unloaded. This is the last code executed.
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
/* Make sure all malloc/calloc/strdup space is freed */
|
||||
if ( gdata->include != NULL ) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -64,9 +64,4 @@
|
||||
|
||||
#include "agent_util.h"
|
||||
|
||||
/* Agent library externals to export. */
|
||||
|
||||
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
|
||||
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -89,7 +89,7 @@ vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jint rc;
|
||||
jvmtiError err;
|
||||
@ -116,6 +116,6 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -37,6 +37,10 @@
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define Monitor WaiterMonitor
|
||||
#endif
|
||||
|
||||
|
||||
/* C++ Monitor class */
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -37,6 +37,9 @@
|
||||
* this sample code.
|
||||
*/
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
#define Thread WaiterThread
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -243,7 +243,7 @@ extern "C" {
|
||||
|
||||
/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
|
||||
{
|
||||
jvmtiEnv *jvmti;
|
||||
jint rc;
|
||||
@ -288,7 +288,7 @@ extern "C" {
|
||||
|
||||
/* Agent_OnUnload() is called last */
|
||||
JNIEXPORT void JNICALL
|
||||
Agent_OnUnload(JavaVM *vm)
|
||||
DEF_Agent_OnUnload(JavaVM *vm)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* AsynchronousChannelGroup implementation based on the AIX pollset framework.
|
||||
|
@ -26,7 +26,7 @@
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides access to the Linux epoll facility.
|
||||
|
@ -29,7 +29,7 @@ import java.nio.file.attribute.*;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.io.IOException;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
@ -29,7 +29,7 @@ import java.nio.file.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
import static sun.nio.fs.LinuxNativeDispatcher.*;
|
||||
|
@ -30,7 +30,7 @@ import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import static sun.nio.fs.UnixNativeDispatcher.*;
|
||||
import static sun.nio.fs.UnixConstants.*;
|
||||
|
@ -26,7 +26,7 @@
|
||||
package sun.nio.ch;
|
||||
|
||||
import java.io.IOException;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Provides access to the BSD kqueue facility.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,13 +35,15 @@
|
||||
|
||||
#include "java_props_macosx.h"
|
||||
|
||||
|
||||
// need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded
|
||||
static void *getJRSFramework() {
|
||||
static void *jrsFwk = NULL;
|
||||
#ifndef STATIC_BUILD
|
||||
// JavaRuntimeSupport doesn't support static Java runtimes
|
||||
if (jrsFwk == NULL) {
|
||||
jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
|
||||
}
|
||||
#endif
|
||||
return jrsFwk;
|
||||
}
|
||||
|
||||
|
@ -245,6 +245,8 @@ static InvocationFunctions *GetExportedJNIFunctions() {
|
||||
return sExportedJNIFunctions = fxns;
|
||||
}
|
||||
|
||||
#ifndef STATIC_BUILD
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_GetDefaultJavaVMInitArgs(void *args) {
|
||||
InvocationFunctions *ifn = GetExportedJNIFunctions();
|
||||
@ -265,6 +267,7 @@ JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs) {
|
||||
if (ifn == NULL) return JNI_ERR;
|
||||
return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow JLI-aware launchers to specify a client/server preference
|
||||
@ -303,7 +306,12 @@ static void *apple_main (void *arg)
|
||||
objc_registerThreadWithCollector();
|
||||
|
||||
if (main_fptr == NULL) {
|
||||
#ifdef STATIC_BUILD
|
||||
extern int main(int argc, char **argv);
|
||||
main_fptr = &main;
|
||||
#else
|
||||
main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
|
||||
#endif
|
||||
if (main_fptr == NULL) {
|
||||
JLI_ReportErrorMessageSys("error locating main entrypoint\n");
|
||||
exit(1);
|
||||
@ -588,6 +596,9 @@ GetJVMPath(const char *jrepath, const char *jvmtype,
|
||||
|
||||
JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
return JNI_TRUE;
|
||||
#else
|
||||
if (stat(jvmpath, &s) == 0) {
|
||||
JLI_TraceLauncher("yes.\n");
|
||||
return JNI_TRUE;
|
||||
@ -595,6 +606,7 @@ GetJVMPath(const char *jrepath, const char *jvmtype,
|
||||
JLI_TraceLauncher("no.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -607,10 +619,18 @@ GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
|
||||
|
||||
if (GetApplicationHome(path, pathsize)) {
|
||||
/* Is JRE co-located with the application? */
|
||||
#ifdef STATIC_BUILD
|
||||
char jvm_cfg[MAXPATHLEN];
|
||||
JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
|
||||
if (access(jvm_cfg, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#else
|
||||
JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
|
||||
if (access(libjava, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif
|
||||
/* ensure storage for path + /jre + NULL */
|
||||
if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
|
||||
JLI_TraceLauncher("Insufficient space to store JRE path\n");
|
||||
@ -629,6 +649,24 @@ GetJREPath(char *path, jint pathsize, const char * arch, jboolean speculative)
|
||||
Dl_info selfInfo;
|
||||
dladdr(&GetJREPath, &selfInfo);
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
char jvm_cfg[MAXPATHLEN];
|
||||
char *p = NULL;
|
||||
strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
|
||||
p = strrchr(jvm_cfg, '/'); *p = '\0';
|
||||
p = strrchr(jvm_cfg, '/');
|
||||
if (strcmp(p, "/.") == 0) {
|
||||
*p = '\0';
|
||||
p = strrchr(jvm_cfg, '/'); *p = '\0';
|
||||
}
|
||||
else *p = '\0';
|
||||
strncpy(path, jvm_cfg, pathsize);
|
||||
strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
|
||||
if (access(jvm_cfg, F_OK) == 0) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *realPathToSelf = realpath(selfInfo.dli_fname, path);
|
||||
if (realPathToSelf != path) {
|
||||
return JNI_FALSE;
|
||||
@ -664,7 +702,11 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn)
|
||||
|
||||
JLI_TraceLauncher("JVM path is %s\n", jvmpath);
|
||||
|
||||
#ifndef STATIC_BUILD
|
||||
libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
|
||||
#else
|
||||
libjvm = dlopen(NULL, RTLD_FIRST);
|
||||
#endif
|
||||
if (libjvm == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
|
||||
JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
|
||||
@ -714,9 +756,14 @@ SetExecname(char **argv)
|
||||
char* exec_path = NULL;
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
int (*fptr)();
|
||||
|
||||
#ifdef STATIC_BUILD
|
||||
void *fptr;
|
||||
fptr = (void *)&SetExecname;
|
||||
#else
|
||||
int (*fptr)();
|
||||
fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
|
||||
#endif
|
||||
if (fptr == NULL) {
|
||||
JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
|
||||
return JNI_FALSE;
|
||||
|
@ -2184,10 +2184,10 @@ public class File
|
||||
|
||||
private static final long PATH_OFFSET;
|
||||
private static final long PREFIX_LENGTH_OFFSET;
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
static {
|
||||
try {
|
||||
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
PATH_OFFSET = unsafe.objectFieldOffset(
|
||||
File.class.getDeclaredField("path"));
|
||||
PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset(
|
||||
|
@ -40,7 +40,7 @@ import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import static java.io.ObjectStreamClass.processQueue;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.ReflectionFactory;
|
||||
|
@ -31,6 +31,12 @@ import java.util.Spliterator;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static java.lang.String.COMPACT_STRINGS;
|
||||
import static java.lang.String.UTF16;
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.checkIndex;
|
||||
import static java.lang.String.checkOffset;
|
||||
|
||||
/**
|
||||
* A mutable sequence of characters.
|
||||
* <p>
|
||||
@ -51,7 +57,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
/**
|
||||
* The value is used for character storage.
|
||||
*/
|
||||
char[] value;
|
||||
byte[] value;
|
||||
|
||||
/**
|
||||
* The id of the encoding used to encode the bytes in {@code value}.
|
||||
*/
|
||||
byte coder;
|
||||
|
||||
/**
|
||||
* The count is the number of characters used.
|
||||
@ -68,7 +79,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* Creates an AbstractStringBuilder of the specified capacity.
|
||||
*/
|
||||
AbstractStringBuilder(int capacity) {
|
||||
value = new char[capacity];
|
||||
if (COMPACT_STRINGS) {
|
||||
value = new byte[capacity];
|
||||
coder = LATIN1;
|
||||
} else {
|
||||
value = StringUTF16.newBytesFor(capacity);
|
||||
coder = UTF16;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +107,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @return the current capacity
|
||||
*/
|
||||
public int capacity() {
|
||||
return value.length;
|
||||
return value.length >> coder;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,8 +127,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @param minimumCapacity the minimum desired capacity.
|
||||
*/
|
||||
public void ensureCapacity(int minimumCapacity) {
|
||||
if (minimumCapacity > 0)
|
||||
if (minimumCapacity > 0) {
|
||||
ensureCapacityInternal(minimumCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -120,24 +138,48 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
private void ensureCapacityInternal(int minimumCapacity) {
|
||||
// overflow-conscious code
|
||||
if (minimumCapacity - value.length > 0)
|
||||
int capacity = value.length >> coder;
|
||||
if (minimumCapacity - capacity > 0) {
|
||||
expandCapacity(minimumCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implements the expansion semantics of ensureCapacity with no
|
||||
* size check or synchronization.
|
||||
*/
|
||||
void expandCapacity(int minimumCapacity) {
|
||||
int newCapacity = value.length * 2 + 2;
|
||||
if (newCapacity - minimumCapacity < 0)
|
||||
private void expandCapacity(int minimumCapacity) {
|
||||
int newCapacity = (value.length >> coder) * 2 + 2;
|
||||
if (newCapacity - minimumCapacity < 0) {
|
||||
newCapacity = minimumCapacity;
|
||||
}
|
||||
if (newCapacity < 0) {
|
||||
if (minimumCapacity < 0) // overflow
|
||||
if (minimumCapacity < 0) {// overflow
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
newCapacity = Integer.MAX_VALUE;
|
||||
}
|
||||
value = Arrays.copyOf(value, newCapacity);
|
||||
if (coder != LATIN1 && newCapacity > StringUTF16.MAX_LENGTH) {
|
||||
if (minimumCapacity >= StringUTF16.MAX_LENGTH) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
newCapacity = StringUTF16.MAX_LENGTH;
|
||||
}
|
||||
this.value = Arrays.copyOf(value, newCapacity << coder);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the coder is "isLatin1", this inflates the internal 8-bit storage
|
||||
* to 16-bit <hi=0, low> pair storage.
|
||||
*/
|
||||
private void inflate() {
|
||||
if (!isLatin1()) {
|
||||
return;
|
||||
}
|
||||
byte[] buf = StringUTF16.newBytesFor(value.length);
|
||||
StringLatin1.inflateSB(value, buf, 0, count);
|
||||
this.value = buf;
|
||||
this.coder = UTF16;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,8 +190,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* returned by a subsequent call to the {@link #capacity()} method.
|
||||
*/
|
||||
public void trimToSize() {
|
||||
if (count < value.length) {
|
||||
value = Arrays.copyOf(value, count);
|
||||
int length = count << coder;
|
||||
if (length < value.length) {
|
||||
value = Arrays.copyOf(value, length);
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,14 +222,17 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* {@code newLength} argument is negative.
|
||||
*/
|
||||
public void setLength(int newLength) {
|
||||
if (newLength < 0)
|
||||
if (newLength < 0) {
|
||||
throw new StringIndexOutOfBoundsException(newLength);
|
||||
ensureCapacityInternal(newLength);
|
||||
|
||||
if (count < newLength) {
|
||||
Arrays.fill(value, count, newLength, '\0');
|
||||
}
|
||||
|
||||
ensureCapacityInternal(newLength);
|
||||
if (count < newLength) {
|
||||
if (isLatin1()) {
|
||||
StringLatin1.fillNull(value, count, newLength);
|
||||
} else {
|
||||
StringUTF16.fillNull(value, count, newLength);
|
||||
}
|
||||
}
|
||||
count = newLength;
|
||||
}
|
||||
|
||||
@ -209,9 +255,11 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
return value[index];
|
||||
checkIndex(index, count);
|
||||
if (isLatin1()) {
|
||||
return (char)(value[index] & 0xff);
|
||||
}
|
||||
return StringUTF16.charAt(value, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,10 +284,11 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* sequence.
|
||||
*/
|
||||
public int codePointAt(int index) {
|
||||
if ((index < 0) || (index >= count)) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
checkIndex(index, count);
|
||||
if (isLatin1()) {
|
||||
return value[index] & 0xff;
|
||||
}
|
||||
return Character.codePointAtImpl(value, index, count);
|
||||
return StringUTF16.codePointAtSB(value, index, count);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,10 +314,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
public int codePointBefore(int index) {
|
||||
int i = index - 1;
|
||||
if ((i < 0) || (i >= count)) {
|
||||
if (i < 0 || i >= count) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return Character.codePointBeforeImpl(value, index, 0);
|
||||
if (isLatin1()) {
|
||||
return value[i] & 0xff;
|
||||
}
|
||||
return StringUTF16.codePointBeforeSB(value, index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,7 +347,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
|
||||
if (isLatin1()) {
|
||||
return endIndex - beginIndex;
|
||||
}
|
||||
return StringUTF16.codePointCountSB(value, beginIndex, endIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,8 +376,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
if (index < 0 || index > count) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
return Character.offsetByCodePointsImpl(value, 0, count,
|
||||
index, codePointOffset);
|
||||
return Character.offsetByCodePoints(this,
|
||||
index, codePointOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,13 +410,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
|
||||
{
|
||||
if (srcBegin < 0)
|
||||
throw new StringIndexOutOfBoundsException(srcBegin);
|
||||
if ((srcEnd < 0) || (srcEnd > count))
|
||||
throw new StringIndexOutOfBoundsException(srcEnd);
|
||||
if (srcBegin > srcEnd)
|
||||
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
|
||||
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
checkRangeSIOOBE(srcBegin, srcEnd, count); // compatible to old version
|
||||
int n = srcEnd - srcBegin;
|
||||
checkRange(dstBegin, dstBegin + n, dst.length);
|
||||
if (isLatin1()) {
|
||||
StringLatin1.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
|
||||
} else {
|
||||
StringUTF16.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -379,9 +435,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* negative or greater than or equal to {@code length()}.
|
||||
*/
|
||||
public void setCharAt(int index, char ch) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
value[index] = ch;
|
||||
checkIndex(index, count);
|
||||
if (isLatin1() && StringLatin1.canEncode(ch)) {
|
||||
value[index] = (byte)ch;
|
||||
} else {
|
||||
if (isLatin1()) {
|
||||
inflate();
|
||||
}
|
||||
StringUTF16.putCharSB(value, index, ch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -418,35 +480,34 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @return a reference to this object.
|
||||
*/
|
||||
public AbstractStringBuilder append(String str) {
|
||||
if (str == null)
|
||||
if (str == null) {
|
||||
return appendNull();
|
||||
}
|
||||
int len = str.length();
|
||||
ensureCapacityInternal(count + len);
|
||||
str.getChars(0, len, value, count);
|
||||
putStringAt(count, str);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Documentation in subclasses because of synchro difference
|
||||
public AbstractStringBuilder append(StringBuffer sb) {
|
||||
if (sb == null)
|
||||
return appendNull();
|
||||
int len = sb.length();
|
||||
ensureCapacityInternal(count + len);
|
||||
sb.getChars(0, len, value, count);
|
||||
count += len;
|
||||
return this;
|
||||
return this.append((AbstractStringBuilder)sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.8
|
||||
*/
|
||||
AbstractStringBuilder append(AbstractStringBuilder asb) {
|
||||
if (asb == null)
|
||||
if (asb == null) {
|
||||
return appendNull();
|
||||
}
|
||||
int len = asb.length();
|
||||
ensureCapacityInternal(count + len);
|
||||
asb.getChars(0, len, value, count);
|
||||
if (getCoder() != asb.getCoder()) {
|
||||
inflate();
|
||||
}
|
||||
asb.getBytes(value, count, coder);
|
||||
count += len;
|
||||
return this;
|
||||
}
|
||||
@ -454,25 +515,35 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
// Documentation in subclasses because of synchro difference
|
||||
@Override
|
||||
public AbstractStringBuilder append(CharSequence s) {
|
||||
if (s == null)
|
||||
if (s == null) {
|
||||
return appendNull();
|
||||
if (s instanceof String)
|
||||
}
|
||||
if (s instanceof String) {
|
||||
return this.append((String)s);
|
||||
if (s instanceof AbstractStringBuilder)
|
||||
}
|
||||
if (s instanceof AbstractStringBuilder) {
|
||||
return this.append((AbstractStringBuilder)s);
|
||||
|
||||
}
|
||||
return this.append(s, 0, s.length());
|
||||
}
|
||||
|
||||
private AbstractStringBuilder appendNull() {
|
||||
int c = count;
|
||||
ensureCapacityInternal(c + 4);
|
||||
final char[] value = this.value;
|
||||
value[c++] = 'n';
|
||||
value[c++] = 'u';
|
||||
value[c++] = 'l';
|
||||
value[c++] = 'l';
|
||||
count = c;
|
||||
ensureCapacityInternal(count + 4);
|
||||
int count = this.count;
|
||||
byte[] val = this.value;
|
||||
if (isLatin1()) {
|
||||
val[count++] = 'n';
|
||||
val[count++] = 'u';
|
||||
val[count++] = 'l';
|
||||
val[count++] = 'l';
|
||||
} else {
|
||||
checkOffset(count + 4, val.length >> 1);
|
||||
StringUTF16.putChar(val, count++, 'n');
|
||||
StringUTF16.putChar(val, count++, 'u');
|
||||
StringUTF16.putChar(val, count++, 'l');
|
||||
StringUTF16.putChar(val, count++, 'l');
|
||||
}
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -507,21 +578,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
@Override
|
||||
public AbstractStringBuilder append(CharSequence s, int start, int end) {
|
||||
if (s == null)
|
||||
if (s == null) {
|
||||
s = "null";
|
||||
if ((start < 0) || (start > end) || (end > s.length()))
|
||||
throw new IndexOutOfBoundsException(
|
||||
"start " + start + ", end " + end + ", s.length() "
|
||||
+ s.length());
|
||||
}
|
||||
checkRange(start, end, s.length());
|
||||
int len = end - start;
|
||||
ensureCapacityInternal(count + len);
|
||||
if (s instanceof String) {
|
||||
((String)s).getChars(start, end, value, count);
|
||||
} else {
|
||||
for (int i = start, j = count; i < end; i++, j++)
|
||||
value[j] = s.charAt(i);
|
||||
}
|
||||
count += len;
|
||||
appendChars(s, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -544,8 +607,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
public AbstractStringBuilder append(char[] str) {
|
||||
int len = str.length;
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(str, 0, value, count, len);
|
||||
count += len;
|
||||
appendChars(str, 0, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -572,10 +634,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* or {@code offset+len > str.length}
|
||||
*/
|
||||
public AbstractStringBuilder append(char str[], int offset, int len) {
|
||||
if (len > 0) // let arraycopy report AIOOBE for len < 0
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(str, offset, value, count, len);
|
||||
count += len;
|
||||
int end = offset + len;
|
||||
checkRange(offset, end, str.length);
|
||||
ensureCapacityInternal(count + len);
|
||||
appendChars(str, offset, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -592,20 +654,39 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @return a reference to this object.
|
||||
*/
|
||||
public AbstractStringBuilder append(boolean b) {
|
||||
if (b) {
|
||||
ensureCapacityInternal(count + 4);
|
||||
value[count++] = 't';
|
||||
value[count++] = 'r';
|
||||
value[count++] = 'u';
|
||||
value[count++] = 'e';
|
||||
ensureCapacityInternal(count + (b ? 4 : 5));
|
||||
int count = this.count;
|
||||
byte[] val = this.value;
|
||||
if (isLatin1()) {
|
||||
if (b) {
|
||||
val[count++] = 't';
|
||||
val[count++] = 'r';
|
||||
val[count++] = 'u';
|
||||
val[count++] = 'e';
|
||||
} else {
|
||||
val[count++] = 'f';
|
||||
val[count++] = 'a';
|
||||
val[count++] = 'l';
|
||||
val[count++] = 's';
|
||||
val[count++] = 'e';
|
||||
}
|
||||
} else {
|
||||
ensureCapacityInternal(count + 5);
|
||||
value[count++] = 'f';
|
||||
value[count++] = 'a';
|
||||
value[count++] = 'l';
|
||||
value[count++] = 's';
|
||||
value[count++] = 'e';
|
||||
if (b) {
|
||||
checkOffset(count + 4, val.length >> 1);
|
||||
StringUTF16.putChar(val, count++, 't');
|
||||
StringUTF16.putChar(val, count++, 'r');
|
||||
StringUTF16.putChar(val, count++, 'u');
|
||||
StringUTF16.putChar(val, count++, 'e');
|
||||
} else {
|
||||
checkOffset(count + 5, val.length >> 1);
|
||||
StringUTF16.putChar(val, count++, 'f');
|
||||
StringUTF16.putChar(val, count++, 'a');
|
||||
StringUTF16.putChar(val, count++, 'l');
|
||||
StringUTF16.putChar(val, count++, 's');
|
||||
StringUTF16.putChar(val, count++, 'e');
|
||||
}
|
||||
}
|
||||
this.count = count;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -627,7 +708,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
@Override
|
||||
public AbstractStringBuilder append(char c) {
|
||||
ensureCapacityInternal(count + 1);
|
||||
value[count++] = c;
|
||||
if (isLatin1() && StringLatin1.canEncode(c)) {
|
||||
value[count++] = (byte)c;
|
||||
} else {
|
||||
if (isLatin1()) {
|
||||
inflate();
|
||||
}
|
||||
StringUTF16.putCharSB(value, count++, c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -652,7 +740,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
: Integer.stringSize(i);
|
||||
int spaceNeeded = count + appendedLength;
|
||||
ensureCapacityInternal(spaceNeeded);
|
||||
Integer.getChars(i, spaceNeeded, value);
|
||||
if (isLatin1()) {
|
||||
Integer.getChars(i, spaceNeeded, value);
|
||||
} else {
|
||||
byte[] val = this.value;
|
||||
checkOffset(spaceNeeded, val.length >> 1);
|
||||
Integer.getCharsUTF16(i, spaceNeeded, val);
|
||||
}
|
||||
count = spaceNeeded;
|
||||
return this;
|
||||
}
|
||||
@ -678,7 +772,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
: Long.stringSize(l);
|
||||
int spaceNeeded = count + appendedLength;
|
||||
ensureCapacityInternal(spaceNeeded);
|
||||
Long.getChars(l, spaceNeeded, value);
|
||||
if (isLatin1()) {
|
||||
Long.getChars(l, spaceNeeded, value);
|
||||
} else {
|
||||
byte[] val = this.value;
|
||||
checkOffset(spaceNeeded, val.length >> 1);
|
||||
Long.getCharsUTF16(l, spaceNeeded, val);
|
||||
}
|
||||
count = spaceNeeded;
|
||||
return this;
|
||||
}
|
||||
@ -732,15 +832,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* greater than {@code end}.
|
||||
*/
|
||||
public AbstractStringBuilder delete(int start, int end) {
|
||||
if (start < 0)
|
||||
throw new StringIndexOutOfBoundsException(start);
|
||||
if (end > count)
|
||||
if (end > count) {
|
||||
end = count;
|
||||
if (start > end)
|
||||
throw new StringIndexOutOfBoundsException();
|
||||
}
|
||||
checkRangeSIOOBE(start, end, count);
|
||||
int len = end - start;
|
||||
if (len > 0) {
|
||||
System.arraycopy(value, start+len, value, start, count-end);
|
||||
shift(end, -len);
|
||||
count -= len;
|
||||
}
|
||||
return this;
|
||||
@ -766,20 +864,10 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* {@code codePoint} isn't a valid Unicode code point
|
||||
*/
|
||||
public AbstractStringBuilder appendCodePoint(int codePoint) {
|
||||
final int count = this.count;
|
||||
|
||||
if (Character.isBmpCodePoint(codePoint)) {
|
||||
ensureCapacityInternal(count + 1);
|
||||
value[count] = (char) codePoint;
|
||||
this.count = count + 1;
|
||||
} else if (Character.isValidCodePoint(codePoint)) {
|
||||
ensureCapacityInternal(count + 2);
|
||||
Character.toSurrogates(codePoint, value, count);
|
||||
this.count = count + 2;
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
return append((char)codePoint);
|
||||
}
|
||||
return this;
|
||||
return append(Character.toChars(codePoint));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -800,9 +888,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* {@code length()}.
|
||||
*/
|
||||
public AbstractStringBuilder deleteCharAt(int index) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
System.arraycopy(value, index+1, value, index, count-index-1);
|
||||
checkIndex(index, count);
|
||||
shift(index + 1, -1);
|
||||
count--;
|
||||
return this;
|
||||
}
|
||||
@ -827,22 +914,16 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* greater than {@code end}.
|
||||
*/
|
||||
public AbstractStringBuilder replace(int start, int end, String str) {
|
||||
if (start < 0)
|
||||
throw new StringIndexOutOfBoundsException(start);
|
||||
if (start > count)
|
||||
throw new StringIndexOutOfBoundsException("start > length()");
|
||||
if (start > end)
|
||||
throw new StringIndexOutOfBoundsException("start > end");
|
||||
|
||||
if (end > count)
|
||||
if (end > count) {
|
||||
end = count;
|
||||
}
|
||||
checkRangeSIOOBE(start, end, count);
|
||||
int len = str.length();
|
||||
int newCount = count + len - (end - start);
|
||||
ensureCapacityInternal(newCount);
|
||||
|
||||
System.arraycopy(value, end, value, start + len, count - end);
|
||||
str.getChars(value, start);
|
||||
shift(end, newCount - count);
|
||||
count = newCount;
|
||||
putStringAt(start, str);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -907,13 +988,16 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* greater than {@code end}.
|
||||
*/
|
||||
public String substring(int start, int end) {
|
||||
if (start < 0)
|
||||
throw new StringIndexOutOfBoundsException(start);
|
||||
if (end > count)
|
||||
throw new StringIndexOutOfBoundsException(end);
|
||||
if (start > end)
|
||||
throw new StringIndexOutOfBoundsException(end - start);
|
||||
return new String(value, start, end - start);
|
||||
checkRangeSIOOBE(start, end, count);
|
||||
if (isLatin1()) {
|
||||
return StringLatin1.newString(value, start, end - start);
|
||||
}
|
||||
return StringUTF16.newStringSB(value, start, end - start);
|
||||
}
|
||||
|
||||
private void shift(int offset, int n) {
|
||||
System.arraycopy(value, offset << coder,
|
||||
value, (offset + n) << coder, (count - offset) << coder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -940,16 +1024,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
public AbstractStringBuilder insert(int index, char[] str, int offset,
|
||||
int len)
|
||||
{
|
||||
if ((index < 0) || (index > length()))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
if ((offset < 0) || (len < 0) || (offset > str.length - len))
|
||||
throw new StringIndexOutOfBoundsException(
|
||||
"offset " + offset + ", len " + len + ", str.length "
|
||||
+ str.length);
|
||||
checkOffset(index, count);
|
||||
checkRangeSIOOBE(offset, offset + len, str.length);
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(value, index, value, index + len, count - index);
|
||||
System.arraycopy(str, offset, value, index, len);
|
||||
shift(index, len);
|
||||
count += len;
|
||||
putCharsAt(index, str, offset, offset + len);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1008,15 +1088,15 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @throws StringIndexOutOfBoundsException if the offset is invalid.
|
||||
*/
|
||||
public AbstractStringBuilder insert(int offset, String str) {
|
||||
if ((offset < 0) || (offset > length()))
|
||||
throw new StringIndexOutOfBoundsException(offset);
|
||||
if (str == null)
|
||||
checkOffset(offset, count);
|
||||
if (str == null) {
|
||||
str = "null";
|
||||
}
|
||||
int len = str.length();
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
str.getChars(value, offset);
|
||||
shift(offset, len);
|
||||
count += len;
|
||||
putStringAt(offset, str);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1045,13 +1125,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @throws StringIndexOutOfBoundsException if the offset is invalid.
|
||||
*/
|
||||
public AbstractStringBuilder insert(int offset, char[] str) {
|
||||
if ((offset < 0) || (offset > length()))
|
||||
throw new StringIndexOutOfBoundsException(offset);
|
||||
checkOffset(offset, count);
|
||||
int len = str.length;
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(value, offset, value, offset + len, count - offset);
|
||||
System.arraycopy(str, 0, value, offset, len);
|
||||
shift(offset, len);
|
||||
count += len;
|
||||
putCharsAt(offset, str, 0, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1077,10 +1156,12 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @throws IndexOutOfBoundsException if the offset is invalid.
|
||||
*/
|
||||
public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
|
||||
if (s == null)
|
||||
if (s == null) {
|
||||
s = "null";
|
||||
if (s instanceof String)
|
||||
}
|
||||
if (s instanceof String) {
|
||||
return this.insert(dstOffset, (String)s);
|
||||
}
|
||||
return this.insert(dstOffset, s, 0, s.length());
|
||||
}
|
||||
|
||||
@ -1128,23 +1209,19 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* {@code start} is greater than {@code end} or
|
||||
* {@code end} is greater than {@code s.length()}
|
||||
*/
|
||||
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
|
||||
int start, int end) {
|
||||
if (s == null)
|
||||
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
|
||||
int start, int end)
|
||||
{
|
||||
if (s == null) {
|
||||
s = "null";
|
||||
if ((dstOffset < 0) || (dstOffset > this.length()))
|
||||
throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
|
||||
if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
|
||||
throw new IndexOutOfBoundsException(
|
||||
"start " + start + ", end " + end + ", s.length() "
|
||||
+ s.length());
|
||||
}
|
||||
checkOffset(dstOffset, count);
|
||||
checkRange(start, end, s.length());
|
||||
int len = end - start;
|
||||
ensureCapacityInternal(count + len);
|
||||
System.arraycopy(value, dstOffset, value, dstOffset + len,
|
||||
count - dstOffset);
|
||||
for (int i=start; i<end; i++)
|
||||
value[dstOffset++] = s.charAt(i);
|
||||
shift(dstOffset, len);
|
||||
count += len;
|
||||
putCharsAt(dstOffset, s, start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1191,10 +1268,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @throws IndexOutOfBoundsException if the offset is invalid.
|
||||
*/
|
||||
public AbstractStringBuilder insert(int offset, char c) {
|
||||
checkOffset(offset, count);
|
||||
ensureCapacityInternal(count + 1);
|
||||
System.arraycopy(value, offset, value, offset + 1, count - offset);
|
||||
value[offset] = c;
|
||||
shift(offset, 1);
|
||||
count += 1;
|
||||
if (isLatin1() && StringLatin1.canEncode(c)) {
|
||||
value[offset] = (byte)c;
|
||||
} else {
|
||||
if (isLatin1()) {
|
||||
inflate();
|
||||
}
|
||||
StringUTF16.putCharSB(value, offset, c);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -1326,7 +1411,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* or {@code -1} if there is no such occurrence.
|
||||
*/
|
||||
public int indexOf(String str, int fromIndex) {
|
||||
return String.indexOf(value, 0, count, str, fromIndex);
|
||||
return String.indexOf(value, coder, count, str, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1366,7 +1451,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* or {@code -1} if there is no such occurrence.
|
||||
*/
|
||||
public int lastIndexOf(String str, int fromIndex) {
|
||||
return String.lastIndexOf(value, 0, count, str, fromIndex);
|
||||
return String.lastIndexOf(value, coder, count, str, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1392,34 +1477,47 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
* @return a reference to this object.
|
||||
*/
|
||||
public AbstractStringBuilder reverse() {
|
||||
boolean hasSurrogates = false;
|
||||
byte[] val = this.value;
|
||||
int count = this.count;
|
||||
int coder = this.coder;
|
||||
int n = count - 1;
|
||||
for (int j = (n-1) >> 1; j >= 0; j--) {
|
||||
int k = n - j;
|
||||
char cj = value[j];
|
||||
char ck = value[k];
|
||||
value[j] = ck;
|
||||
value[k] = cj;
|
||||
if (Character.isSurrogate(cj) ||
|
||||
Character.isSurrogate(ck)) {
|
||||
hasSurrogates = true;
|
||||
if (COMPACT_STRINGS && coder == LATIN1) {
|
||||
for (int j = (n-1) >> 1; j >= 0; j--) {
|
||||
int k = n - j;
|
||||
byte cj = val[j];
|
||||
val[j] = val[k];
|
||||
val[k] = cj;
|
||||
}
|
||||
} else {
|
||||
checkOffset(count, val.length >> 1);
|
||||
boolean hasSurrogates = false;
|
||||
for (int j = (n-1) >> 1; j >= 0; j--) {
|
||||
int k = n - j;
|
||||
char cj = StringUTF16.getChar(val, j);
|
||||
char ck = StringUTF16.getChar(val, k);
|
||||
StringUTF16.putChar(val, j, ck);
|
||||
StringUTF16.putChar(val, k, cj);
|
||||
if (Character.isSurrogate(cj) ||
|
||||
Character.isSurrogate(ck)) {
|
||||
hasSurrogates = true;
|
||||
}
|
||||
}
|
||||
if (hasSurrogates) {
|
||||
reverseAllValidSurrogatePairs(val, count);
|
||||
}
|
||||
}
|
||||
if (hasSurrogates) {
|
||||
reverseAllValidSurrogatePairs();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Outlined helper method for reverse() */
|
||||
private void reverseAllValidSurrogatePairs() {
|
||||
private void reverseAllValidSurrogatePairs(byte[] val, int count) {
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
char c2 = value[i];
|
||||
char c2 = StringUTF16.getChar(val, i);
|
||||
if (Character.isLowSurrogate(c2)) {
|
||||
char c1 = value[i + 1];
|
||||
char c1 = StringUTF16.getChar(val, i + 1);
|
||||
if (Character.isHighSurrogate(c1)) {
|
||||
value[i++] = c1;
|
||||
value[i] = c2;
|
||||
StringUTF16.putChar(val, i++, c1);
|
||||
StringUTF16.putChar(val, i, c2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1444,10 +1542,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
@Override
|
||||
public IntStream chars() {
|
||||
byte[] val = this.value; int count = this.count; byte coder = this.coder;
|
||||
checkOffset(count, val.length >> coder);
|
||||
// Reuse String-based spliterator. This requires a supplier to
|
||||
// capture the value and count when the terminal operation is executed
|
||||
return StreamSupport.intStream(
|
||||
() -> new String.IntCharArraySpliterator(value, 0, count, 0),
|
||||
() -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
|
||||
: new StringUTF16.CharsSpliterator(val, 0, count, 0),
|
||||
Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
|
||||
false);
|
||||
}
|
||||
@ -1458,10 +1559,13 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
@Override
|
||||
public IntStream codePoints() {
|
||||
byte[] val = this.value; int count = this.count; byte coder = this.coder;
|
||||
checkOffset(count, val.length >> coder);
|
||||
// Reuse String-based spliterator. This requires a supplier to
|
||||
// capture the value and count when the terminal operation is executed
|
||||
return StreamSupport.intStream(
|
||||
() -> new String.CodePointsSpliterator(value, 0, count, 0),
|
||||
() -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
|
||||
: new StringUTF16.CodePointsSpliterator(val, 0, count, 0),
|
||||
Spliterator.ORDERED,
|
||||
false);
|
||||
}
|
||||
@ -1469,8 +1573,147 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
||||
/**
|
||||
* Needed by {@code String} for the contentEquals method.
|
||||
*/
|
||||
final char[] getValue() {
|
||||
final byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invoker guarantees it is in UTF16 (inflate itself for asb), if two
|
||||
* coders are different and the dstBegin has enough space
|
||||
*
|
||||
* @param dstBegin the char index, not offset of byte[]
|
||||
* @param coder the coder of dst[]
|
||||
*/
|
||||
protected void getBytes(byte dst[], int dstBegin, byte coder) {
|
||||
if (this.coder == coder) {
|
||||
System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
|
||||
} else { // this.coder == LATIN && coder == UTF16
|
||||
StringLatin1.inflateSB(value, dst, dstBegin, count);
|
||||
}
|
||||
}
|
||||
|
||||
/* for readObject() */
|
||||
protected void initBytes(char[] value, int off, int len) {
|
||||
if (String.COMPACT_STRINGS) {
|
||||
this.value = StringUTF16.compress(value, off, len);
|
||||
if (this.value != null) {
|
||||
this.coder = LATIN1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.coder = UTF16;
|
||||
this.value = StringUTF16.toBytes(value, off, len);
|
||||
}
|
||||
|
||||
final byte getCoder() {
|
||||
return COMPACT_STRINGS ? coder : UTF16;
|
||||
}
|
||||
|
||||
final boolean isLatin1() {
|
||||
return COMPACT_STRINGS && coder == LATIN1;
|
||||
}
|
||||
|
||||
private final void putCharsAt(int index, char[] s, int off, int end) {
|
||||
if (isLatin1()) {
|
||||
byte[] val = this.value;
|
||||
for (int i = off, j = index; i < end; i++) {
|
||||
char c = s[i];
|
||||
if (StringLatin1.canEncode(c)) {
|
||||
val[j++] = (byte)c;
|
||||
} else {
|
||||
inflate();
|
||||
StringUTF16.putCharsSB(this.value, j, s, i, end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringUTF16.putCharsSB(this.value, index, s, off, end);
|
||||
}
|
||||
}
|
||||
|
||||
private final void putCharsAt(int index, CharSequence s, int off, int end) {
|
||||
if (isLatin1()) {
|
||||
byte[] val = this.value;
|
||||
for (int i = off, j = index; i < end; i++) {
|
||||
char c = s.charAt(i);
|
||||
if (StringLatin1.canEncode(c)) {
|
||||
val[j++] = (byte)c;
|
||||
} else {
|
||||
inflate();
|
||||
StringUTF16.putCharsSB(this.value, j, s, i, end);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringUTF16.putCharsSB(this.value, index, s, off, end);
|
||||
}
|
||||
}
|
||||
|
||||
private final void putStringAt(int index, String str) {
|
||||
if (getCoder() != str.coder()) {
|
||||
inflate();
|
||||
}
|
||||
byte[] val = this.value;
|
||||
byte coder = this.coder;
|
||||
checkOffset(index + str.length(), val.length >> coder);
|
||||
str.getBytes(val, index, coder);
|
||||
}
|
||||
|
||||
private final void appendChars(char[] s, int off, int end) {
|
||||
if (isLatin1()) {
|
||||
byte[] val = this.value;
|
||||
for (int i = off, j = count; i < end; i++) {
|
||||
char c = s[i];
|
||||
if (StringLatin1.canEncode(c)) {
|
||||
val[j++] = (byte)c;
|
||||
} else {
|
||||
count = j;
|
||||
inflate();
|
||||
StringUTF16.putCharsSB(this.value, j, s, i, end);
|
||||
count += end - i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringUTF16.putCharsSB(this.value, count, s, off, end);
|
||||
}
|
||||
count += end - off;
|
||||
}
|
||||
|
||||
private final void appendChars(CharSequence s, int off, int end) {
|
||||
if (isLatin1()) {
|
||||
byte[] val = this.value;
|
||||
for (int i = off, j = count; i < end; i++) {
|
||||
char c = s.charAt(i);
|
||||
if (StringLatin1.canEncode(c)) {
|
||||
val[j++] = (byte)c;
|
||||
} else {
|
||||
count = j;
|
||||
inflate();
|
||||
StringUTF16.putCharsSB(this.value, j, s, i, end);
|
||||
count += end - i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
StringUTF16.putCharsSB(this.value, count, s, off, end);
|
||||
}
|
||||
count += end - off;
|
||||
}
|
||||
|
||||
/* IndexOutOfBoundsException, if out of bounds */
|
||||
private static void checkRange(int start, int end, int len) {
|
||||
if (start < 0 || start > end || end > len) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"start " + start + ", end " + end + ", length " + len);
|
||||
}
|
||||
}
|
||||
|
||||
/* StringIndexOutOfBoundsException, if out of bounds */
|
||||
private static void checkRangeSIOOBE(int start, int end, int len) {
|
||||
if (start < 0 || start > end || end > len) {
|
||||
throw new StringIndexOutOfBoundsException(
|
||||
"start " + start + ", end " + end + ", length " + len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.StringJoiner;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.ConstantPool;
|
||||
|
@ -29,6 +29,10 @@ import java.lang.annotation.Native;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import static java.lang.String.COMPACT_STRINGS;
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.UTF16;
|
||||
|
||||
/**
|
||||
* The {@code Integer} class wraps a value of the primitive type
|
||||
* {@code int} in an object. An object of type {@code Integer}
|
||||
@ -138,25 +142,47 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
return toString(i);
|
||||
}
|
||||
|
||||
char buf[] = new char[33];
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[33];
|
||||
boolean negative = (i < 0);
|
||||
int charPos = 32;
|
||||
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
while (i <= -radix) {
|
||||
buf[charPos--] = (byte)digits[-(i % radix)];
|
||||
i = i / radix;
|
||||
}
|
||||
buf[charPos] = (byte)digits[-i];
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = '-';
|
||||
}
|
||||
|
||||
return StringLatin1.newString(buf, charPos, (33 - charPos));
|
||||
}
|
||||
return toStringUTF16(i, radix);
|
||||
}
|
||||
|
||||
private static String toStringUTF16(int i, int radix) {
|
||||
byte[] buf = new byte[33 * 2];
|
||||
boolean negative = (i < 0);
|
||||
int charPos = 32;
|
||||
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
while (i <= -radix) {
|
||||
buf[charPos--] = digits[-(i % radix)];
|
||||
StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
|
||||
i = i / radix;
|
||||
}
|
||||
buf[charPos] = digits[-i];
|
||||
StringUTF16.putChar(buf, charPos, digits[-i]);
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = '-';
|
||||
StringUTF16.putChar(buf, --charPos, '-');
|
||||
}
|
||||
|
||||
return new String(buf, charPos, (33 - charPos));
|
||||
return StringUTF16.newString(buf, charPos, (33 - charPos));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,12 +338,16 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
// assert shift > 0 && shift <=5 : "Illegal shift value";
|
||||
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
|
||||
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
|
||||
char[] buf = new char[chars];
|
||||
|
||||
formatUnsignedInt(val, shift, buf, 0, chars);
|
||||
|
||||
// Use special constructor which takes over "buf".
|
||||
return new String(buf, true);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[chars];
|
||||
formatUnsignedInt(val, shift, buf, 0, chars);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[chars * 2];
|
||||
formatUnsignedIntUTF16(val, shift, buf, 0, chars);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,7 +361,7 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
* @param offset the offset in the destination buffer to start at
|
||||
* @param len the number of characters to write
|
||||
*/
|
||||
static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
|
||||
static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
|
||||
// assert shift > 0 && shift <=5 : "Illegal shift value";
|
||||
// assert offset >= 0 && offset < buf.length : "illegal offset";
|
||||
// assert len > 0 && (offset + len) <= buf.length : "illegal length";
|
||||
@ -344,6 +374,28 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
/** byte[]/LATIN1 version */
|
||||
static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
|
||||
int charPos = offset + len;
|
||||
int radix = 1 << shift;
|
||||
int mask = radix - 1;
|
||||
do {
|
||||
buf[--charPos] = (byte)Integer.digits[val & mask];
|
||||
val >>>= shift;
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
/** byte[]/UTF16 version */
|
||||
static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
|
||||
int charPos = offset + len;
|
||||
int radix = 1 << shift;
|
||||
int mask = radix - 1;
|
||||
do {
|
||||
StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
|
||||
val >>>= shift;
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
static final char [] DigitTens = {
|
||||
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
|
||||
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
|
||||
@ -401,9 +453,15 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
if (i == Integer.MIN_VALUE)
|
||||
return "-2147483648";
|
||||
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
|
||||
char[] buf = new char[size];
|
||||
getChars(i, size, buf);
|
||||
return new String(buf, true);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[size];
|
||||
getChars(i, size, buf);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[size * 2];
|
||||
getCharsUTF16(i, size, buf);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -433,7 +491,7 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
*
|
||||
* Will fail if i == Integer.MIN_VALUE
|
||||
*/
|
||||
static void getChars(int i, int index, char[] buf) {
|
||||
static void getChars(int i, int index, byte[] buf) {
|
||||
int q, r;
|
||||
int charPos = index;
|
||||
char sign = 0;
|
||||
@ -449,8 +507,8 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
// really: r = i - (q * 100);
|
||||
r = i - ((q << 6) + (q << 5) + (q << 2));
|
||||
i = q;
|
||||
buf [--charPos] = DigitOnes[r];
|
||||
buf [--charPos] = DigitTens[r];
|
||||
buf [--charPos] = (byte)DigitOnes[r];
|
||||
buf [--charPos] = (byte)DigitTens[r];
|
||||
}
|
||||
|
||||
// Fall thru to fast mode for smaller numbers
|
||||
@ -458,12 +516,46 @@ public final class Integer extends Number implements Comparable<Integer> {
|
||||
for (;;) {
|
||||
q = (i * 52429) >>> (16+3);
|
||||
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
|
||||
buf [--charPos] = digits [r];
|
||||
buf [--charPos] = (byte)digits [r];
|
||||
i = q;
|
||||
if (i == 0) break;
|
||||
}
|
||||
if (sign != 0) {
|
||||
buf [--charPos] = sign;
|
||||
buf [--charPos] = (byte)sign;
|
||||
}
|
||||
}
|
||||
|
||||
static void getCharsUTF16(int i, int index, byte[] buf) {
|
||||
int q, r;
|
||||
int charPos = index;
|
||||
char sign = 0;
|
||||
|
||||
if (i < 0) {
|
||||
sign = '-';
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Generate two digits per iteration
|
||||
while (i >= 65536) {
|
||||
q = i / 100;
|
||||
// really: r = i - (q * 100);
|
||||
r = i - ((q << 6) + (q << 5) + (q << 2));
|
||||
i = q;
|
||||
StringUTF16.putChar(buf, --charPos, DigitOnes[r]);
|
||||
StringUTF16.putChar(buf, --charPos, DigitTens[r]);
|
||||
}
|
||||
|
||||
// Fall thru to fast mode for smaller numbers
|
||||
// assert(i <= 65536, i);
|
||||
for (;;) {
|
||||
q = (i * 52429) >>> (16+3);
|
||||
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
|
||||
StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
|
||||
i = q;
|
||||
if (i == 0) break;
|
||||
}
|
||||
if (sign != 0) {
|
||||
StringUTF16.putChar(buf, --charPos, sign);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,9 @@ import java.math.*;
|
||||
import java.util.Objects;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import static java.lang.String.COMPACT_STRINGS;
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.UTF16;
|
||||
|
||||
/**
|
||||
* The {@code Long} class wraps a value of the primitive type {@code
|
||||
@ -124,25 +127,46 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
radix = 10;
|
||||
if (radix == 10)
|
||||
return toString(i);
|
||||
char[] buf = new char[65];
|
||||
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[65];
|
||||
int charPos = 64;
|
||||
boolean negative = (i < 0);
|
||||
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
while (i <= -radix) {
|
||||
buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))];
|
||||
i = i / radix;
|
||||
}
|
||||
buf[charPos] = (byte)Integer.digits[(int)(-i)];
|
||||
|
||||
if (negative) {
|
||||
buf[--charPos] = '-';
|
||||
}
|
||||
return StringLatin1.newString(buf, charPos, (65 - charPos));
|
||||
}
|
||||
return toStringUTF16(i, radix);
|
||||
}
|
||||
|
||||
private static String toStringUTF16(long i, int radix) {
|
||||
byte[] buf = new byte[65 * 2];
|
||||
int charPos = 64;
|
||||
boolean negative = (i < 0);
|
||||
|
||||
if (!negative) {
|
||||
i = -i;
|
||||
}
|
||||
|
||||
while (i <= -radix) {
|
||||
buf[charPos--] = Integer.digits[(int)(-(i % radix))];
|
||||
StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]);
|
||||
i = i / radix;
|
||||
}
|
||||
buf[charPos] = Integer.digits[(int)(-i)];
|
||||
|
||||
StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]);
|
||||
if (negative) {
|
||||
buf[--charPos] = '-';
|
||||
StringUTF16.putChar(buf, --charPos, '-');
|
||||
}
|
||||
|
||||
return new String(buf, charPos, (65 - charPos));
|
||||
return StringUTF16.newString(buf, charPos, (65 - charPos));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -355,10 +379,16 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
// assert shift > 0 && shift <=5 : "Illegal shift value";
|
||||
int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
|
||||
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
|
||||
char[] buf = new char[chars];
|
||||
|
||||
formatUnsignedLong(val, shift, buf, 0, chars);
|
||||
return new String(buf, true);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[chars];
|
||||
formatUnsignedLong0(val, shift, buf, 0, chars);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[chars * 2];
|
||||
formatUnsignedLong0UTF16(val, shift, buf, 0, chars);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -385,6 +415,28 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
/** byte[]/LATIN1 version */
|
||||
static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) {
|
||||
int charPos = offset + len;
|
||||
int radix = 1 << shift;
|
||||
int mask = radix - 1;
|
||||
do {
|
||||
buf[--charPos] = (byte)Integer.digits[((int) val) & mask];
|
||||
val >>>= shift;
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
/** byte[]/UTF16 version */
|
||||
static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
|
||||
int charPos = offset + len;
|
||||
int radix = 1 << shift;
|
||||
int mask = radix - 1;
|
||||
do {
|
||||
StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]);
|
||||
val >>>= shift;
|
||||
} while (charPos > offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code String} object representing the specified
|
||||
* {@code long}. The argument is converted to signed decimal
|
||||
@ -399,9 +451,15 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
if (i == Long.MIN_VALUE)
|
||||
return "-9223372036854775808";
|
||||
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
|
||||
char[] buf = new char[size];
|
||||
getChars(i, size, buf);
|
||||
return new String(buf, true);
|
||||
if (COMPACT_STRINGS) {
|
||||
byte[] buf = new byte[size];
|
||||
getChars(i, size, buf);
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = new byte[size * 2];
|
||||
getCharsUTF16(i, size, buf);
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,7 +489,7 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
*
|
||||
* Will fail if i == Long.MIN_VALUE
|
||||
*/
|
||||
static void getChars(long i, int index, char[] buf) {
|
||||
static void getChars(long i, int index, byte[] buf) {
|
||||
long q;
|
||||
int r;
|
||||
int charPos = index;
|
||||
@ -448,8 +506,8 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
// really: r = i - (q * 100);
|
||||
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
|
||||
i = q;
|
||||
buf[--charPos] = Integer.DigitOnes[r];
|
||||
buf[--charPos] = Integer.DigitTens[r];
|
||||
buf[--charPos] = (byte)Integer.DigitOnes[r];
|
||||
buf[--charPos] = (byte)Integer.DigitTens[r];
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
@ -460,8 +518,8 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
// really: r = i2 - (q * 100);
|
||||
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
|
||||
i2 = q2;
|
||||
buf[--charPos] = Integer.DigitOnes[r];
|
||||
buf[--charPos] = Integer.DigitTens[r];
|
||||
buf[--charPos] = (byte)Integer.DigitOnes[r];
|
||||
buf[--charPos] = (byte)Integer.DigitTens[r];
|
||||
}
|
||||
|
||||
// Fall thru to fast mode for smaller numbers
|
||||
@ -469,12 +527,59 @@ public final class Long extends Number implements Comparable<Long> {
|
||||
for (;;) {
|
||||
q2 = (i2 * 52429) >>> (16+3);
|
||||
r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
|
||||
buf[--charPos] = Integer.digits[r];
|
||||
buf[--charPos] = (byte)Integer.digits[r];
|
||||
i2 = q2;
|
||||
if (i2 == 0) break;
|
||||
}
|
||||
if (sign != 0) {
|
||||
buf[--charPos] = sign;
|
||||
buf[--charPos] = (byte)sign;
|
||||
}
|
||||
}
|
||||
|
||||
static void getCharsUTF16(long i, int index, byte[] buf) {
|
||||
long q;
|
||||
int r;
|
||||
int charPos = index;
|
||||
char sign = 0;
|
||||
|
||||
if (i < 0) {
|
||||
sign = '-';
|
||||
i = -i;
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using longs until quotient fits into an int
|
||||
while (i > Integer.MAX_VALUE) {
|
||||
q = i / 100;
|
||||
// really: r = i - (q * 100);
|
||||
r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
|
||||
i = q;
|
||||
StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
|
||||
StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
|
||||
}
|
||||
|
||||
// Get 2 digits/iteration using ints
|
||||
int q2;
|
||||
int i2 = (int)i;
|
||||
while (i2 >= 65536) {
|
||||
q2 = i2 / 100;
|
||||
// really: r = i2 - (q * 100);
|
||||
r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
|
||||
i2 = q2;
|
||||
StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
|
||||
StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
|
||||
}
|
||||
|
||||
// Fall thru to fast mode for smaller numbers
|
||||
// assert(i2 <= 65536, i2);
|
||||
for (;;) {
|
||||
q2 = (i2 * 52429) >>> (16+3);
|
||||
r = i2 - ((q2 << 3) + (q2 << 1)); // r = i2-(q2*10) ...
|
||||
StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
|
||||
i2 = q2;
|
||||
if (i2 == 0) break;
|
||||
}
|
||||
if (sign != 0) {
|
||||
StringUTF16.putChar(buf, --charPos, sign);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,11 @@
|
||||
package java.lang;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Pipe;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -43,6 +45,11 @@ import java.security.PrivilegedAction;
|
||||
* {@link Process} instance with those attributes. The {@link
|
||||
* #start()} method can be invoked repeatedly from the same instance
|
||||
* to create new subprocesses with identical or related attributes.
|
||||
* <p>
|
||||
* The {@link #startPipeline startPipeline} method can be invoked to create
|
||||
* a pipeline of new processes that send the output of each process
|
||||
* directly to the next process. Each process has the attributes of
|
||||
* its respective ProcessBuilder.
|
||||
*
|
||||
* <p>Each process builder manages these process attributes:
|
||||
*
|
||||
@ -696,11 +703,37 @@ public final class ProcessBuilder
|
||||
private Redirect() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private implementation subclass of Redirect that holds a FileDescriptor for the
|
||||
* output of a previously started Process.
|
||||
* The FileDescriptor is used as the standard input of the next Process
|
||||
* to be started.
|
||||
*/
|
||||
static class RedirectPipeImpl extends Redirect {
|
||||
final FileDescriptor fd;
|
||||
|
||||
RedirectPipeImpl() {
|
||||
this.fd = new FileDescriptor();
|
||||
}
|
||||
@Override
|
||||
public Type type() { return Type.PIPE; }
|
||||
|
||||
@Override
|
||||
public String toString() { return type().toString();}
|
||||
|
||||
FileDescriptor getFd() { return fd; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of redirects, creating the default as needed.
|
||||
* @return the array of redirects
|
||||
*/
|
||||
private Redirect[] redirects() {
|
||||
if (redirects == null)
|
||||
if (redirects == null) {
|
||||
redirects = new Redirect[] {
|
||||
Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
|
||||
Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
|
||||
};
|
||||
}
|
||||
return redirects;
|
||||
}
|
||||
|
||||
@ -1039,6 +1072,18 @@ public final class ProcessBuilder
|
||||
* @see Runtime#exec(String[], String[], java.io.File)
|
||||
*/
|
||||
public Process start() throws IOException {
|
||||
return start(redirects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new Process using an explicit array of redirects.
|
||||
* See {@link #start} for details of starting each Process.
|
||||
*
|
||||
* @param redirect array of redirects for stdin, stdout, stderr
|
||||
* @return the new Process
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private Process start(Redirect[] redirects) throws IOException {
|
||||
// Must convert to array first -- a malicious user-supplied
|
||||
// list might try to circumvent the security check.
|
||||
String[] cmdarray = command.toArray(new String[command.size()]);
|
||||
@ -1089,4 +1134,171 @@ public final class ProcessBuilder
|
||||
cause);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a Process for each ProcessBuilder, creating a pipeline of
|
||||
* processes linked by their standard output and standard input streams.
|
||||
* The attributes of each ProcessBuilder are used to start the respective
|
||||
* process except that as each process is started, its standard output
|
||||
* is directed to the standard input of the next. The redirects for standard
|
||||
* input of the first process and standard output of the last process are
|
||||
* initialized using the redirect settings of the respective ProcessBuilder.
|
||||
* All other {@code ProcessBuilder} redirects should be
|
||||
* {@link Redirect#PIPE Redirect.PIPE}.
|
||||
* <p>
|
||||
* All input and output streams between the intermediate processes are
|
||||
* not accessible.
|
||||
* The {@link Process#getOutputStream standard input} of all processes
|
||||
* except the first process are <i>null output streams</i>
|
||||
* The {@link Process#getInputStream standard output} of all processes
|
||||
* except the last process are <i>null input streams</i>.
|
||||
* <p>
|
||||
* The {@link #redirectErrorStream} of each ProcessBuilder applies to the
|
||||
* respective process. If set to {@code true}, the error stream is written
|
||||
* to the same stream as standard output.
|
||||
* <p>
|
||||
* If starting any of the processes throws an Exception, all processes
|
||||
* are forcibly destroyed.
|
||||
* <p>
|
||||
* The {@code startPipeline} method performs the same checks on
|
||||
* each ProcessBuilder as does the {@link #start} method. The new process
|
||||
* will invoke the command and arguments given by {@link #command()},
|
||||
* in a working directory as given by {@link #directory()},
|
||||
* with a process environment as given by {@link #environment()}.
|
||||
* <p>
|
||||
* This method checks that the command is a valid operating
|
||||
* system command. Which commands are valid is system-dependent,
|
||||
* but at the very least the command must be a non-empty list of
|
||||
* non-null strings.
|
||||
* <p>
|
||||
* A minimal set of system dependent environment variables may
|
||||
* be required to start a process on some operating systems.
|
||||
* As a result, the subprocess may inherit additional environment variable
|
||||
* settings beyond those in the process builder's {@link #environment()}.
|
||||
* <p>
|
||||
* If there is a security manager, its
|
||||
* {@link SecurityManager#checkExec checkExec}
|
||||
* method is called with the first component of this object's
|
||||
* {@code command} array as its argument. This may result in
|
||||
* a {@link SecurityException} being thrown.
|
||||
* <p>
|
||||
* Starting an operating system process is highly system-dependent.
|
||||
* Among the many things that can go wrong are:
|
||||
* <ul>
|
||||
* <li>The operating system program file was not found.
|
||||
* <li>Access to the program file was denied.
|
||||
* <li>The working directory does not exist.
|
||||
* <li>Invalid character in command argument, such as NUL.
|
||||
* </ul>
|
||||
* <p>
|
||||
* In such cases an exception will be thrown. The exact nature
|
||||
* of the exception is system-dependent, but it will always be a
|
||||
* subclass of {@link IOException}.
|
||||
* <p>
|
||||
* If the operating system does not support the creation of
|
||||
* processes, an {@link UnsupportedOperationException} will be thrown.
|
||||
* <p>
|
||||
* Subsequent modifications to this process builder will not
|
||||
* affect the returned {@link Process}.
|
||||
* @apiNote
|
||||
* For example to count the unique imports for all the files in a file hierarchy
|
||||
* on a Unix compatible platform:
|
||||
* <pre>{@code
|
||||
* String directory = "/home/duke/src";
|
||||
* ProcessBuilder[] builders = {
|
||||
* new ProcessBuilder("find", directory, "-type", "f"),
|
||||
new ProcessBuilder("xargs", "grep", "-h", "^import "),
|
||||
new ProcessBuilder("awk", "{print $2;}"),
|
||||
new ProcessBuilder("sort", "-u")};
|
||||
* List<Process> processes = ProcessBuilder.startPipeline(
|
||||
* Arrays.asList(builders));
|
||||
* Process last = processes.get(processes.size()-1);
|
||||
* try (InputStream is = last.getInputStream();
|
||||
* Reader isr = new InputStreamReader(is);
|
||||
* BufferedReader r = new BufferedReader(isr)) {
|
||||
* long count = r.lines().count();
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param builders a List of ProcessBuilders
|
||||
* @return a {@code List<Process>}es started from the corresponding
|
||||
* ProcessBuilder
|
||||
* @throws IllegalArgumentException any of the redirects except the
|
||||
* standard input of the first builder and the standard output of
|
||||
* the last builder are not {@link Redirect#PIPE}.
|
||||
* @throws NullPointerException
|
||||
* if an element of the command list is null or
|
||||
* if an element of the ProcessBuilder list is null or
|
||||
* the builders argument is null
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the command is an empty list (has size {@code 0})
|
||||
* @throws SecurityException
|
||||
* if a security manager exists and
|
||||
* <ul>
|
||||
* <li>its
|
||||
* {@link SecurityManager#checkExec checkExec}
|
||||
* method doesn't allow creation of the subprocess, or
|
||||
* <li>the standard input to the subprocess was
|
||||
* {@linkplain #redirectInput redirected from a file}
|
||||
* and the security manager's
|
||||
* {@link SecurityManager#checkRead(String) checkRead} method
|
||||
* denies read access to the file, or
|
||||
* <li>the standard output or standard error of the
|
||||
* subprocess was
|
||||
* {@linkplain #redirectOutput redirected to a file}
|
||||
* and the security manager's
|
||||
* {@link SecurityManager#checkWrite(String) checkWrite} method
|
||||
* denies write access to the file
|
||||
* </ul>
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* If the operating system does not support the creation of processes
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public static List<Process> startPipeline(List<ProcessBuilder> builders) throws IOException {
|
||||
// Accumulate and check the builders
|
||||
final int numBuilders = builders.size();
|
||||
List<Process> processes = new ArrayList<>(numBuilders);
|
||||
try {
|
||||
Redirect prevOutput = null;
|
||||
for (int index = 0; index < builders.size(); index++) {
|
||||
ProcessBuilder builder = builders.get(index);
|
||||
Redirect[] redirects = builder.redirects();
|
||||
if (index > 0) {
|
||||
// check the current Builder to see if it can take input from the previous
|
||||
if (builder.redirectInput() != Redirect.PIPE) {
|
||||
throw new IllegalArgumentException("builder redirectInput()" +
|
||||
" must be PIPE except for the first builder: "
|
||||
+ builder.redirectInput());
|
||||
}
|
||||
redirects[0] = prevOutput;
|
||||
}
|
||||
if (index < numBuilders - 1) {
|
||||
// check all but the last stage has output = PIPE
|
||||
if (builder.redirectOutput() != Redirect.PIPE) {
|
||||
throw new IllegalArgumentException("builder redirectOutput()" +
|
||||
" must be PIPE except for the last builder: "
|
||||
+ builder.redirectOutput());
|
||||
}
|
||||
redirects[1] = new RedirectPipeImpl(); // placeholder for new output
|
||||
}
|
||||
processes.add(builder.start(redirects));
|
||||
prevOutput = redirects[1];
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Cleanup processes already started
|
||||
processes.forEach(Process::destroyForcibly);
|
||||
processes.forEach(p -> {
|
||||
try {
|
||||
p.waitFor(); // Wait for it to exit
|
||||
} catch (InterruptedException ie) {
|
||||
// If interrupted; continue with next Process
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
throw ex;
|
||||
}
|
||||
return processes;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -104,7 +104,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
* A cache of the last value returned by toString. Cleared
|
||||
* whenever the StringBuffer is modified.
|
||||
*/
|
||||
private transient char[] toStringCache;
|
||||
private transient String toStringCache;
|
||||
|
||||
/** use serialVersionUID from JDK 1.0.2 for interoperability */
|
||||
static final long serialVersionUID = 3388685877147921107L;
|
||||
@ -169,15 +169,13 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
@Override
|
||||
public synchronized int capacity() {
|
||||
return value.length;
|
||||
return super.capacity();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public synchronized void ensureCapacity(int minimumCapacity) {
|
||||
if (minimumCapacity > value.length) {
|
||||
expandCapacity(minimumCapacity);
|
||||
}
|
||||
super.ensureCapacity(minimumCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,9 +202,7 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
*/
|
||||
@Override
|
||||
public synchronized char charAt(int index) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
return value[index];
|
||||
return super.charAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -261,10 +257,8 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
*/
|
||||
@Override
|
||||
public synchronized void setCharAt(int index, char ch) {
|
||||
if ((index < 0) || (index >= count))
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
toStringCache = null;
|
||||
value[index] = ch;
|
||||
super.setCharAt(index, ch);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -680,9 +674,11 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
@HotSpotIntrinsicCandidate
|
||||
public synchronized String toString() {
|
||||
if (toStringCache == null) {
|
||||
toStringCache = Arrays.copyOfRange(value, 0, count);
|
||||
return toStringCache =
|
||||
isLatin1() ? StringLatin1.newString(value, 0, count)
|
||||
: StringUTF16.newString(value, 0, count);
|
||||
}
|
||||
return new String(toStringCache, true);
|
||||
return new String(toStringCache);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -710,7 +706,13 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
private synchronized void writeObject(java.io.ObjectOutputStream s)
|
||||
throws java.io.IOException {
|
||||
java.io.ObjectOutputStream.PutField fields = s.putFields();
|
||||
fields.put("value", value);
|
||||
char[] val = new char[capacity()];
|
||||
if (isLatin1()) {
|
||||
StringLatin1.getChars(value, 0, count, val, 0);
|
||||
} else {
|
||||
StringUTF16.getChars(value, 0, count, val, 0);
|
||||
}
|
||||
fields.put("value", val);
|
||||
fields.put("count", count);
|
||||
fields.put("shared", false);
|
||||
s.writeFields();
|
||||
@ -723,7 +725,12 @@ import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
java.io.ObjectInputStream.GetField fields = s.readFields();
|
||||
value = (char[])fields.get("value", null);
|
||||
char[] val = (char[])fields.get("value", null);
|
||||
initBytes(val, 0, val.length);
|
||||
count = fields.get("count", 0);
|
||||
}
|
||||
|
||||
protected synchronized void getBytes(byte dst[], int dstBegin, byte coder) {
|
||||
super.getBytes(dst, dstBegin, coder);
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +412,8 @@ public final class StringBuilder
|
||||
@HotSpotIntrinsicCandidate
|
||||
public String toString() {
|
||||
// Create a copy, don't share the array
|
||||
return new String(value, 0, count);
|
||||
return isLatin1() ? StringLatin1.newString(value, 0, count)
|
||||
: StringUTF16.newStringSB(value, 0, count);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -430,7 +431,13 @@ public final class StringBuilder
|
||||
throws java.io.IOException {
|
||||
s.defaultWriteObject();
|
||||
s.writeInt(count);
|
||||
s.writeObject(value);
|
||||
char[] val = new char[capacity()];
|
||||
if (isLatin1()) {
|
||||
StringLatin1.getChars(value, 0, count, val, 0);
|
||||
} else {
|
||||
StringUTF16.getChars(value, 0, count, val, 0);
|
||||
}
|
||||
s.writeObject(val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -441,7 +448,8 @@ public final class StringBuilder
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
s.defaultReadObject();
|
||||
count = s.readInt();
|
||||
value = (char[]) s.readObject();
|
||||
char[] val = (char[]) s.readObject();
|
||||
initBytes(val, 0, val.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -38,11 +38,19 @@ import java.nio.charset.CodingErrorAction;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.Arrays;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import sun.misc.MessageUtils;
|
||||
import sun.nio.cs.HistoricallyNamedCharset;
|
||||
import sun.nio.cs.ArrayDecoder;
|
||||
import sun.nio.cs.ArrayEncoder;
|
||||
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.UTF16;
|
||||
import static java.lang.String.COMPACT_STRINGS;
|
||||
import static java.nio.charset.StandardCharsets.ISO_8859_1;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* Utility class for string encoding and decoding.
|
||||
*/
|
||||
@ -72,23 +80,13 @@ class StringCoding {
|
||||
|
||||
// Trim the given byte array to the given length
|
||||
//
|
||||
private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) {
|
||||
private static byte[] safeTrim(byte[] ba, int len, boolean isTrusted) {
|
||||
if (len == ba.length && (isTrusted || System.getSecurityManager() == null))
|
||||
return ba;
|
||||
else
|
||||
return Arrays.copyOf(ba, len);
|
||||
}
|
||||
|
||||
// Trim the given char array to the given length
|
||||
//
|
||||
private static char[] safeTrim(char[] ca, int len,
|
||||
Charset cs, boolean isTrusted) {
|
||||
if (len == ca.length && (isTrusted || System.getSecurityManager() == null))
|
||||
return ca;
|
||||
else
|
||||
return Arrays.copyOf(ca, len);
|
||||
}
|
||||
|
||||
private static int scale(int len, float expansionFactor) {
|
||||
// We need to perform double, not float, arithmetic; otherwise
|
||||
// we lose low order bits when len is larger than 2**24.
|
||||
@ -117,21 +115,64 @@ class StringCoding {
|
||||
}
|
||||
}
|
||||
|
||||
static class Result {
|
||||
byte[] value;
|
||||
byte coder;
|
||||
|
||||
Result with() {
|
||||
coder = COMPACT_STRINGS ? LATIN1 : UTF16;
|
||||
value = new byte[0];
|
||||
return this;
|
||||
}
|
||||
|
||||
Result with(char[] val, int off, int len) {
|
||||
if (String.COMPACT_STRINGS) {
|
||||
byte[] bs = StringUTF16.compress(val, off, len);
|
||||
if (bs != null) {
|
||||
value = bs;
|
||||
coder = LATIN1;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
coder = UTF16;
|
||||
value = StringUTF16.toBytes(val, off, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
Result with(byte[] val, byte coder) {
|
||||
this.coder = coder;
|
||||
value = val;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static boolean hasNegatives(byte[] ba, int off, int len) {
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (ba[i] < 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -- Decoding --
|
||||
private static class StringDecoder {
|
||||
static class StringDecoder {
|
||||
private final String requestedCharsetName;
|
||||
private final Charset cs;
|
||||
private final boolean isASCIICompatible;
|
||||
private final CharsetDecoder cd;
|
||||
private final boolean isTrusted;
|
||||
protected final Result result;
|
||||
|
||||
private StringDecoder(Charset cs, String rcn) {
|
||||
StringDecoder(Charset cs, String rcn) {
|
||||
this.requestedCharsetName = rcn;
|
||||
this.cs = cs;
|
||||
this.cd = cs.newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
this.isTrusted = (cs.getClass().getClassLoader0() == null);
|
||||
this.result = new Result();
|
||||
this.isASCIICompatible = (cd instanceof ArrayDecoder) &&
|
||||
((ArrayDecoder)cd).isASCIICompatible();
|
||||
}
|
||||
|
||||
String charsetName() {
|
||||
@ -144,36 +185,58 @@ class StringCoding {
|
||||
return requestedCharsetName;
|
||||
}
|
||||
|
||||
char[] decode(byte[] ba, int off, int len) {
|
||||
Result decode(byte[] ba, int off, int len) {
|
||||
if (len == 0) {
|
||||
return result.with();
|
||||
}
|
||||
// fastpath for ascii compatible
|
||||
if (isASCIICompatible && !hasNegatives(ba, off, len)) {
|
||||
if (COMPACT_STRINGS) {
|
||||
return result.with(Arrays.copyOfRange(ba, off, off + len),
|
||||
LATIN1);
|
||||
} else {
|
||||
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
|
||||
}
|
||||
}
|
||||
int en = scale(len, cd.maxCharsPerByte());
|
||||
char[] ca = new char[en];
|
||||
if (len == 0)
|
||||
return ca;
|
||||
if (cd instanceof ArrayDecoder) {
|
||||
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
|
||||
return safeTrim(ca, clen, cs, isTrusted);
|
||||
return result.with(ca, 0, clen);
|
||||
}
|
||||
cd.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
try {
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return result.with(ca, 0, cb.position());
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringDecoder8859_1 extends StringDecoder {
|
||||
StringDecoder8859_1(Charset cs, String rcn) {
|
||||
super(cs, rcn);
|
||||
}
|
||||
Result decode(byte[] ba, int off, int len) {
|
||||
if (COMPACT_STRINGS) {
|
||||
return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1);
|
||||
} else {
|
||||
cd.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
try {
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return safeTrim(ca, cb.position(), cs, isTrusted);
|
||||
return result.with(StringLatin1.inflate(ba, off, len), UTF16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char[] decode(String charsetName, byte[] ba, int off, int len)
|
||||
static Result decode(String charsetName, byte[] ba, int off, int len)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
StringDecoder sd = deref(decoder);
|
||||
@ -183,8 +246,15 @@ class StringCoding {
|
||||
sd = null;
|
||||
try {
|
||||
Charset cs = lookupCharset(csn);
|
||||
if (cs != null)
|
||||
sd = new StringDecoder(cs, csn);
|
||||
if (cs != null) {
|
||||
if (cs == UTF_8) {
|
||||
sd = new StringDecoderUTF8(cs, csn);
|
||||
} else if (cs == ISO_8859_1) {
|
||||
sd = new StringDecoder8859_1(cs, csn);
|
||||
} else {
|
||||
sd = new StringDecoder(cs, csn);
|
||||
}
|
||||
}
|
||||
} catch (IllegalCharsetNameException x) {}
|
||||
if (sd == null)
|
||||
throw new UnsupportedEncodingException(csn);
|
||||
@ -193,7 +263,7 @@ class StringCoding {
|
||||
return sd.decode(ba, off, len);
|
||||
}
|
||||
|
||||
static char[] decode(Charset cs, byte[] ba, int off, int len) {
|
||||
static Result decode(Charset cs, byte[] ba, int off, int len) {
|
||||
// (1)We never cache the "external" cs, the only benefit of creating
|
||||
// an additional StringDe/Encoder object to wrap it is to share the
|
||||
// de/encode() method. These SD/E objects are short-lived, the young-gen
|
||||
@ -210,44 +280,57 @@ class StringCoding {
|
||||
// check (... && (isTrusted || SM == null || getClassLoader0())) in trim
|
||||
// but it then can be argued that the SM is null when the operation
|
||||
// is started...
|
||||
if (cs == UTF_8) {
|
||||
return StringDecoderUTF8.decode(ba, off, len, new Result());
|
||||
}
|
||||
CharsetDecoder cd = cs.newDecoder();
|
||||
// ascii fastpath
|
||||
if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) &&
|
||||
((ArrayDecoder)cd).isASCIICompatible() &&
|
||||
!hasNegatives(ba, off, len))) {
|
||||
if (COMPACT_STRINGS) {
|
||||
return new Result().with(Arrays.copyOfRange(ba, off, off + len),
|
||||
LATIN1);
|
||||
} else {
|
||||
return new Result().with(StringLatin1.inflate(ba, off, len), UTF16);
|
||||
}
|
||||
}
|
||||
int en = scale(len, cd.maxCharsPerByte());
|
||||
char[] ca = new char[en];
|
||||
if (len == 0)
|
||||
return ca;
|
||||
boolean isTrusted = false;
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
|
||||
ba = Arrays.copyOfRange(ba, off, off + len);
|
||||
off = 0;
|
||||
}
|
||||
if (len == 0) {
|
||||
return new Result().with();
|
||||
}
|
||||
if (System.getSecurityManager() != null &&
|
||||
cs.getClass().getClassLoader0() != null) {
|
||||
ba = Arrays.copyOfRange(ba, off, off + len);
|
||||
off = 0;
|
||||
}
|
||||
cd.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE)
|
||||
.reset();
|
||||
|
||||
char[] ca = new char[en];
|
||||
if (cd instanceof ArrayDecoder) {
|
||||
int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
|
||||
return safeTrim(ca, clen, cs, isTrusted);
|
||||
} else {
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
try {
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return safeTrim(ca, cb.position(), cs, isTrusted);
|
||||
return new Result().with(ca, 0, clen);
|
||||
}
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
|
||||
CharBuffer cb = CharBuffer.wrap(ca);
|
||||
try {
|
||||
CoderResult cr = cd.decode(bb, cb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = cd.flush(cb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return new Result().with(ca, 0, cb.position());
|
||||
}
|
||||
|
||||
static char[] decode(byte[] ba, int off, int len) {
|
||||
static Result decode(byte[] ba, int off, int len) {
|
||||
String csn = Charset.defaultCharset().name();
|
||||
try {
|
||||
// use charset name decode() variant which provides caching.
|
||||
@ -273,6 +356,7 @@ class StringCoding {
|
||||
private static class StringEncoder {
|
||||
private Charset cs;
|
||||
private CharsetEncoder ce;
|
||||
private final boolean isASCIICompatible;
|
||||
private final String requestedCharsetName;
|
||||
private final boolean isTrusted;
|
||||
|
||||
@ -283,6 +367,8 @@ class StringCoding {
|
||||
.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
this.isTrusted = (cs.getClass().getClassLoader0() == null);
|
||||
this.isASCIICompatible = (ce instanceof ArrayEncoder) &&
|
||||
((ArrayEncoder)ce).isASCIICompatible();
|
||||
}
|
||||
|
||||
String charsetName() {
|
||||
@ -295,36 +381,186 @@ class StringCoding {
|
||||
return requestedCharsetName;
|
||||
}
|
||||
|
||||
byte[] encode(char[] ca, int off, int len) {
|
||||
byte[] encode(byte coder, byte[] val) {
|
||||
// fastpath for ascii compatible
|
||||
if (coder == LATIN1 && isASCIICompatible &&
|
||||
!hasNegatives(val, 0, val.length)) {
|
||||
return Arrays.copyOf(val, val.length);
|
||||
}
|
||||
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
|
||||
int en = scale(len, ce.maxBytesPerChar());
|
||||
byte[] ba = new byte[en];
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return ba;
|
||||
if (ce instanceof ArrayEncoder) {
|
||||
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
|
||||
return safeTrim(ba, blen, cs, isTrusted);
|
||||
} else {
|
||||
ce.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca, off, len);
|
||||
try {
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return safeTrim(ba, bb.position(), cs, isTrusted);
|
||||
}
|
||||
if (ce instanceof ArrayEncoder) {
|
||||
if (!isTrusted) {
|
||||
val = Arrays.copyOf(val, val.length);
|
||||
}
|
||||
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
|
||||
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
|
||||
if (blen != -1) {
|
||||
return safeTrim(ba, blen, isTrusted);
|
||||
}
|
||||
}
|
||||
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
|
||||
: StringUTF16.toChars(val);
|
||||
ce.reset();
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
|
||||
try {
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
// Substitution is always enabled,
|
||||
// so this shouldn't happen
|
||||
throw new Error(x);
|
||||
}
|
||||
return safeTrim(ba, bb.position(), isTrusted);
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] encode(String charsetName, char[] ca, int off, int len)
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int implEncodeISOArray(byte[] sa, int sp,
|
||||
byte[] da, int dp, int len) {
|
||||
int i = 0;
|
||||
for (; i < len; i++) {
|
||||
char c = StringUTF16.getChar(sa, sp++);
|
||||
if (c > '\u00FF')
|
||||
break;
|
||||
da[dp++] = (byte)c;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static byte[] encode8859_1(byte coder, byte[] val) {
|
||||
if (coder == LATIN1) {
|
||||
return Arrays.copyOf(val, val.length);
|
||||
}
|
||||
int len = val.length >> 1;
|
||||
byte[] dst = new byte[len];
|
||||
int dp = 0;
|
||||
int sp = 0;
|
||||
int sl = len;
|
||||
while (sp < sl) {
|
||||
int ret = implEncodeISOArray(val, sp, dst, dp, len);
|
||||
sp = sp + ret;
|
||||
dp = dp + ret;
|
||||
if (ret != len) {
|
||||
char c = StringUTF16.getChar(val, sp++);
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(StringUTF16.getChar(val, sp))) {
|
||||
sp++;
|
||||
}
|
||||
dst[dp++] = '?';
|
||||
len = sl - sp;
|
||||
}
|
||||
}
|
||||
if (dp == dst.length) {
|
||||
return dst;
|
||||
}
|
||||
return Arrays.copyOf(dst, dp);
|
||||
}
|
||||
|
||||
static byte[] encodeASCII(byte coder, byte[] val) {
|
||||
if (coder == LATIN1) {
|
||||
byte[] dst = new byte[val.length];
|
||||
for (int i = 0; i < val.length; i++) {
|
||||
if (val[i] < 0) {
|
||||
dst[i] = '?';
|
||||
} else {
|
||||
dst[i] = val[i];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
int len = val.length >> 1;
|
||||
byte[] dst = new byte[len];
|
||||
int dp = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = StringUTF16.getChar(val, i);
|
||||
if (c < 0x80) {
|
||||
dst[dp++] = (byte)c;
|
||||
continue;
|
||||
}
|
||||
if (Character.isHighSurrogate(c) && i + 1 < len &&
|
||||
Character.isLowSurrogate(StringUTF16.getChar(val, i + 1))) {
|
||||
i++;
|
||||
}
|
||||
dst[dp++] = '?';
|
||||
}
|
||||
if (len == dp) {
|
||||
return dst;
|
||||
}
|
||||
return Arrays.copyOf(dst, dp);
|
||||
}
|
||||
|
||||
static byte[] encodeUTF8(byte coder, byte[] val) {
|
||||
int dp = 0;
|
||||
byte[] dst;
|
||||
if (coder == LATIN1) {
|
||||
dst = new byte[val.length << 1];
|
||||
for (int sp = 0; sp < val.length; sp++) {
|
||||
byte c = val[sp];
|
||||
if (c < 0) {
|
||||
dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6));
|
||||
dst[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else {
|
||||
dst[dp++] = c;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int sp = 0;
|
||||
int sl = val.length >> 1;
|
||||
dst = new byte[sl * 3];
|
||||
char c;
|
||||
while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') {
|
||||
// ascii fast loop;
|
||||
dst[dp++] = (byte)c;
|
||||
sp++;
|
||||
}
|
||||
while (sp < sl) {
|
||||
c = StringUTF16.getChar(val, sp++);
|
||||
if (c < 0x80) {
|
||||
dst[dp++] = (byte)c;
|
||||
} else if (c < 0x800) {
|
||||
dst[dp++] = (byte)(0xc0 | (c >> 6));
|
||||
dst[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
} else if (Character.isSurrogate(c)) {
|
||||
int uc = -1;
|
||||
char c2;
|
||||
if (Character.isHighSurrogate(c) && sp < sl &&
|
||||
Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) {
|
||||
uc = Character.toCodePoint(c, c2);
|
||||
}
|
||||
if (uc < 0) {
|
||||
dst[dp++] = '?';
|
||||
} else {
|
||||
dst[dp++] = (byte)(0xf0 | ((uc >> 18)));
|
||||
dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
|
||||
dst[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
|
||||
dst[dp++] = (byte)(0x80 | (uc & 0x3f));
|
||||
sp++; // 2 chars
|
||||
}
|
||||
} else {
|
||||
// 3 bytes, 16 bits
|
||||
dst[dp++] = (byte)(0xe0 | ((c >> 12)));
|
||||
dst[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
|
||||
dst[dp++] = (byte)(0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dp == dst.length) {
|
||||
return dst;
|
||||
}
|
||||
return Arrays.copyOf(dst, dp);
|
||||
}
|
||||
|
||||
static byte[] encode(String charsetName, byte coder, byte[] val)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
StringEncoder se = deref(encoder);
|
||||
@ -334,62 +570,88 @@ class StringCoding {
|
||||
se = null;
|
||||
try {
|
||||
Charset cs = lookupCharset(csn);
|
||||
if (cs != null)
|
||||
if (cs != null) {
|
||||
if (cs == UTF_8) {
|
||||
return encodeUTF8(coder, val);
|
||||
} else if (cs == ISO_8859_1) {
|
||||
return encode8859_1(coder, val);
|
||||
} else if (cs == US_ASCII) {
|
||||
return encodeASCII(coder, val);
|
||||
}
|
||||
se = new StringEncoder(cs, csn);
|
||||
}
|
||||
} catch (IllegalCharsetNameException x) {}
|
||||
if (se == null)
|
||||
if (se == null) {
|
||||
throw new UnsupportedEncodingException (csn);
|
||||
}
|
||||
set(encoder, se);
|
||||
}
|
||||
return se.encode(ca, off, len);
|
||||
return se.encode(coder, val);
|
||||
}
|
||||
|
||||
static byte[] encode(Charset cs, char[] ca, int off, int len) {
|
||||
static byte[] encode(Charset cs, byte coder, byte[] val) {
|
||||
if (cs == UTF_8) {
|
||||
return encodeUTF8(coder, val);
|
||||
} else if (cs == ISO_8859_1) {
|
||||
return encode8859_1(coder, val);
|
||||
} else if (cs == US_ASCII) {
|
||||
return encodeASCII(coder, val);
|
||||
}
|
||||
CharsetEncoder ce = cs.newEncoder();
|
||||
// fastpath for ascii compatible
|
||||
if (coder == LATIN1 && (((ce instanceof ArrayEncoder) &&
|
||||
((ArrayEncoder)ce).isASCIICompatible() &&
|
||||
!hasNegatives(val, 0, val.length)))) {
|
||||
return Arrays.copyOf(val, val.length);
|
||||
}
|
||||
int len = val.length >> coder; // assume LATIN1=0/UTF16=1;
|
||||
int en = scale(len, ce.maxBytesPerChar());
|
||||
byte[] ba = new byte[en];
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
return ba;
|
||||
boolean isTrusted = false;
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
|
||||
ca = Arrays.copyOfRange(ca, off, off + len);
|
||||
off = 0;
|
||||
}
|
||||
}
|
||||
boolean isTrusted = System.getSecurityManager() == null ||
|
||||
cs.getClass().getClassLoader0() == null;
|
||||
ce.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE)
|
||||
.reset();
|
||||
if (ce instanceof ArrayEncoder) {
|
||||
int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
|
||||
return safeTrim(ba, blen, cs, isTrusted);
|
||||
} else {
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca, off, len);
|
||||
try {
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
throw new Error(x);
|
||||
if (!isTrusted) {
|
||||
val = Arrays.copyOf(val, val.length);
|
||||
}
|
||||
int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
|
||||
: ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
|
||||
if (blen != -1) {
|
||||
return safeTrim(ba, blen, isTrusted);
|
||||
}
|
||||
return safeTrim(ba, bb.position(), cs, isTrusted);
|
||||
}
|
||||
char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
|
||||
: StringUTF16.toChars(val);
|
||||
ByteBuffer bb = ByteBuffer.wrap(ba);
|
||||
CharBuffer cb = CharBuffer.wrap(ca, 0, len);
|
||||
try {
|
||||
CoderResult cr = ce.encode(cb, bb, true);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
cr = ce.flush(bb);
|
||||
if (!cr.isUnderflow())
|
||||
cr.throwException();
|
||||
} catch (CharacterCodingException x) {
|
||||
throw new Error(x);
|
||||
}
|
||||
return safeTrim(ba, bb.position(), isTrusted);
|
||||
}
|
||||
|
||||
static byte[] encode(char[] ca, int off, int len) {
|
||||
static byte[] encode(byte coder, byte[] val) {
|
||||
String csn = Charset.defaultCharset().name();
|
||||
try {
|
||||
// use charset name encode() variant which provides caching.
|
||||
return encode(csn, ca, off, len);
|
||||
return encode(csn, coder, val);
|
||||
} catch (UnsupportedEncodingException x) {
|
||||
warnUnsupportedCharset(csn);
|
||||
}
|
||||
try {
|
||||
return encode("ISO-8859-1", ca, off, len);
|
||||
return encode("ISO-8859-1", coder, val);
|
||||
} catch (UnsupportedEncodingException x) {
|
||||
// If this code is hit during VM initialization, MessageUtils is
|
||||
// the only way we will be able to get any kind of error message.
|
||||
|
235
jdk/src/java.base/share/classes/java/lang/StringDecoderUTF8.java
Normal file
235
jdk/src/java.base/share/classes/java/lang/StringDecoderUTF8.java
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.UTF16;
|
||||
import static java.lang.String.COMPACT_STRINGS;
|
||||
import static java.lang.Character.isSurrogate;
|
||||
import static java.lang.Character.highSurrogate;
|
||||
import static java.lang.Character.lowSurrogate;
|
||||
import static java.lang.Character.isSupplementaryCodePoint;
|
||||
import static java.lang.StringUTF16.putChar;
|
||||
|
||||
class StringDecoderUTF8 extends StringCoding.StringDecoder {
|
||||
|
||||
StringDecoderUTF8(Charset cs, String rcn) {
|
||||
super(cs, rcn);
|
||||
}
|
||||
|
||||
private static boolean isNotContinuation(int b) {
|
||||
return (b & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed3(int b1, int b2, int b3) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed3_2(int b1, int b2) {
|
||||
return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed4(int b2, int b3, int b4) {
|
||||
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
|
||||
(b4 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed4_2(int b1, int b2) {
|
||||
return (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
|
||||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
|
||||
(b2 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
private static boolean isMalformed4_3(int b3) {
|
||||
return (b3 & 0xc0) != 0x80;
|
||||
}
|
||||
|
||||
// for nb == 3/4
|
||||
private static int malformedN(byte[] src, int sp, int nb) {
|
||||
if (nb == 3) {
|
||||
int b1 = src[sp++];
|
||||
int b2 = src[sp++]; // no need to lookup b3
|
||||
return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
|
||||
isNotContinuation(b2)) ? 1 : 2;
|
||||
} else if (nb == 4) { // we don't care the speed here
|
||||
int b1 = src[sp++] & 0xff;
|
||||
int b2 = src[sp++] & 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
(b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
|
||||
(b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
|
||||
isNotContinuation(b2))
|
||||
return 1;
|
||||
if (isNotContinuation(src[sp++]))
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
assert false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static char repl = '\ufffd';
|
||||
|
||||
StringCoding.Result decode(byte[] src, int sp, int len) {
|
||||
return decode(src, sp, len, result);
|
||||
}
|
||||
|
||||
static StringCoding.Result decode(byte[] src, int sp, int len,
|
||||
StringCoding.Result ret) {
|
||||
int sl = sp + len;
|
||||
byte[] dst = new byte[len];
|
||||
int dp = 0;
|
||||
if (COMPACT_STRINGS) { // Latin1 only loop
|
||||
while (sp < sl) {
|
||||
int b1 = src[sp];
|
||||
if (b1 >= 0) {
|
||||
dst[dp++] = (byte)b1;
|
||||
sp++;
|
||||
continue;
|
||||
}
|
||||
if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) &&
|
||||
sp + 1 < sl) {
|
||||
int b2 = src[sp + 1];
|
||||
if (!isNotContinuation(b2)) {
|
||||
dst[dp++] = (byte)(((b1 << 6) ^ b2)^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0)));
|
||||
sp += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// anything not a latin1, including the repl
|
||||
// we have to go with the utf16
|
||||
break;
|
||||
}
|
||||
if (sp == sl) {
|
||||
if (dp != dst.length) {
|
||||
dst = Arrays.copyOf(dst, dp);
|
||||
}
|
||||
return ret.with(dst, LATIN1);
|
||||
}
|
||||
}
|
||||
if (dp == 0) {
|
||||
dst = new byte[len << 1];
|
||||
} else {
|
||||
byte[] buf = new byte[len << 1];
|
||||
StringLatin1.inflate(dst, 0, buf, 0, dp);
|
||||
dst = buf;
|
||||
}
|
||||
while (sp < sl) {
|
||||
int b1 = src[sp++];
|
||||
if (b1 >= 0) {
|
||||
putChar(dst, dp++, (char) b1);
|
||||
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
|
||||
if (sp < sl) {
|
||||
int b2 = src[sp++];
|
||||
if (isNotContinuation(b2)) {
|
||||
putChar(dst, dp++, repl);
|
||||
sp--;
|
||||
} else {
|
||||
putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^
|
||||
(((byte) 0xC0 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
putChar(dst, dp++, repl);
|
||||
break;
|
||||
} else if ((b1 >> 4) == -2) {
|
||||
if (sp + 1 < sl) {
|
||||
int b2 = src[sp++];
|
||||
int b3 = src[sp++];
|
||||
if (isMalformed3(b1, b2, b3)) {
|
||||
putChar(dst, dp++, repl);
|
||||
sp -= 3;
|
||||
sp += malformedN(src, sp, 3);
|
||||
} else {
|
||||
char c = (char)((b1 << 12) ^
|
||||
(b2 << 6) ^
|
||||
(b3 ^
|
||||
(((byte) 0xE0 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
putChar(dst, dp++, isSurrogate(c) ? repl : c);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sp < sl && isMalformed3_2(b1, src[sp])) {
|
||||
putChar(dst, dp++, repl);
|
||||
continue;
|
||||
}
|
||||
putChar(dst, dp++, repl);
|
||||
break;
|
||||
} else if ((b1 >> 3) == -2) {
|
||||
if (sp + 2 < sl) {
|
||||
int b2 = src[sp++];
|
||||
int b3 = src[sp++];
|
||||
int b4 = src[sp++];
|
||||
int uc = ((b1 << 18) ^
|
||||
(b2 << 12) ^
|
||||
(b3 << 6) ^
|
||||
(b4 ^
|
||||
(((byte) 0xF0 << 18) ^
|
||||
((byte) 0x80 << 12) ^
|
||||
((byte) 0x80 << 6) ^
|
||||
((byte) 0x80 << 0))));
|
||||
if (isMalformed4(b2, b3, b4) ||
|
||||
!isSupplementaryCodePoint(uc)) { // shortest form check
|
||||
putChar(dst, dp++, repl);
|
||||
sp -= 4;
|
||||
sp += malformedN(src, sp, 4);
|
||||
} else {
|
||||
putChar(dst, dp++, highSurrogate(uc));
|
||||
putChar(dst, dp++, lowSurrogate(uc));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
b1 &= 0xff;
|
||||
if (b1 > 0xf4 ||
|
||||
sp < sl && isMalformed4_2(b1, src[sp] & 0xff)) {
|
||||
putChar(dst, dp++, repl);
|
||||
continue;
|
||||
}
|
||||
sp++;
|
||||
putChar(dst, dp++, repl);
|
||||
if (sp < sl && isMalformed4_3(src[sp])) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
putChar(dst, dp++, repl);
|
||||
}
|
||||
}
|
||||
if (dp != len) {
|
||||
dst = Arrays.copyOf(dst, dp << 1);
|
||||
}
|
||||
return ret.with(dst, UTF16);
|
||||
}
|
||||
}
|
600
jdk/src/java.base/share/classes/java/lang/StringLatin1.java
Normal file
600
jdk/src/java.base/share/classes/java/lang/StringLatin1.java
Normal file
@ -0,0 +1,600 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.stream.IntStream;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.UTF16;
|
||||
import static java.lang.String.checkOffset;
|
||||
|
||||
final class StringLatin1 {
|
||||
|
||||
public static char charAt(byte[] value, int index) {
|
||||
if (index < 0 || index >= value.length) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return (char)(value[index] & 0xff);
|
||||
}
|
||||
|
||||
public static boolean canEncode(int cp) {
|
||||
return cp >>> 8 == 0;
|
||||
}
|
||||
|
||||
public static int length(byte[] value) {
|
||||
return value.length;
|
||||
}
|
||||
|
||||
public static int codePointAt(byte[] value, int index, int end) {
|
||||
return value[index] & 0xff;
|
||||
}
|
||||
|
||||
public static int codePointBefore(byte[] value, int index) {
|
||||
return value[index - 1] & 0xff;
|
||||
}
|
||||
|
||||
public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
|
||||
return endIndex - beginIndex;
|
||||
}
|
||||
|
||||
public static char[] toChars(byte[] value) {
|
||||
char[] dst = new char[value.length];
|
||||
inflate(value, 0, dst, 0, value.length);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static byte[] inflate(byte[] value, int off, int len) {
|
||||
byte[] ret = StringUTF16.newBytesFor(len);
|
||||
inflate(value, off, ret, 0, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
|
||||
inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
}
|
||||
|
||||
public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
|
||||
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static boolean equals(byte[] value, byte[] other) {
|
||||
if (value.length == other.length) {
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
if (value[i] != other[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int compareTo(byte[] value, byte[] other) {
|
||||
int len1 = value.length;
|
||||
int len2 = other.length;
|
||||
int lim = Math.min(len1, len2);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
if (value[k] != other[k]) {
|
||||
return getChar(value, k) - getChar(other, k);
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int compareToUTF16(byte[] value, byte[] other) {
|
||||
int len1 = length(value);
|
||||
int len2 = StringUTF16.length(other);
|
||||
int lim = Math.min(len1, len2);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
char c1 = getChar(value, k);
|
||||
char c2 = StringUTF16.getChar(other, k);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] value) {
|
||||
int h = 0;
|
||||
for (byte v : value) {
|
||||
h = 31 * h + (v & 0xff);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public static int indexOf(byte[] value, int ch, int fromIndex) {
|
||||
if (!canEncode(ch)) {
|
||||
return -1;
|
||||
}
|
||||
int max = value.length;
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
} else if (fromIndex >= max) {
|
||||
// Note: fromIndex might be near -1>>>1.
|
||||
return -1;
|
||||
}
|
||||
byte c = (byte)ch;
|
||||
for (int i = fromIndex; i < max; i++) {
|
||||
if (value[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOf(byte[] value, byte[] str) {
|
||||
if (str.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.length == 0) {
|
||||
return -1;
|
||||
}
|
||||
return indexOf(value, value.length, str, str.length, 0);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
|
||||
byte first = str[0];
|
||||
int max = (valueCount - strCount);
|
||||
for (int i = fromIndex; i <= max; i++) {
|
||||
// Look for first character.
|
||||
if (value[i] != first) {
|
||||
while (++i <= max && value[i] != first);
|
||||
}
|
||||
// Found first character, now look at the rest of value
|
||||
if (i <= max) {
|
||||
int j = i + 1;
|
||||
int end = j + strCount - 1;
|
||||
for (int k = 1; j < end && value[j] == str[k]; j++, k++);
|
||||
if (j == end) {
|
||||
// Found whole string.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int lastIndexOf(byte[] src, int srcCount,
|
||||
byte[] tgt, int tgtCount, int fromIndex) {
|
||||
int min = tgtCount - 1;
|
||||
int i = min + fromIndex;
|
||||
int strLastIndex = tgtCount - 1;
|
||||
char strLastChar = (char)(tgt[strLastIndex] & 0xff);
|
||||
|
||||
startSearchForLastChar:
|
||||
while (true) {
|
||||
while (i >= min && (src[i] & 0xff) != strLastChar) {
|
||||
i--;
|
||||
}
|
||||
if (i < min) {
|
||||
return -1;
|
||||
}
|
||||
int j = i - 1;
|
||||
int start = j - strLastIndex;
|
||||
int k = strLastIndex - 1;
|
||||
while (j > start) {
|
||||
if ((src[j--] & 0xff) != (tgt[k--] & 0xff)) {
|
||||
i--;
|
||||
continue startSearchForLastChar;
|
||||
}
|
||||
}
|
||||
return start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int lastIndexOf(final byte[] value, int ch, int fromIndex) {
|
||||
if (!canEncode(ch)) {
|
||||
return -1;
|
||||
}
|
||||
int off = Math.min(fromIndex, value.length - 1);
|
||||
for (; off >= 0; off--) {
|
||||
if (value[off] == (byte)ch) {
|
||||
return off;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String replace(byte[] value, char oldChar, char newChar) {
|
||||
if (canEncode(oldChar)) {
|
||||
int len = value.length;
|
||||
int i = -1;
|
||||
while (++i < len) {
|
||||
if (value[i] == (byte)oldChar) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < len) {
|
||||
if (canEncode(newChar)) {
|
||||
byte buf[] = new byte[len];
|
||||
for (int j = 0; j < i; j++) { // TBD arraycopy?
|
||||
buf[j] = value[j];
|
||||
}
|
||||
while (i < len) {
|
||||
byte c = value[i];
|
||||
buf[i] = (c == (byte)oldChar) ? (byte)newChar : c;
|
||||
i++;
|
||||
}
|
||||
return new String(buf, LATIN1);
|
||||
} else {
|
||||
byte[] buf = StringUTF16.newBytesFor(len);
|
||||
// inflate from latin1 to UTF16
|
||||
inflate(value, 0, buf, 0, i);
|
||||
while (i < len) {
|
||||
char c = (char)(value[i] & 0xff);
|
||||
StringUTF16.putChar(buf, i, (c == oldChar) ? newChar : c);
|
||||
i++;
|
||||
}
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null; // for string to return this;
|
||||
}
|
||||
|
||||
// case insensitive
|
||||
public static boolean regionMatchesCI(byte[] value, int toffset,
|
||||
byte[] other, int ooffset, int len) {
|
||||
int last = toffset + len;
|
||||
while (toffset < last) {
|
||||
char c1 = (char)(value[toffset++] & 0xff);
|
||||
char c2 = (char)(other[ooffset++] & 0xff);
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2) {
|
||||
continue;
|
||||
}
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean regionMatchesCI_UTF16(byte[] value, int toffset,
|
||||
byte[] other, int ooffset, int len) {
|
||||
int last = toffset + len;
|
||||
while (toffset < last) {
|
||||
char c1 = (char)(value[toffset++] & 0xff);
|
||||
char c2 = StringUTF16.getChar(other, ooffset++);
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2) {
|
||||
continue;
|
||||
}
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String toLowerCase(String str, byte[] value, Locale locale) {
|
||||
if (locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
int first;
|
||||
final int len = value.length;
|
||||
// Now check if there are any characters that need to be changed, or are surrogate
|
||||
for (first = 0 ; first < len; first++) {
|
||||
int cp = value[first] & 0xff;
|
||||
if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first == len)
|
||||
return str;
|
||||
String lang = locale.getLanguage();
|
||||
if (lang == "tr" || lang == "az" || lang == "lt") {
|
||||
return toLowerCaseEx(str, value, first, locale, true);
|
||||
}
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(value, 0, result, 0, first); // Just copy the first few
|
||||
// lowerCase characters.
|
||||
for (int i = first; i < len; i++) {
|
||||
int cp = value[i] & 0xff;
|
||||
cp = Character.toLowerCase(cp);
|
||||
if (!canEncode(cp)) { // not a latin1 character
|
||||
return toLowerCaseEx(str, value, first, locale, false);
|
||||
}
|
||||
result[i] = (byte)cp;
|
||||
}
|
||||
return new String(result, LATIN1);
|
||||
}
|
||||
|
||||
private static String toLowerCaseEx(String str, byte[] value,
|
||||
int first, Locale locale, boolean localeDependent)
|
||||
{
|
||||
byte[] result = StringUTF16.newBytesFor(value.length);
|
||||
int resultOffset = 0;
|
||||
for (int i = 0; i < first; i++) {
|
||||
StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
|
||||
}
|
||||
for (int i = first; i < value.length; i++) {
|
||||
int srcChar = value[i] & 0xff;
|
||||
int lowerChar;
|
||||
char[] lowerCharArray;
|
||||
if (localeDependent) {
|
||||
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
|
||||
} else {
|
||||
lowerChar = Character.toLowerCase(srcChar);
|
||||
}
|
||||
if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp
|
||||
StringUTF16.putChar(result, resultOffset++, lowerChar);
|
||||
} else {
|
||||
if (lowerChar == Character.ERROR) {
|
||||
lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
|
||||
} else {
|
||||
lowerCharArray = Character.toChars(lowerChar);
|
||||
}
|
||||
/* Grow result if needed */
|
||||
int mapLen = lowerCharArray.length;
|
||||
if (mapLen > 1) {
|
||||
byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
|
||||
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
|
||||
result = result2;
|
||||
}
|
||||
for (int x = 0; x < mapLen; ++x) {
|
||||
StringUTF16.putChar(result, resultOffset++, lowerCharArray[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return StringUTF16.newString(result, 0, resultOffset);
|
||||
}
|
||||
|
||||
public static String toUpperCase(String str, byte[] value, Locale locale) {
|
||||
if (locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
int first;
|
||||
final int len = value.length;
|
||||
|
||||
// Now check if there are any characters that need to be changed, or are surrogate
|
||||
for (first = 0 ; first < len; first++ ) {
|
||||
int cp = value[first] & 0xff;
|
||||
if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first == len) {
|
||||
return str;
|
||||
}
|
||||
String lang = locale.getLanguage();
|
||||
if (lang == "tr" || lang == "az" || lang == "lt") {
|
||||
return toUpperCaseEx(str, value, first, locale, true);
|
||||
}
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(value, 0, result, 0, first); // Just copy the first few
|
||||
// upperCase characters.
|
||||
for (int i = first; i < len; i++) {
|
||||
int cp = value[i] & 0xff;
|
||||
cp = Character.toUpperCaseEx(cp);
|
||||
if (!canEncode(cp)) { // not a latin1 character
|
||||
return toUpperCaseEx(str, value, first, locale, false);
|
||||
}
|
||||
result[i] = (byte)cp;
|
||||
}
|
||||
return new String(result, LATIN1);
|
||||
}
|
||||
|
||||
private static String toUpperCaseEx(String str, byte[] value,
|
||||
int first, Locale locale, boolean localeDependent)
|
||||
{
|
||||
byte[] result = StringUTF16.newBytesFor(value.length);
|
||||
int resultOffset = 0;
|
||||
for (int i = 0; i < first; i++) {
|
||||
StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
|
||||
}
|
||||
for (int i = first; i < value.length; i++) {
|
||||
int srcChar = value[i] & 0xff;
|
||||
int upperChar;
|
||||
char[] upperCharArray;
|
||||
if (localeDependent) {
|
||||
upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
|
||||
} else {
|
||||
upperChar = Character.toUpperCaseEx(srcChar);
|
||||
}
|
||||
if (Character.isBmpCodePoint(upperChar)) {
|
||||
StringUTF16.putChar(result, resultOffset++, upperChar);
|
||||
} else {
|
||||
if (upperChar == Character.ERROR) {
|
||||
if (localeDependent) {
|
||||
upperCharArray =
|
||||
ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
|
||||
} else {
|
||||
upperCharArray = Character.toUpperCaseCharArray(srcChar);
|
||||
}
|
||||
} else {
|
||||
upperCharArray = Character.toChars(upperChar);
|
||||
}
|
||||
/* Grow result if needed */
|
||||
int mapLen = upperCharArray.length;
|
||||
if (mapLen > 1) {
|
||||
byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
|
||||
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
|
||||
result = result2;
|
||||
}
|
||||
for (int x = 0; x < mapLen; ++x) {
|
||||
StringUTF16.putChar(result, resultOffset++, upperCharArray[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return StringUTF16.newString(result, 0, resultOffset);
|
||||
}
|
||||
|
||||
public static String trim(byte[] value) {
|
||||
int len = value.length;
|
||||
int st = 0;
|
||||
while ((st < len) && ((value[st] & 0xff) <= ' ')) {
|
||||
st++;
|
||||
}
|
||||
while ((st < len) && ((value[len - 1] & 0xff) <= ' ')) {
|
||||
len--;
|
||||
}
|
||||
return ((st > 0) || (len < value.length)) ?
|
||||
newString(value, st, len - st) : null;
|
||||
}
|
||||
|
||||
public static void putChar(byte[] val, int index, int c) {
|
||||
//assert (canEncode(c));
|
||||
val[index] = (byte)(c);
|
||||
}
|
||||
|
||||
public static char getChar(byte[] val, int index) {
|
||||
return (char)(val[index] & 0xff);
|
||||
}
|
||||
|
||||
public static byte[] toBytes(int[] val, int off, int len) {
|
||||
byte[] ret = new byte[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
int cp = val[off++];
|
||||
if (!canEncode(cp)) {
|
||||
return null;
|
||||
}
|
||||
ret[i] = (byte)cp;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(char c) {
|
||||
return new byte[] { (byte)c };
|
||||
}
|
||||
|
||||
public static String newString(byte[] val, int index, int len) {
|
||||
return new String(Arrays.copyOfRange(val, index, index + len),
|
||||
LATIN1);
|
||||
}
|
||||
|
||||
public static void fillNull(byte[] val, int index, int end) {
|
||||
Arrays.fill(val, index, end, (byte)0);
|
||||
}
|
||||
|
||||
// inflatedCopy byte[] -> char[]
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
dst[dstOff++] = (char)(src[srcOff++] & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
// inflatedCopy byte[] -> byte[]
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
StringUTF16.putChar(dst, dstOff++, src[srcOff++] & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
static class CharsSpliterator implements Spliterator.OfInt {
|
||||
private final byte[] array;
|
||||
private int index; // current index, modified on advance/split
|
||||
private final int fence; // one past last index
|
||||
private final int cs;
|
||||
|
||||
CharsSpliterator(byte[] array, int acs) {
|
||||
this(array, 0, array.length, acs);
|
||||
}
|
||||
|
||||
CharsSpliterator(byte[] array, int origin, int fence, int acs) {
|
||||
this.array = array;
|
||||
this.index = origin;
|
||||
this.fence = fence;
|
||||
this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
|
||||
| Spliterator.SUBSIZED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfInt trySplit() {
|
||||
int lo = index, mid = (lo + fence) >>> 1;
|
||||
return (lo >= mid)
|
||||
? null
|
||||
: new CharsSpliterator(array, lo, index = mid, cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(IntConsumer action) {
|
||||
byte[] a; int i, hi; // hoist accesses and checks from loop
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if ((a = array).length >= (hi = fence) &&
|
||||
(i = index) >= 0 && i < (index = hi)) {
|
||||
do { action.accept(a[i] & 0xff); } while (++i < hi);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(IntConsumer action) {
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (index >= 0 && index < fence) {
|
||||
action.accept(array[index++] & 0xff);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() { return (long)(fence - index); }
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return cs;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
|
||||
checkOffset(srcEnd, val.length);
|
||||
getChars(val, srcBegin, srcEnd, dst, dstBegin);
|
||||
}
|
||||
|
||||
public static void inflateSB(byte[] val, byte[] dst, int dstOff, int count) {
|
||||
checkOffset(count, val.length);
|
||||
checkOffset(dstOff + count, dst.length >> 1); // dst is utf16
|
||||
inflate(val, 0, dst, dstOff, count);
|
||||
}
|
||||
}
|
971
jdk/src/java.base/share/classes/java/lang/StringUTF16.java
Normal file
971
jdk/src/java.base/share/classes/java/lang/StringUTF16.java
Normal file
@ -0,0 +1,971 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.lang;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.IntConsumer;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import static java.lang.String.UTF16;
|
||||
import static java.lang.String.LATIN1;
|
||||
import static java.lang.String.checkIndex;
|
||||
import static java.lang.String.checkOffset;
|
||||
|
||||
final class StringUTF16 {
|
||||
|
||||
public static byte[] newBytesFor(int len) {
|
||||
if (len < 0) {
|
||||
throw new NegativeArraySizeException();
|
||||
}
|
||||
if (len > MAX_LENGTH) {
|
||||
throw new OutOfMemoryError("UTF16 String size is " + len +
|
||||
", should be less than " + MAX_LENGTH);
|
||||
}
|
||||
return new byte[len << 1];
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static void putChar(byte[] val, int index, int c) {
|
||||
index <<= 1;
|
||||
val[index++] = (byte)(c >> HI_BYTE_SHIFT);
|
||||
val[index] = (byte)(c >> LO_BYTE_SHIFT);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static char getChar(byte[] val, int index) {
|
||||
index <<= 1;
|
||||
return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
|
||||
((val[index] & 0xff) << LO_BYTE_SHIFT));
|
||||
}
|
||||
|
||||
public static char charAt(byte[] value, int index) {
|
||||
if (index < 0 || index >= value.length >> 1) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
}
|
||||
return getChar(value, index);
|
||||
}
|
||||
|
||||
public static int length(byte[] value) {
|
||||
return value.length >> 1;
|
||||
}
|
||||
|
||||
public static int codePointAt(byte[] value, int index, int end) {
|
||||
char c1 = getChar(value, index);
|
||||
if (Character.isHighSurrogate(c1) && ++index < end) {
|
||||
char c2 = getChar(value, index);
|
||||
if (Character.isLowSurrogate(c2)) {
|
||||
return Character.toCodePoint(c1, c2);
|
||||
}
|
||||
}
|
||||
return c1;
|
||||
}
|
||||
|
||||
public static int codePointBefore(byte[] value, int index) {
|
||||
char c2 = getChar(value, --index);
|
||||
if (Character.isLowSurrogate(c2) && index > 0) {
|
||||
char c1 = getChar(value, --index);
|
||||
if (Character.isHighSurrogate(c1)) {
|
||||
return Character.toCodePoint(c1, c2);
|
||||
}
|
||||
}
|
||||
return c2;
|
||||
}
|
||||
|
||||
public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
|
||||
int count = endIndex - beginIndex;
|
||||
for (int i = beginIndex; i < endIndex; ) {
|
||||
if (Character.isHighSurrogate(getChar(value, i++)) &&
|
||||
i < endIndex &&
|
||||
Character.isLowSurrogate(getChar(value, i))) {
|
||||
count--;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static char[] toChars(byte[] value) {
|
||||
char[] dst = new char[value.length >> 1];
|
||||
getChars(value, 0, dst.length, dst, 0);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static byte[] toBytes(char[] value, int off, int len) {
|
||||
byte[] val = newBytesFor(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
putChar(val, i, value[off++]);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static byte[] compress(char[] val, int off, int len) {
|
||||
byte[] ret = new byte[len];
|
||||
if (compress(val, off, ret, 0, len) == len) {
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] compress(byte[] val, int off, int len) {
|
||||
byte[] ret = new byte[len];
|
||||
if (compress(val, off, ret, 0, len) == len) {
|
||||
return ret;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// compressedCopy char[] -> byte[]
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = src[srcOff++];
|
||||
if (c >>> 8 != 0) {
|
||||
return 0;
|
||||
}
|
||||
dst[dstOff++] = (byte)c;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// compressedCopy byte[] -> byte[]
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
int c = getChar(src, srcOff++);
|
||||
if (c >>> 8 != 0) {
|
||||
return 0;
|
||||
}
|
||||
dst[dstOff++] = (byte)c;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(int[] val, int index, int len) {
|
||||
final int end = index + len;
|
||||
// Pass 1: Compute precise size of char[]
|
||||
int n = len;
|
||||
for (int i = index; i < end; i++) {
|
||||
int cp = val[i];
|
||||
if (Character.isBmpCodePoint(cp))
|
||||
continue;
|
||||
else if (Character.isValidCodePoint(cp))
|
||||
n++;
|
||||
else throw new IllegalArgumentException(Integer.toString(cp));
|
||||
}
|
||||
// Pass 2: Allocate and fill in <high, low> pair
|
||||
byte[] buf = newBytesFor(n);
|
||||
for (int i = index, j = 0; i < end; i++, j++) {
|
||||
int cp = val[i];
|
||||
if (Character.isBmpCodePoint(cp)) {
|
||||
putChar(buf, j, cp);
|
||||
} else {
|
||||
putChar(buf, j++, Character.highSurrogate(cp));
|
||||
putChar(buf, j, Character.lowSurrogate(cp));
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(char c) {
|
||||
byte[] result = new byte[2];
|
||||
putChar(result, 0, c);
|
||||
return result;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
|
||||
for (int i = srcBegin; i < srcEnd; i++) {
|
||||
dst[dstBegin++] = getChar(value, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* @see java.lang.String.getBytes(int, int, byte[], int) */
|
||||
public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
|
||||
srcBegin <<= 1;
|
||||
srcEnd <<= 1;
|
||||
for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
|
||||
dst[dstBegin++] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static boolean equals(byte[] value, byte[] other) {
|
||||
if (value.length == other.length) {
|
||||
int len = value.length >> 1;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (getChar(value, i) != getChar(other, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int compareTo(byte[] value, byte[] other) {
|
||||
int len1 = length(value);
|
||||
int len2 = length(other);
|
||||
int lim = Math.min(len1, len2);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
char c1 = getChar(value, k);
|
||||
char c2 = getChar(other, k);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int compareToLatin1(byte[] value, byte[] other) {
|
||||
int len1 = length(value);
|
||||
int len2 = StringLatin1.length(other);
|
||||
int lim = Math.min(len1, len2);
|
||||
for (int k = 0; k < lim; k++) {
|
||||
char c1 = getChar(value, k);
|
||||
char c2 = StringLatin1.getChar(other, k);
|
||||
if (c1 != c2) {
|
||||
return c1 - c2;
|
||||
}
|
||||
}
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] value) {
|
||||
int h = 0;
|
||||
int length = value.length >> 1;
|
||||
for (int i = 0; i < length; i++) {
|
||||
h = 31 * h + getChar(value, i);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
public static int indexOf(byte[] value, int ch, int fromIndex) {
|
||||
int max = value.length >> 1;
|
||||
if (fromIndex < 0) {
|
||||
fromIndex = 0;
|
||||
} else if (fromIndex >= max) {
|
||||
// Note: fromIndex might be near -1>>>1.
|
||||
return -1;
|
||||
}
|
||||
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
// handle most cases here (ch is a BMP code point or a
|
||||
// negative value (invalid code point))
|
||||
return indexOfChar(value, ch, fromIndex, max);
|
||||
} else {
|
||||
return indexOfSupplementary(value, ch, fromIndex, max);
|
||||
}
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOf(byte[] value, byte[] str) {
|
||||
if (str.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.length == 0) {
|
||||
return -1;
|
||||
}
|
||||
return indexOf(value, length(value), str, length(str), 0);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
|
||||
char first = getChar(str, 0);
|
||||
int max = (valueCount - strCount);
|
||||
for (int i = fromIndex; i <= max; i++) {
|
||||
// Look for first character.
|
||||
if (getChar(value, i) != first) {
|
||||
while (++i <= max && getChar(value, i) != first);
|
||||
}
|
||||
// Found first character, now look at the rest of value
|
||||
if (i <= max) {
|
||||
int j = i + 1;
|
||||
int end = j + strCount - 1;
|
||||
for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
|
||||
if (j == end) {
|
||||
// Found whole string.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles indexOf Latin1 substring in UTF16 string.
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOfLatin1(byte[] value, byte[] str) {
|
||||
if (str.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (value.length == 0) {
|
||||
return -1;
|
||||
}
|
||||
return indexOfLatin1(value, length(value), str, str.length, 0);
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
|
||||
char first = (char)(tgt[0] & 0xff);
|
||||
int max = (srcCount - tgtCount);
|
||||
for (int i = fromIndex; i <= max; i++) {
|
||||
// Look for first character.
|
||||
if (getChar(src, i) != first) {
|
||||
while (++i <= max && getChar(src, i) != first);
|
||||
}
|
||||
// Found first character, now look at the rest of v2
|
||||
if (i <= max) {
|
||||
int j = i + 1;
|
||||
int end = j + tgtCount - 1;
|
||||
for (int k = 1;
|
||||
j < end && getChar(src, j) == (tgt[k] & 0xff);
|
||||
j++, k++);
|
||||
if (j == end) {
|
||||
// Found whole string.
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@HotSpotIntrinsicCandidate
|
||||
private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
|
||||
for (int i = fromIndex; i < max; i++) {
|
||||
if (getChar(value, i) == ch) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles (rare) calls of indexOf with a supplementary character.
|
||||
*/
|
||||
private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
|
||||
if (Character.isValidCodePoint(ch)) {
|
||||
final char hi = Character.highSurrogate(ch);
|
||||
final char lo = Character.lowSurrogate(ch);
|
||||
for (int i = fromIndex; i < max - 1; i++) {
|
||||
if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int lastIndexOf(byte[] src, int srcCount,
|
||||
byte[] tgt, int tgtCount, int fromIndex) {
|
||||
int min = tgtCount - 1;
|
||||
int i = min + fromIndex;
|
||||
int strLastIndex = tgtCount - 1;
|
||||
char strLastChar = getChar(tgt, strLastIndex);
|
||||
|
||||
startSearchForLastChar:
|
||||
while (true) {
|
||||
while (i >= min && getChar(src, i) != strLastChar) {
|
||||
i--;
|
||||
}
|
||||
if (i < min) {
|
||||
return -1;
|
||||
}
|
||||
int j = i - 1;
|
||||
int start = j - strLastIndex;
|
||||
int k = strLastIndex - 1;
|
||||
while (j > start) {
|
||||
if (getChar(src, j--) != getChar(tgt, k--)) {
|
||||
i--;
|
||||
continue startSearchForLastChar;
|
||||
}
|
||||
}
|
||||
return start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
|
||||
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
|
||||
// handle most cases here (ch is a BMP code point or a
|
||||
// negative value (invalid code point))
|
||||
int i = Math.min(fromIndex, (value.length >> 1) - 1);
|
||||
for (; i >= 0; i--) {
|
||||
if (getChar(value, i) == ch) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
} else {
|
||||
return lastIndexOfSupplementary(value, ch, fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles (rare) calls of lastIndexOf with a supplementary character.
|
||||
*/
|
||||
private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
|
||||
if (Character.isValidCodePoint(ch)) {
|
||||
char hi = Character.highSurrogate(ch);
|
||||
char lo = Character.lowSurrogate(ch);
|
||||
int i = Math.min(fromIndex, (value.length >> 1) - 2);
|
||||
for (; i >= 0; i--) {
|
||||
if (getChar(value, i) == hi && getChar(value, i + 1) == lo) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String replace(byte[] value, char oldChar, char newChar) {
|
||||
int len = value.length >> 1;
|
||||
int i = -1;
|
||||
while (++i < len) {
|
||||
if (getChar(value, i) == oldChar) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < len) {
|
||||
byte buf[] = new byte[value.length];
|
||||
for (int j = 0; j < i; j++) {
|
||||
putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
|
||||
}
|
||||
while (i < len) {
|
||||
char c = getChar(value, i);
|
||||
putChar(buf, i, c == oldChar ? newChar : c);
|
||||
i++;
|
||||
}
|
||||
// Check if we should try to compress to latin1
|
||||
if (String.COMPACT_STRINGS &&
|
||||
!StringLatin1.canEncode(oldChar) &&
|
||||
StringLatin1.canEncode(newChar)) {
|
||||
byte[] val = compress(buf, 0, len);
|
||||
if (val != null) {
|
||||
return new String(val, LATIN1);
|
||||
}
|
||||
}
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean regionMatchesCI(byte[] value, int toffset,
|
||||
byte[] other, int ooffset, int len) {
|
||||
int last = toffset + len;
|
||||
while (toffset < last) {
|
||||
char c1 = getChar(value, toffset++);
|
||||
char c2 = getChar(other, ooffset++);
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
// try converting both characters to uppercase.
|
||||
// If the results match, then the comparison scan should
|
||||
// continue.
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2) {
|
||||
continue;
|
||||
}
|
||||
// Unfortunately, conversion to uppercase does not work properly
|
||||
// for the Georgian alphabet, which has strange rules about case
|
||||
// conversion. So we need to make one last check before
|
||||
// exiting.
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
|
||||
byte[] other, int ooffset,
|
||||
int len) {
|
||||
int last = toffset + len;
|
||||
while (toffset < last) {
|
||||
char c1 = getChar(value, toffset++);
|
||||
char c2 = (char)(other[ooffset++] & 0xff);
|
||||
if (c1 == c2) {
|
||||
continue;
|
||||
}
|
||||
char u1 = Character.toUpperCase(c1);
|
||||
char u2 = Character.toUpperCase(c2);
|
||||
if (u1 == u2) {
|
||||
continue;
|
||||
}
|
||||
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static String toLowerCase(String str, byte[] value, Locale locale) {
|
||||
if (locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
int first;
|
||||
boolean hasSurr = false;
|
||||
final int len = value.length >> 1;
|
||||
|
||||
// Now check if there are any characters that need to be changed, or are surrogate
|
||||
for (first = 0 ; first < len; first++) {
|
||||
int cp = (int)getChar(value, first);
|
||||
if (Character.isSurrogate((char)cp)) {
|
||||
hasSurr = true;
|
||||
break;
|
||||
}
|
||||
if (cp != Character.toLowerCase(cp)) { // no need to check Character.ERROR
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first == len)
|
||||
return str;
|
||||
byte[] result = new byte[value.length];
|
||||
System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
|
||||
// lowerCase characters.
|
||||
String lang = locale.getLanguage();
|
||||
if (lang == "tr" || lang == "az" || lang == "lt") {
|
||||
return toLowerCaseEx(str, value, result, first, locale, true);
|
||||
}
|
||||
if (hasSurr) {
|
||||
return toLowerCaseEx(str, value, result, first, locale, false);
|
||||
}
|
||||
int bits = 0;
|
||||
for (int i = first; i < len; i++) {
|
||||
int cp = (int)getChar(value, i);
|
||||
if (cp == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
|
||||
Character.isSurrogate((char)cp)) {
|
||||
return toLowerCaseEx(str, value, result, i, locale, false);
|
||||
}
|
||||
if (cp == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
|
||||
return toLowerCaseEx(str, value, result, i, locale, true);
|
||||
}
|
||||
cp = Character.toLowerCase(cp);
|
||||
if (!Character.isBmpCodePoint(cp)) {
|
||||
return toLowerCaseEx(str, value, result, i, locale, false);
|
||||
}
|
||||
bits |= cp;
|
||||
putChar(result, i, cp);
|
||||
}
|
||||
if (bits >>> 8 != 0) {
|
||||
return new String(result, UTF16);
|
||||
} else {
|
||||
return newString(result, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
private static String toLowerCaseEx(String str, byte[] value,
|
||||
byte[] result, int first, Locale locale,
|
||||
boolean localeDependent) {
|
||||
int resultOffset = first;
|
||||
int length = value.length >> 1;
|
||||
int srcCount;
|
||||
for (int i = first; i < length; i += srcCount) {
|
||||
int srcChar = getChar(value, i);
|
||||
int lowerChar;
|
||||
char[] lowerCharArray;
|
||||
srcCount = 1;
|
||||
if (Character.isSurrogate((char)srcChar)) {
|
||||
srcChar = codePointAt(value, i, length);
|
||||
srcCount = Character.charCount(srcChar);
|
||||
}
|
||||
if (localeDependent ||
|
||||
srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
|
||||
srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
|
||||
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
|
||||
} else {
|
||||
lowerChar = Character.toLowerCase(srcChar);
|
||||
}
|
||||
if (Character.isBmpCodePoint(lowerChar)) { // Character.ERROR is not a bmp
|
||||
putChar(result, resultOffset++, lowerChar);
|
||||
} else {
|
||||
if (lowerChar == Character.ERROR) {
|
||||
lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
|
||||
} else {
|
||||
lowerCharArray = Character.toChars(lowerChar);
|
||||
}
|
||||
/* Grow result if needed */
|
||||
int mapLen = lowerCharArray.length;
|
||||
if (mapLen > srcCount) {
|
||||
byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
|
||||
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
|
||||
result = result2;
|
||||
}
|
||||
for (int x = 0; x < mapLen; ++x) {
|
||||
putChar(result, resultOffset++, lowerCharArray[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newString(result, 0, resultOffset);
|
||||
}
|
||||
|
||||
public static String toUpperCase(String str, byte[] value, Locale locale) {
|
||||
if (locale == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
int first;
|
||||
boolean hasSurr = false;
|
||||
final int len = value.length >> 1;
|
||||
|
||||
// Now check if there are any characters that need to be changed, or are surrogate
|
||||
for (first = 0 ; first < len; first++) {
|
||||
int cp = (int)getChar(value, first);
|
||||
if (Character.isSurrogate((char)cp)) {
|
||||
hasSurr = true;
|
||||
break;
|
||||
}
|
||||
if (cp != Character.toUpperCaseEx(cp)) { // no need to check Character.ERROR
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first == len) {
|
||||
return str;
|
||||
}
|
||||
byte[] result = new byte[value.length];
|
||||
System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
|
||||
// upperCase characters.
|
||||
String lang = locale.getLanguage();
|
||||
if (lang == "tr" || lang == "az" || lang == "lt") {
|
||||
return toUpperCaseEx(str, value, result, first, locale, true);
|
||||
}
|
||||
if (hasSurr) {
|
||||
return toUpperCaseEx(str, value, result, first, locale, false);
|
||||
}
|
||||
int bits = 0;
|
||||
for (int i = first; i < len; i++) {
|
||||
int cp = (int)getChar(value, i);
|
||||
if (Character.isSurrogate((char)cp)) {
|
||||
return toUpperCaseEx(str, value, result, i, locale, false);
|
||||
}
|
||||
cp = Character.toUpperCaseEx(cp);
|
||||
if (!Character.isBmpCodePoint(cp)) { // Character.ERROR is not bmp
|
||||
return toUpperCaseEx(str, value, result, i, locale, false);
|
||||
}
|
||||
bits |= cp;
|
||||
putChar(result, i, cp);
|
||||
}
|
||||
if (bits >>> 8 != 0) {
|
||||
return new String(result, UTF16);
|
||||
} else {
|
||||
return newString(result, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
private static String toUpperCaseEx(String str, byte[] value,
|
||||
byte[] result, int first,
|
||||
Locale locale, boolean localeDependent)
|
||||
{
|
||||
int resultOffset = first;
|
||||
int length = value.length >> 1;
|
||||
int srcCount;
|
||||
for (int i = first; i < length; i += srcCount) {
|
||||
int srcChar = getChar(value, i);
|
||||
int upperChar;
|
||||
char[] upperCharArray;
|
||||
srcCount = 1;
|
||||
if (Character.isSurrogate((char)srcChar)) {
|
||||
srcChar = codePointAt(value, i, length);
|
||||
srcCount = Character.charCount(srcChar);
|
||||
}
|
||||
if (localeDependent) {
|
||||
upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
|
||||
} else {
|
||||
upperChar = Character.toUpperCaseEx(srcChar);
|
||||
}
|
||||
if (Character.isBmpCodePoint(upperChar)) {
|
||||
putChar(result, resultOffset++, upperChar);
|
||||
} else {
|
||||
if (upperChar == Character.ERROR) {
|
||||
if (localeDependent) {
|
||||
upperCharArray =
|
||||
ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
|
||||
} else {
|
||||
upperCharArray = Character.toUpperCaseCharArray(srcChar);
|
||||
}
|
||||
} else {
|
||||
upperCharArray = Character.toChars(upperChar);
|
||||
}
|
||||
/* Grow result if needed */
|
||||
int mapLen = upperCharArray.length;
|
||||
if (mapLen > srcCount) {
|
||||
byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
|
||||
System.arraycopy(result, 0, result2, 0, resultOffset << 1);
|
||||
result = result2;
|
||||
}
|
||||
for (int x = 0; x < mapLen; ++x) {
|
||||
putChar(result, resultOffset++, upperCharArray[x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newString(result, 0, resultOffset);
|
||||
}
|
||||
|
||||
public static String trim(byte[] value) {
|
||||
int length = value.length >> 1;
|
||||
int len = length;
|
||||
int st = 0;
|
||||
while (st < len && getChar(value, st) <= ' ') {
|
||||
st++;
|
||||
}
|
||||
while (st < len && getChar(value, len - 1) <= ' ') {
|
||||
len--;
|
||||
}
|
||||
return ((st > 0) || (len < length )) ?
|
||||
new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
|
||||
null;
|
||||
}
|
||||
|
||||
public static void putChars(byte[] val, int index, char[] str, int off, int end) {
|
||||
while (off < end) {
|
||||
putChar(val, index++, str[off++]);
|
||||
}
|
||||
}
|
||||
|
||||
public static String newString(byte[] val, int index, int len) {
|
||||
if (String.COMPACT_STRINGS) {
|
||||
byte[] buf = compress(val, index, len);
|
||||
if (buf != null) {
|
||||
return new String(buf, LATIN1);
|
||||
}
|
||||
}
|
||||
int last = index + len;
|
||||
return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
|
||||
}
|
||||
|
||||
public static void fillNull(byte[] val, int index, int end) {
|
||||
Arrays.fill(val, index << 1, end << 1, (byte)0);
|
||||
}
|
||||
|
||||
static class CharsSpliterator implements Spliterator.OfInt {
|
||||
private final byte[] array;
|
||||
private int index; // current index, modified on advance/split
|
||||
private final int fence; // one past last index
|
||||
private final int cs;
|
||||
|
||||
CharsSpliterator(byte[] array, int acs) {
|
||||
this(array, 0, array.length >> 1, acs);
|
||||
}
|
||||
|
||||
CharsSpliterator(byte[] array, int origin, int fence, int acs) {
|
||||
this.array = array;
|
||||
this.index = origin;
|
||||
this.fence = fence;
|
||||
this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
|
||||
| Spliterator.SUBSIZED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfInt trySplit() {
|
||||
int lo = index, mid = (lo + fence) >>> 1;
|
||||
return (lo >= mid)
|
||||
? null
|
||||
: new CharsSpliterator(array, lo, index = mid, cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(IntConsumer action) {
|
||||
byte[] a; int i, hi; // hoist accesses and checks from loop
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (((a = array).length >> 1) >= (hi = fence) &&
|
||||
(i = index) >= 0 && i < (index = hi)) {
|
||||
do { action.accept(getChar(a, i)); } while (++i < hi);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(IntConsumer action) {
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (index >= 0 && index < fence) {
|
||||
action.accept(getChar(array, index++));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() { return (long)(fence - index); }
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return cs;
|
||||
}
|
||||
}
|
||||
|
||||
static class CodePointsSpliterator implements Spliterator.OfInt {
|
||||
private final byte[] array;
|
||||
private int index; // current index, modified on advance/split
|
||||
private final int fence; // one past last index
|
||||
private final int cs;
|
||||
|
||||
CodePointsSpliterator(byte[] array, int acs) {
|
||||
this(array, 0, array.length >> 1, acs);
|
||||
}
|
||||
|
||||
CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
|
||||
this.array = array;
|
||||
this.index = origin;
|
||||
this.fence = fence;
|
||||
this.cs = acs | Spliterator.ORDERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfInt trySplit() {
|
||||
int lo = index, mid = (lo + fence) >>> 1;
|
||||
if (lo >= mid)
|
||||
return null;
|
||||
|
||||
int midOneLess;
|
||||
// If the mid-point intersects a surrogate pair
|
||||
if (Character.isLowSurrogate(getChar(array, mid)) &&
|
||||
Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) {
|
||||
// If there is only one pair it cannot be split
|
||||
if (lo >= midOneLess)
|
||||
return null;
|
||||
// Shift the mid-point to align with the surrogate pair
|
||||
return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
|
||||
}
|
||||
return new CodePointsSpliterator(array, lo, index = mid, cs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachRemaining(IntConsumer action) {
|
||||
byte[] a; int i, hi; // hoist accesses and checks from loop
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (((a = array).length >> 1) >= (hi = fence) &&
|
||||
(i = index) >= 0 && i < (index = hi)) {
|
||||
do {
|
||||
i = advance(a, i, hi, action);
|
||||
} while (i < hi);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryAdvance(IntConsumer action) {
|
||||
if (action == null)
|
||||
throw new NullPointerException();
|
||||
if (index >= 0 && index < fence) {
|
||||
index = advance(array, index, fence, action);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Advance one code point from the index, i, and return the next
|
||||
// index to advance from
|
||||
private static int advance(byte[] a, int i, int hi, IntConsumer action) {
|
||||
char c1 = getChar(a, i++);
|
||||
int cp = c1;
|
||||
if (Character.isHighSurrogate(c1) && i < hi) {
|
||||
char c2 = getChar(a, i);
|
||||
if (Character.isLowSurrogate(c2)) {
|
||||
i++;
|
||||
cp = Character.toCodePoint(c1, c2);
|
||||
}
|
||||
}
|
||||
action.accept(cp);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long estimateSize() { return (long)(fence - index); }
|
||||
|
||||
@Override
|
||||
public int characteristics() {
|
||||
return cs;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
|
||||
checkOffset(srcEnd, val.length >> 1);
|
||||
getChars(val, srcBegin, srcEnd, dst, dstBegin);
|
||||
}
|
||||
|
||||
public static void putCharSB(byte[] val, int index, int c) {
|
||||
checkIndex(index, val.length >> 1);
|
||||
putChar(val, index, c);
|
||||
}
|
||||
|
||||
public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
|
||||
checkOffset(index + end - off, val.length >> 1);
|
||||
putChars(val, index, ca, off, end);
|
||||
}
|
||||
|
||||
public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
|
||||
checkOffset(index + end - off, val.length >> 1);
|
||||
for (int i = off; i < end; i++) {
|
||||
putChar(val, index++, s.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static int codePointAtSB(byte[] val, int index, int end) {
|
||||
checkOffset(end, val.length >> 1);
|
||||
return codePointAt(val, index, end);
|
||||
}
|
||||
|
||||
public static int codePointBeforeSB(byte[] val, int index) {
|
||||
checkOffset(index, val.length >> 1);
|
||||
return codePointBefore(val, index);
|
||||
}
|
||||
|
||||
public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
|
||||
checkOffset(endIndex, val.length >> 1);
|
||||
return codePointCount(val, beginIndex, endIndex);
|
||||
}
|
||||
|
||||
public static String newStringSB(byte[] val, int index, int len) {
|
||||
checkOffset(index + len, val.length >> 1);
|
||||
return newString(val, index, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
private static native boolean isBigEndian();
|
||||
|
||||
static final int HI_BYTE_SHIFT;
|
||||
static final int LO_BYTE_SHIFT;
|
||||
static {
|
||||
if (isBigEndian()) {
|
||||
HI_BYTE_SHIFT = 8;
|
||||
LO_BYTE_SHIFT = 0;
|
||||
} else {
|
||||
HI_BYTE_SHIFT = 0;
|
||||
LO_BYTE_SHIFT = 8;
|
||||
}
|
||||
}
|
||||
|
||||
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
|
||||
package java.lang.invoke;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import sun.invoke.util.VerifyAccess;
|
||||
@ -224,12 +224,12 @@ class DirectMethodHandle extends MethodHandle {
|
||||
assert(names.length == nameCursor);
|
||||
if (doesAlloc) {
|
||||
// names = { argx,y,z,... new C, init method }
|
||||
names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
|
||||
names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
|
||||
names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
|
||||
names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
|
||||
} else if (needsInit) {
|
||||
names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
|
||||
names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
|
||||
} else {
|
||||
names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
|
||||
names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
|
||||
}
|
||||
assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
|
||||
Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
|
||||
@ -250,9 +250,9 @@ class DirectMethodHandle extends MethodHandle {
|
||||
}
|
||||
|
||||
static Object findDirectMethodHandle(Name name) {
|
||||
if (name.function == Lazy.NF_internalMemberName ||
|
||||
name.function == Lazy.NF_internalMemberNameEnsureInit ||
|
||||
name.function == Lazy.NF_constructorMethod) {
|
||||
if (name.function == NF_internalMemberName ||
|
||||
name.function == NF_internalMemberNameEnsureInit ||
|
||||
name.function == NF_constructorMethod) {
|
||||
assert(name.arguments.length == 1);
|
||||
return name.arguments[0];
|
||||
}
|
||||
@ -613,18 +613,18 @@ class DirectMethodHandle extends MethodHandle {
|
||||
final int RESULT = nameCursor-1; // either the call or the cast
|
||||
Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
|
||||
if (needsInit)
|
||||
names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
|
||||
names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
|
||||
if (needsCast && !isGetter)
|
||||
names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
|
||||
names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
|
||||
Object[] outArgs = new Object[1 + linkerType.parameterCount()];
|
||||
assert(outArgs.length == (isGetter ? 3 : 4));
|
||||
outArgs[0] = UNSAFE;
|
||||
if (isStatic) {
|
||||
outArgs[1] = names[F_HOLDER] = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
|
||||
outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
|
||||
outArgs[1] = names[F_HOLDER] = new Name(NF_staticBase, names[DMH_THIS]);
|
||||
outArgs[2] = names[F_OFFSET] = new Name(NF_staticOffset, names[DMH_THIS]);
|
||||
} else {
|
||||
outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
|
||||
outArgs[2] = names[F_OFFSET] = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
|
||||
outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
|
||||
outArgs[2] = names[F_OFFSET] = new Name(NF_fieldOffset, names[DMH_THIS]);
|
||||
}
|
||||
if (!isGetter) {
|
||||
outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
|
||||
@ -632,7 +632,7 @@ class DirectMethodHandle extends MethodHandle {
|
||||
for (Object a : outArgs) assert(a != null);
|
||||
names[LINKER_CALL] = new Name(linker, outArgs);
|
||||
if (needsCast && isGetter)
|
||||
names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
|
||||
names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
|
||||
for (Name n : names) assert(n != null);
|
||||
String fieldOrStatic = (isStatic ? "Static" : "Field");
|
||||
String lambdaName = (linkerName + fieldOrStatic); // significant only for debugging
|
||||
@ -645,50 +645,45 @@ class DirectMethodHandle extends MethodHandle {
|
||||
* Pre-initialized NamedFunctions for bootstrapping purposes.
|
||||
* Factored in an inner class to delay initialization until first usage.
|
||||
*/
|
||||
private static class Lazy {
|
||||
static final NamedFunction
|
||||
NF_internalMemberName,
|
||||
NF_internalMemberNameEnsureInit,
|
||||
NF_ensureInitialized,
|
||||
NF_fieldOffset,
|
||||
NF_checkBase,
|
||||
NF_staticBase,
|
||||
NF_staticOffset,
|
||||
NF_checkCast,
|
||||
NF_allocateInstance,
|
||||
NF_constructorMethod;
|
||||
static {
|
||||
try {
|
||||
NamedFunction nfs[] = {
|
||||
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberName", Object.class)),
|
||||
NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
|
||||
NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("ensureInitialized", Object.class)),
|
||||
NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("fieldOffset", Object.class)),
|
||||
NF_checkBase = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkBase", Object.class)),
|
||||
NF_staticBase = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticBase", Object.class)),
|
||||
NF_staticOffset = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticOffset", Object.class)),
|
||||
NF_checkCast = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkCast", Object.class, Object.class)),
|
||||
NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("allocateInstance", Object.class)),
|
||||
NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("constructorMethod", Object.class))
|
||||
};
|
||||
for (NamedFunction nf : nfs) {
|
||||
// Each nf must be statically invocable or we get tied up in our bootstraps.
|
||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
|
||||
nf.resolve();
|
||||
}
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
static final NamedFunction
|
||||
NF_internalMemberName,
|
||||
NF_internalMemberNameEnsureInit,
|
||||
NF_ensureInitialized,
|
||||
NF_fieldOffset,
|
||||
NF_checkBase,
|
||||
NF_staticBase,
|
||||
NF_staticOffset,
|
||||
NF_checkCast,
|
||||
NF_allocateInstance,
|
||||
NF_constructorMethod;
|
||||
static {
|
||||
try {
|
||||
NamedFunction nfs[] = {
|
||||
NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberName", Object.class)),
|
||||
NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
|
||||
NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("ensureInitialized", Object.class)),
|
||||
NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("fieldOffset", Object.class)),
|
||||
NF_checkBase = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkBase", Object.class)),
|
||||
NF_staticBase = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticBase", Object.class)),
|
||||
NF_staticOffset = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("staticOffset", Object.class)),
|
||||
NF_checkCast = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("checkCast", Object.class, Object.class)),
|
||||
NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("allocateInstance", Object.class)),
|
||||
NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
|
||||
.getDeclaredMethod("constructorMethod", Object.class))
|
||||
};
|
||||
// Each nf must be statically invocable or we get tied up in our bootstraps.
|
||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ package java.lang.invoke;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.*;
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
import java.io.FilePermission;
|
||||
|
@ -750,7 +750,7 @@ class InvokerBytecodeGenerator {
|
||||
assert(!isLinkerMethodInvoke(name)); // should use the static path for these
|
||||
if (true) {
|
||||
// push receiver
|
||||
MethodHandle target = name.function.resolvedHandle;
|
||||
MethodHandle target = name.function.resolvedHandle();
|
||||
assert(target != null) : name.exprString();
|
||||
mv.visitLdcInsn(constantPlaceholder(target));
|
||||
emitReferenceCast(MethodHandle.class, target);
|
||||
@ -775,10 +775,19 @@ class InvokerBytecodeGenerator {
|
||||
// Sample classes from each package we are willing to bind to statically:
|
||||
java.lang.Object.class,
|
||||
java.util.Arrays.class,
|
||||
sun.misc.Unsafe.class
|
||||
jdk.internal.misc.Unsafe.class
|
||||
//MethodHandle.class already covered
|
||||
};
|
||||
|
||||
static boolean isStaticallyInvocable(NamedFunction[] functions) {
|
||||
for (NamedFunction nf : functions) {
|
||||
if (!isStaticallyInvocable(nf.member())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean isStaticallyInvocable(Name name) {
|
||||
return isStaticallyInvocable(name.function.member());
|
||||
}
|
||||
@ -881,7 +890,7 @@ class InvokerBytecodeGenerator {
|
||||
// The array will be a constant.
|
||||
Object emptyArray;
|
||||
try {
|
||||
emptyArray = name.function.resolvedHandle.invoke();
|
||||
emptyArray = name.function.resolvedHandle().invoke();
|
||||
} catch (Throwable ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
@ -1085,8 +1094,8 @@ class InvokerBytecodeGenerator {
|
||||
Label L_handler = new Label();
|
||||
Label L_done = new Label();
|
||||
|
||||
Class<?> returnType = result.function.resolvedHandle.type().returnType();
|
||||
MethodType type = args.function.resolvedHandle.type()
|
||||
Class<?> returnType = result.function.resolvedHandle().type().returnType();
|
||||
MethodType type = args.function.resolvedHandle().type()
|
||||
.dropParameterTypes(0,1)
|
||||
.changeReturnType(returnType);
|
||||
|
||||
|
@ -429,11 +429,8 @@ class Invokers {
|
||||
NF_checkCustomized = new NamedFunction(Invokers.class
|
||||
.getDeclaredMethod("checkCustomized", Object.class))
|
||||
};
|
||||
for (NamedFunction nf : nfs) {
|
||||
// Each nf must be statically invocable or we get tied up in our bootstraps.
|
||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
|
||||
nf.resolve();
|
||||
}
|
||||
// Each nf must be statically invocable or we get tied up in our bootstraps.
|
||||
assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
|
@ -1024,7 +1024,7 @@ class LambdaForm {
|
||||
|
||||
static class NamedFunction {
|
||||
final MemberName member;
|
||||
@Stable MethodHandle resolvedHandle;
|
||||
private @Stable MethodHandle resolvedHandle;
|
||||
@Stable MethodHandle invoker;
|
||||
|
||||
NamedFunction(MethodHandle resolvedHandle) {
|
||||
@ -1074,8 +1074,10 @@ class LambdaForm {
|
||||
return resolvedHandle;
|
||||
}
|
||||
|
||||
void resolve() {
|
||||
resolvedHandle = DirectMethodHandle.make(member);
|
||||
synchronized void resolve() {
|
||||
if (resolvedHandle == null) {
|
||||
resolvedHandle = DirectMethodHandle.make(member);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1235,6 +1237,7 @@ class LambdaForm {
|
||||
traceInterpreter("| getInvoker", this);
|
||||
invoker();
|
||||
}
|
||||
// resolvedHandle might be uninitialized, ok for tracing
|
||||
if (resolvedHandle == null) {
|
||||
traceInterpreter("| resolve", this);
|
||||
resolvedHandle();
|
||||
@ -1704,88 +1707,108 @@ class LambdaForm {
|
||||
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
|
||||
|
||||
static LambdaForm identityForm(BasicType type) {
|
||||
return LF_identityForm[type.ordinal()];
|
||||
int ord = type.ordinal();
|
||||
LambdaForm form = LF_identity[ord];
|
||||
if (form != null) {
|
||||
return form;
|
||||
}
|
||||
createFormsFor(type);
|
||||
return LF_identity[ord];
|
||||
}
|
||||
|
||||
static LambdaForm zeroForm(BasicType type) {
|
||||
return LF_zeroForm[type.ordinal()];
|
||||
int ord = type.ordinal();
|
||||
LambdaForm form = LF_zero[ord];
|
||||
if (form != null) {
|
||||
return form;
|
||||
}
|
||||
createFormsFor(type);
|
||||
return LF_zero[ord];
|
||||
}
|
||||
|
||||
static NamedFunction identity(BasicType type) {
|
||||
return NF_identity[type.ordinal()];
|
||||
int ord = type.ordinal();
|
||||
NamedFunction function = NF_identity[ord];
|
||||
if (function != null) {
|
||||
return function;
|
||||
}
|
||||
createFormsFor(type);
|
||||
return NF_identity[ord];
|
||||
}
|
||||
|
||||
static NamedFunction constantZero(BasicType type) {
|
||||
return NF_zero[type.ordinal()];
|
||||
int ord = type.ordinal();
|
||||
NamedFunction function = NF_zero[ord];
|
||||
if (function != null) {
|
||||
return function;
|
||||
}
|
||||
createFormsFor(type);
|
||||
return NF_zero[ord];
|
||||
}
|
||||
private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
|
||||
private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
|
||||
private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
|
||||
private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
|
||||
private static void createIdentityForms() {
|
||||
for (BasicType type : BasicType.ALL_TYPES) {
|
||||
int ord = type.ordinal();
|
||||
char btChar = type.basicTypeChar();
|
||||
boolean isVoid = (type == V_TYPE);
|
||||
Class<?> btClass = type.btClass;
|
||||
MethodType zeType = MethodType.methodType(btClass);
|
||||
MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
|
||||
|
||||
// Look up some symbolic names. It might not be necessary to have these,
|
||||
// but if we need to emit direct references to bytecodes, it helps.
|
||||
// Zero is built from a call to an identity function with a constant zero input.
|
||||
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
|
||||
MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
|
||||
try {
|
||||
private static final @Stable LambdaForm[] LF_identity = new LambdaForm[TYPE_LIMIT];
|
||||
private static final @Stable LambdaForm[] LF_zero = new LambdaForm[TYPE_LIMIT];
|
||||
private static final @Stable NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
|
||||
private static final @Stable NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
|
||||
|
||||
private static synchronized void createFormsFor(BasicType type) {
|
||||
final int ord = type.ordinal();
|
||||
LambdaForm idForm = LF_identity[ord];
|
||||
if (idForm != null) {
|
||||
return;
|
||||
}
|
||||
char btChar = type.basicTypeChar();
|
||||
boolean isVoid = (type == V_TYPE);
|
||||
Class<?> btClass = type.btClass;
|
||||
MethodType zeType = MethodType.methodType(btClass);
|
||||
MethodType idType = (isVoid) ? zeType : zeType.appendParameterTypes(btClass);
|
||||
|
||||
// Look up symbolic names. It might not be necessary to have these,
|
||||
// but if we need to emit direct references to bytecodes, it helps.
|
||||
// Zero is built from a call to an identity function with a constant zero input.
|
||||
MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
|
||||
MemberName zeMem = null;
|
||||
try {
|
||||
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
|
||||
if (!isVoid) {
|
||||
zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
|
||||
zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
|
||||
idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
|
||||
} catch (IllegalAccessException|NoSuchMethodException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
|
||||
NamedFunction idFun = new NamedFunction(idMem);
|
||||
LambdaForm idForm;
|
||||
if (isVoid) {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE) };
|
||||
idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
|
||||
} else {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
|
||||
idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
|
||||
}
|
||||
LF_identityForm[ord] = idForm;
|
||||
NF_identity[ord] = idFun;
|
||||
|
||||
NamedFunction zeFun = new NamedFunction(zeMem);
|
||||
LambdaForm zeForm;
|
||||
if (isVoid) {
|
||||
zeForm = idForm;
|
||||
} else {
|
||||
Object zeValue = Wrapper.forBasicType(btChar).zero();
|
||||
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
|
||||
zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
|
||||
}
|
||||
LF_zeroForm[ord] = zeForm;
|
||||
NF_zero[ord] = zeFun;
|
||||
|
||||
assert(idFun.isIdentity());
|
||||
assert(zeFun.isConstantZero());
|
||||
assert(new Name(zeFun).isConstantZero());
|
||||
} catch (IllegalAccessException|NoSuchMethodException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
|
||||
// Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
|
||||
for (BasicType type : BasicType.ALL_TYPES) {
|
||||
int ord = type.ordinal();
|
||||
NamedFunction idFun = NF_identity[ord];
|
||||
LambdaForm idForm = LF_identityForm[ord];
|
||||
MemberName idMem = idFun.member;
|
||||
idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
|
||||
NamedFunction idFun;
|
||||
LambdaForm zeForm;
|
||||
NamedFunction zeFun;
|
||||
if (isVoid) {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE) };
|
||||
idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
|
||||
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
|
||||
|
||||
NamedFunction zeFun = NF_zero[ord];
|
||||
LambdaForm zeForm = LF_zeroForm[ord];
|
||||
MemberName zeMem = zeFun.member;
|
||||
zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
|
||||
assert(zeMem == null);
|
||||
zeForm = idForm;
|
||||
zeFun = idFun;
|
||||
} else {
|
||||
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
|
||||
idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
|
||||
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
|
||||
|
||||
assert(idFun.isIdentity());
|
||||
assert(zeFun.isConstantZero());
|
||||
assert(new Name(zeFun).isConstantZero());
|
||||
assert(zeMem != null);
|
||||
Object zeValue = Wrapper.forBasicType(btChar).zero();
|
||||
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
|
||||
zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
|
||||
zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm));
|
||||
}
|
||||
|
||||
LF_zero[ord] = zeForm;
|
||||
NF_zero[ord] = zeFun;
|
||||
LF_identity[ord] = idForm;
|
||||
NF_identity[ord] = idFun;
|
||||
|
||||
assert(idFun.isIdentity());
|
||||
assert(zeFun.isConstantZero());
|
||||
assert(new Name(zeFun).isConstantZero());
|
||||
}
|
||||
|
||||
// Avoid appealing to ValueConversions at bootstrap time:
|
||||
@ -1794,13 +1817,12 @@ class LambdaForm {
|
||||
private static float identity_F(float x) { return x; }
|
||||
private static double identity_D(double x) { return x; }
|
||||
private static Object identity_L(Object x) { return x; }
|
||||
private static void identity_V() { return; } // same as zeroV, but that's OK
|
||||
private static void identity_V() { return; }
|
||||
private static int zero_I() { return 0; }
|
||||
private static long zero_J() { return 0; }
|
||||
private static float zero_F() { return 0; }
|
||||
private static double zero_D() { return 0; }
|
||||
private static Object zero_L() { return null; }
|
||||
private static void zero_V() { return; }
|
||||
|
||||
/**
|
||||
* Internal marker for byte-compiled LambdaForms.
|
||||
@ -1830,7 +1852,6 @@ class LambdaForm {
|
||||
|
||||
// Put this last, so that previous static inits can run before.
|
||||
static {
|
||||
createIdentityForms();
|
||||
if (USE_PREDEFINED_INTERPRET_METHODS)
|
||||
computeInitialPreparedForms();
|
||||
NamedFunction.initializeInvokers();
|
||||
|
@ -541,7 +541,7 @@ class LambdaFormEditor {
|
||||
assert(pos > 0); // cannot spread the MH arg itself
|
||||
|
||||
Name spreadParam = new Name(L_TYPE);
|
||||
Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
|
||||
Name checkSpread = new Name(MethodHandleImpl.NF_checkSpreadArgument, spreadParam, arrayLength);
|
||||
|
||||
// insert the new expressions
|
||||
int exprPos = lambdaForm.arity();
|
||||
|
@ -219,7 +219,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
if (convSpec == null) continue;
|
||||
MethodHandle fn;
|
||||
if (convSpec instanceof Class) {
|
||||
fn = Lazy.MH_cast.bindTo(convSpec);
|
||||
fn = getConstantHandle(MH_cast).bindTo(convSpec);
|
||||
} else {
|
||||
fn = (MethodHandle) convSpec;
|
||||
}
|
||||
@ -239,7 +239,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
if (convSpec == void.class)
|
||||
fn = null;
|
||||
else
|
||||
fn = Lazy.MH_cast.bindTo(convSpec);
|
||||
fn = getConstantHandle(MH_cast).bindTo(convSpec);
|
||||
} else {
|
||||
fn = (MethodHandle) convSpec;
|
||||
}
|
||||
@ -302,7 +302,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
Name conv;
|
||||
if (convSpec instanceof Class) {
|
||||
Class<?> convClass = (Class<?>) convSpec;
|
||||
conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]);
|
||||
conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]);
|
||||
} else {
|
||||
MethodHandle fn = (MethodHandle) convSpec;
|
||||
conv = new Name(fn, names[INARG_BASE + i]);
|
||||
@ -326,7 +326,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
|
||||
} else if (convSpec instanceof Class) {
|
||||
Class<?> convClass = (Class<?>) convSpec;
|
||||
conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]);
|
||||
conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]);
|
||||
} else {
|
||||
MethodHandle fn = (MethodHandle) convSpec;
|
||||
if (fn.type().parameterCount() == 0)
|
||||
@ -529,7 +529,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
// Spread the array.
|
||||
MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
|
||||
Name array = names[argIndex];
|
||||
names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
|
||||
names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
|
||||
for (int j = 0; j < spreadArgCount; i++, j++) {
|
||||
indexes[i] = nameCursor;
|
||||
names[nameCursor++] = new Name(aload, array, j);
|
||||
@ -566,66 +566,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
throw newIllegalArgumentException("array is not of length "+n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-initialized NamedFunctions for bootstrapping purposes.
|
||||
* Factored in an inner class to delay initialization until first usage.
|
||||
*/
|
||||
static class Lazy {
|
||||
private static final Class<?> MHI = MethodHandleImpl.class;
|
||||
private static final Class<?> CLS = Class.class;
|
||||
|
||||
private static final MethodHandle[] ARRAYS;
|
||||
private static final MethodHandle[] FILL_ARRAYS;
|
||||
|
||||
static final NamedFunction NF_checkSpreadArgument;
|
||||
static final NamedFunction NF_guardWithCatch;
|
||||
static final NamedFunction NF_throwException;
|
||||
static final NamedFunction NF_profileBoolean;
|
||||
|
||||
static final MethodHandle MH_cast;
|
||||
static final MethodHandle MH_selectAlternative;
|
||||
static final MethodHandle MH_copyAsPrimitiveArray;
|
||||
static final MethodHandle MH_fillNewTypedArray;
|
||||
static final MethodHandle MH_fillNewArray;
|
||||
static final MethodHandle MH_arrayIdentity;
|
||||
|
||||
static {
|
||||
ARRAYS = makeArrays();
|
||||
FILL_ARRAYS = makeFillArrays();
|
||||
|
||||
try {
|
||||
NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
|
||||
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
|
||||
MethodHandle.class, Object[].class));
|
||||
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
|
||||
NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
|
||||
|
||||
NF_checkSpreadArgument.resolve();
|
||||
NF_guardWithCatch.resolve();
|
||||
NF_throwException.resolve();
|
||||
NF_profileBoolean.resolve();
|
||||
|
||||
MH_cast = IMPL_LOOKUP.findVirtual(CLS, "cast",
|
||||
MethodType.methodType(Object.class, Object.class));
|
||||
MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
|
||||
MethodType.methodType(Object.class, Wrapper.class, Object[].class));
|
||||
MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
|
||||
MethodType.methodType(Object[].class, Object[].class));
|
||||
MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
|
||||
MethodType.methodType(Object[].class, Integer.class, Object[].class));
|
||||
MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
|
||||
MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
|
||||
|
||||
MH_selectAlternative = makeIntrinsic(
|
||||
IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
|
||||
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
|
||||
Intrinsic.SELECT_ALTERNATIVE);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Factory method: Collect or filter selected argument(s). */
|
||||
static MethodHandle makeCollectArguments(MethodHandle target,
|
||||
MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
|
||||
@ -911,10 +851,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
// profile branch
|
||||
if (PROFILE != -1) {
|
||||
names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
|
||||
names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
|
||||
}
|
||||
// call selectAlternative
|
||||
names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
|
||||
names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
|
||||
|
||||
// call target or fallback
|
||||
invokeArgs[0] = names[SELECT_ALT];
|
||||
@ -989,7 +929,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
// t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
|
||||
Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
|
||||
names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
|
||||
names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs);
|
||||
|
||||
// t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
|
||||
MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
|
||||
@ -1073,7 +1013,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
|
||||
return mh;
|
||||
}
|
||||
return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
|
||||
return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true);
|
||||
}
|
||||
|
||||
static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
|
||||
@ -1421,25 +1361,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
{ return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
|
||||
|
||||
private static final int ARRAYS_COUNT = 11;
|
||||
|
||||
private static MethodHandle[] makeArrays() {
|
||||
MethodHandle[] mhs = new MethodHandle[MAX_ARITY + 1];
|
||||
for (int i = 0; i < ARRAYS_COUNT; i++) {
|
||||
MethodHandle mh = findCollector("array", i, Object[].class);
|
||||
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||
mhs[i] = mh;
|
||||
}
|
||||
assert(assertArrayMethodCount(mhs));
|
||||
return mhs;
|
||||
}
|
||||
|
||||
private static boolean assertArrayMethodCount(MethodHandle[] mhs) {
|
||||
assert(findCollector("array", ARRAYS_COUNT, Object[].class) == null);
|
||||
for (int i = 0; i < ARRAYS_COUNT; i++) {
|
||||
assert(mhs[i] != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1];
|
||||
|
||||
// filling versions of the above:
|
||||
// using Integer len instead of int len and no varargs to avoid bootstrapping problems
|
||||
@ -1488,24 +1410,17 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
{ fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
|
||||
|
||||
private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods
|
||||
private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT];
|
||||
|
||||
private static MethodHandle[] makeFillArrays() {
|
||||
MethodHandle[] mhs = new MethodHandle[FILL_ARRAYS_COUNT];
|
||||
mhs[0] = null; // there is no empty fill; at least a0 is required
|
||||
for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
|
||||
MethodHandle mh = findCollector("fillArray", i, Object[].class, Integer.class, Object[].class);
|
||||
mhs[i] = mh;
|
||||
private static MethodHandle getFillArray(int count) {
|
||||
assert (count > 0 && count < FILL_ARRAYS_COUNT);
|
||||
MethodHandle mh = FILL_ARRAYS[count];
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
assert(assertFillArrayMethodCount(mhs));
|
||||
return mhs;
|
||||
}
|
||||
|
||||
private static boolean assertFillArrayMethodCount(MethodHandle[] mhs) {
|
||||
assert(findCollector("fillArray", FILL_ARRAYS_COUNT, Object[].class, Integer.class, Object[].class) == null);
|
||||
for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
|
||||
assert(mhs[i] != null);
|
||||
}
|
||||
return true;
|
||||
mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class);
|
||||
FILL_ARRAYS[count] = mh;
|
||||
return mh;
|
||||
}
|
||||
|
||||
private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
|
||||
@ -1518,12 +1433,19 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
* arguments and returns an Object array of them, as if for varargs.
|
||||
*/
|
||||
static MethodHandle varargsArray(int nargs) {
|
||||
MethodHandle mh = Lazy.ARRAYS[nargs];
|
||||
if (mh != null) return mh;
|
||||
mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
|
||||
MethodHandle mh = ARRAYS[nargs];
|
||||
if (mh != null) {
|
||||
return mh;
|
||||
}
|
||||
if (nargs < ARRAYS_COUNT) {
|
||||
mh = findCollector("array", nargs, Object[].class);
|
||||
} else {
|
||||
mh = buildVarargsArray(getConstantHandle(MH_fillNewArray),
|
||||
getConstantHandle(MH_arrayIdentity), nargs);
|
||||
}
|
||||
assert(assertCorrectArity(mh, nargs));
|
||||
mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
|
||||
return Lazy.ARRAYS[nargs] = mh;
|
||||
return ARRAYS[nargs] = mh;
|
||||
}
|
||||
|
||||
private static boolean assertCorrectArity(MethodHandle mh, int arity) {
|
||||
@ -1531,7 +1453,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Array identity function (used as Lazy.MH_arrayIdentity).
|
||||
// Array identity function (used as getConstantHandle(MH_arrayIdentity)).
|
||||
static <T> T[] identity(T[] x) {
|
||||
return x;
|
||||
}
|
||||
@ -1547,12 +1469,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
MethodHandle mh = finisher;
|
||||
if (rightLen > 0) {
|
||||
MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
|
||||
if (mh == Lazy.MH_arrayIdentity)
|
||||
if (mh.equals(getConstantHandle(MH_arrayIdentity)))
|
||||
mh = rightFiller;
|
||||
else
|
||||
mh = MethodHandles.collectArguments(mh, 0, rightFiller);
|
||||
}
|
||||
if (mh == Lazy.MH_arrayIdentity)
|
||||
if (mh.equals(getConstantHandle(MH_arrayIdentity)))
|
||||
mh = leftCollector;
|
||||
else
|
||||
mh = MethodHandles.collectArguments(mh, 0, leftCollector);
|
||||
@ -1560,7 +1482,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
}
|
||||
|
||||
private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1;
|
||||
private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
|
||||
private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
|
||||
/** fill_array_to_right(N).invoke(a, argL..arg[N-1])
|
||||
* fills a[L]..a[N-1] with corresponding arguments,
|
||||
* and then returns a. The value L is a global constant (LEFT_ARGS).
|
||||
@ -1574,7 +1496,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
}
|
||||
private static MethodHandle buildFiller(int nargs) {
|
||||
if (nargs <= LEFT_ARGS)
|
||||
return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged
|
||||
return getConstantHandle(MH_arrayIdentity); // no args to fill; return the array unchanged
|
||||
// we need room for both mh and a in mh.invoke(a, arg*[nargs])
|
||||
final int CHUNK = LEFT_ARGS;
|
||||
int rightLen = nargs % CHUNK;
|
||||
@ -1590,7 +1512,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
|
||||
assert(rightLen > 0);
|
||||
MethodHandle midFill = fillToRight(midLen); // recursive fill
|
||||
MethodHandle rightFill = Lazy.FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
|
||||
MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen); // [midLen..nargs-1]
|
||||
assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
|
||||
assert(rightFill.type().parameterCount() == 1 + rightLen);
|
||||
|
||||
@ -1641,14 +1563,14 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
|
||||
mh = MethodHandles.constant(arrayType, example);
|
||||
} else if (elemType.isPrimitive()) {
|
||||
MethodHandle builder = Lazy.MH_fillNewArray;
|
||||
MethodHandle builder = getConstantHandle(MH_fillNewArray);
|
||||
MethodHandle producer = buildArrayProducer(arrayType);
|
||||
mh = buildVarargsArray(builder, producer, nargs);
|
||||
} else {
|
||||
Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
|
||||
Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
|
||||
MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
|
||||
MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
|
||||
MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example);
|
||||
MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed
|
||||
mh = buildVarargsArray(builder, producer, nargs);
|
||||
}
|
||||
mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
|
||||
@ -1662,7 +1584,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
private static MethodHandle buildArrayProducer(Class<?> arrayType) {
|
||||
Class<?> elemType = arrayType.getComponentType();
|
||||
assert(elemType.isPrimitive());
|
||||
return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
|
||||
return getConstantHandle(MH_copyAsPrimitiveArray).bindTo(Wrapper.forPrimitiveType(elemType));
|
||||
}
|
||||
|
||||
/*non-public*/ static void assertSame(Object mh1, Object mh2) {
|
||||
@ -1673,4 +1595,87 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
throw newInternalError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Local constant functions:
|
||||
/*non-public*/ static final NamedFunction
|
||||
NF_checkSpreadArgument,
|
||||
NF_guardWithCatch,
|
||||
NF_throwException,
|
||||
NF_profileBoolean;
|
||||
|
||||
static {
|
||||
try {
|
||||
NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
|
||||
.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
|
||||
NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class
|
||||
.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
|
||||
MethodHandle.class, Object[].class));
|
||||
NF_throwException = new NamedFunction(MethodHandleImpl.class
|
||||
.getDeclaredMethod("throwException", Throwable.class));
|
||||
NF_profileBoolean = new NamedFunction(MethodHandleImpl.class
|
||||
.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Indexes into constant method handles:
|
||||
private static final int
|
||||
MH_cast = 0,
|
||||
MH_selectAlternative = 1,
|
||||
MH_copyAsPrimitiveArray = 2,
|
||||
MH_fillNewTypedArray = 3,
|
||||
MH_fillNewArray = 4,
|
||||
MH_arrayIdentity = 5,
|
||||
MH_LIMIT = 6;
|
||||
|
||||
private static MethodHandle getConstantHandle(int idx) {
|
||||
MethodHandle handle = HANDLES[idx];
|
||||
if (handle != null) {
|
||||
return handle;
|
||||
}
|
||||
return setCachedHandle(idx, makeConstantHandle(idx));
|
||||
}
|
||||
|
||||
private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) {
|
||||
// Simulate a CAS, to avoid racy duplication of results.
|
||||
MethodHandle prev = HANDLES[idx];
|
||||
if (prev != null) {
|
||||
return prev;
|
||||
}
|
||||
HANDLES[idx] = method;
|
||||
return method;
|
||||
}
|
||||
|
||||
// Local constant method handles:
|
||||
private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT];
|
||||
|
||||
private static MethodHandle makeConstantHandle(int idx) {
|
||||
try {
|
||||
switch (idx) {
|
||||
case MH_cast:
|
||||
return IMPL_LOOKUP.findVirtual(Class.class, "cast",
|
||||
MethodType.methodType(Object.class, Object.class));
|
||||
case MH_copyAsPrimitiveArray:
|
||||
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray",
|
||||
MethodType.methodType(Object.class, Wrapper.class, Object[].class));
|
||||
case MH_arrayIdentity:
|
||||
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity",
|
||||
MethodType.methodType(Object[].class, Object[].class));
|
||||
case MH_fillNewArray:
|
||||
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray",
|
||||
MethodType.methodType(Object[].class, Integer.class, Object[].class));
|
||||
case MH_fillNewTypedArray:
|
||||
return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray",
|
||||
MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
|
||||
case MH_selectAlternative:
|
||||
return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
|
||||
MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
|
||||
Intrinsic.SELECT_ALTERNATIVE);
|
||||
}
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw newInternalError(ex);
|
||||
}
|
||||
throw newInternalError("Unknown function index: " + idx);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class MethodHandleNatives {
|
||||
static native int getMembers(Class<?> defc, String matchName, String matchSig,
|
||||
int matchFlags, Class<?> caller, int skip, MemberName[] results);
|
||||
|
||||
/// Field layout queries parallel to sun.misc.Unsafe:
|
||||
/// Field layout queries parallel to jdk.internal.misc.Unsafe:
|
||||
static native long objectFieldOffset(MemberName self); // e.g., returns vmindex
|
||||
static native long staticFieldOffset(MemberName self); // e.g., returns vmindex
|
||||
static native Object staticFieldBase(MemberName self); // e.g., returns clazz
|
||||
|
@ -27,7 +27,7 @@ package java.lang.invoke;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* This class consists exclusively of static names internal to the
|
||||
|
@ -3726,12 +3726,12 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
}
|
||||
|
||||
private static class UnsafeHolder {
|
||||
private static final sun.misc.Unsafe unsafe;
|
||||
private static final jdk.internal.misc.Unsafe unsafe;
|
||||
private static final long intCompactOffset;
|
||||
private static final long intValOffset;
|
||||
static {
|
||||
try {
|
||||
unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
intCompactOffset = unsafe.objectFieldOffset
|
||||
(BigDecimal.class.getDeclaredField("intCompact"));
|
||||
intValOffset = unsafe.objectFieldOffset
|
||||
|
@ -4526,12 +4526,12 @@ public class BigInteger extends Number implements Comparable<BigInteger> {
|
||||
|
||||
// Support for resetting final fields while deserializing
|
||||
private static class UnsafeHolder {
|
||||
private static final sun.misc.Unsafe unsafe;
|
||||
private static final jdk.internal.misc.Unsafe unsafe;
|
||||
private static final long signumOffset;
|
||||
private static final long magOffset;
|
||||
static {
|
||||
try {
|
||||
unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
signumOffset = unsafe.objectFieldOffset
|
||||
(BigInteger.class.getDeclaredField("signum"));
|
||||
magOffset = unsafe.objectFieldOffset
|
||||
|
@ -576,11 +576,11 @@ class Inet6Address extends InetAddress {
|
||||
};
|
||||
|
||||
private static final long FIELDS_OFFSET;
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
try {
|
||||
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
FIELDS_OFFSET = unsafe.objectFieldOffset(
|
||||
Inet6Address.class.getDeclaredField("holder6"));
|
||||
UNSAFE = unsafe;
|
||||
|
@ -29,6 +29,7 @@ import java.util.NavigableSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceLoader;
|
||||
import java.security.AccessController;
|
||||
import java.io.ObjectStreamException;
|
||||
@ -733,7 +734,7 @@ class InetAddress implements java.io.Serializable {
|
||||
*/
|
||||
public String toString() {
|
||||
String hostName = holder().getHostName();
|
||||
return ((hostName != null) ? hostName : "")
|
||||
return Objects.toString(hostName, "")
|
||||
+ "/" + getHostAddress();
|
||||
}
|
||||
|
||||
@ -1493,11 +1494,11 @@ class InetAddress implements java.io.Serializable {
|
||||
}
|
||||
|
||||
private static final long FIELDS_OFFSET;
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
try {
|
||||
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
FIELDS_OFFSET = unsafe.objectFieldOffset(
|
||||
InetAddress.class.getDeclaredField("holder")
|
||||
);
|
||||
|
@ -303,10 +303,10 @@ public class InetSocketAddress
|
||||
}
|
||||
|
||||
private static final long FIELDS_OFFSET;
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
private static final jdk.internal.misc.Unsafe UNSAFE;
|
||||
static {
|
||||
try {
|
||||
sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
|
||||
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
FIELDS_OFFSET = unsafe.objectFieldOffset(
|
||||
InetSocketAddress.class.getDeclaredField("holder"));
|
||||
UNSAFE = unsafe;
|
||||
|
@ -61,21 +61,21 @@ public interface SocketOptions {
|
||||
* If the requested option is binary, it can be set using this method by
|
||||
* a java.lang.Boolean:
|
||||
* <BR><PRE>
|
||||
* s.setOption(TCP_NODELAY, new Boolean(true));
|
||||
* s.setOption(TCP_NODELAY, Boolean.TRUE);
|
||||
* // OK - enables TCP_NODELAY, a binary option
|
||||
* </PRE>
|
||||
* <BR>
|
||||
* Any option can be disabled using this method with a Boolean(false):
|
||||
* Any option can be disabled using this method with a Boolean.FALSE:
|
||||
* <BR><PRE>
|
||||
* s.setOption(TCP_NODELAY, new Boolean(false));
|
||||
* s.setOption(TCP_NODELAY, Boolean.FALSE);
|
||||
* // OK - disables TCP_NODELAY
|
||||
* s.setOption(SO_LINGER, new Boolean(false));
|
||||
* s.setOption(SO_LINGER, Boolean.FALSE);
|
||||
* // OK - disables SO_LINGER
|
||||
* </PRE>
|
||||
* <BR>
|
||||
* For an option that has a notion of on and off, and requires
|
||||
* a non-boolean parameter, setting its value to anything other than
|
||||
* <I>Boolean(false)</I> implicitly enables it.
|
||||
* <I>Boolean.FALSE</I> implicitly enables it.
|
||||
* <BR>
|
||||
* Throws SocketException if the option is unrecognized,
|
||||
* the socket is closed, or some low-level error occurred
|
||||
@ -91,8 +91,8 @@ public interface SocketOptions {
|
||||
|
||||
/**
|
||||
* Fetch the value of an option.
|
||||
* Binary options will return java.lang.Boolean(true)
|
||||
* if enabled, java.lang.Boolean(false) if disabled, e.g.:
|
||||
* Binary options will return java.lang.Boolean.TRUE
|
||||
* if enabled, java.lang.Boolean.FALSE if disabled, e.g.:
|
||||
* <BR><PRE>
|
||||
* SocketImpl s;
|
||||
* ...
|
||||
@ -105,13 +105,13 @@ public interface SocketOptions {
|
||||
* <P>
|
||||
* For options that take a particular type as a parameter,
|
||||
* getOption(int) will return the parameter's value, else
|
||||
* it will return java.lang.Boolean(false):
|
||||
* it will return java.lang.Boolean.FALSE:
|
||||
* <PRE>
|
||||
* Object o = s.getOption(SO_LINGER);
|
||||
* if (o instanceof Integer) {
|
||||
* System.out.print("Linger time is " + ((Integer)o).intValue());
|
||||
* } else {
|
||||
* // the true type of o is java.lang.Boolean(false);
|
||||
* // the true type of o is java.lang.Boolean.FALSE;
|
||||
* }
|
||||
* </PRE>
|
||||
*
|
||||
|
@ -32,6 +32,7 @@ import java.security.PrivilegedAction;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.StringTokenizer;
|
||||
@ -1250,7 +1251,7 @@ public abstract class URLConnection {
|
||||
|
||||
if (handler != null) {
|
||||
ContentHandler h = handlers.putIfAbsent(contentType, handler);
|
||||
return h != null ? h : handler;
|
||||
return Objects.requireNonNullElse(h, handler);
|
||||
}
|
||||
|
||||
try {
|
||||
@ -1263,7 +1264,7 @@ public abstract class URLConnection {
|
||||
assert handler != null;
|
||||
|
||||
ContentHandler h = handlers.putIfAbsent(contentType, handler);
|
||||
return h != null ? h : handler;
|
||||
return Objects.requireNonNullElse(h, handler);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -32,7 +32,7 @@ import java.util.concurrent.atomic.LongAdder;
|
||||
import jdk.internal.misc.JavaNioAccess;
|
||||
import jdk.internal.misc.JavaLangRefAccess;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.misc.VM;
|
||||
|
||||
/**
|
||||
|
@ -29,7 +29,7 @@ package java.nio;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import sun.misc.Cleaner;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import sun.misc.VM;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
package java.nio;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
#if[rw]
|
||||
@ -477,7 +477,7 @@ class Heap$Type$Buffer$RW$
|
||||
#if[rw]
|
||||
|
||||
public float getFloat() {
|
||||
int x = unsafe.getIntUnaligned(hb, byteOffset(nextPutIndex(4)), bigEndian);
|
||||
int x = unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
|
||||
return Float.intBitsToFloat(x);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
package java.nio;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -37,6 +37,7 @@ import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.ServiceConfigurationError;
|
||||
@ -625,6 +626,7 @@ public abstract class Charset
|
||||
|
||||
private final String name; // tickles a bug in oldjavac
|
||||
private final String[] aliases; // tickles a bug in oldjavac
|
||||
private final String[] zeroAliases = new String[0];
|
||||
private Set<String> aliasSet = null;
|
||||
|
||||
/**
|
||||
@ -642,7 +644,7 @@ public abstract class Charset
|
||||
*/
|
||||
protected Charset(String canonicalName, String[] aliases) {
|
||||
checkName(canonicalName);
|
||||
String[] as = (aliases == null) ? new String[0] : aliases;
|
||||
String[] as = Objects.requireNonNullElse(aliases, zeroAliases);
|
||||
for (int i = 0; i < as.length; i++)
|
||||
checkName(as[i]);
|
||||
this.name = canonicalName;
|
||||
|
@ -419,7 +419,7 @@ public class SecureRandom extends java.util.Random {
|
||||
* @since 1.5
|
||||
*/
|
||||
public String getAlgorithm() {
|
||||
return (algorithm != null) ? algorithm : "unknown";
|
||||
return Objects.toString(algorithm, "unknown");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import static java.time.LocalTime.NANOS_PER_MINUTE;
|
||||
import static java.time.LocalTime.NANOS_PER_SECOND;
|
||||
|
||||
import static java.time.LocalTime.NANOS_PER_MILLI;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
@ -182,7 +182,7 @@ public abstract class Clock {
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a clock that returns the current instant using best available
|
||||
* Obtains a clock that returns the current instant using the best available
|
||||
* system clock.
|
||||
* <p>
|
||||
* This clock is based on the best available system clock.
|
||||
@ -204,10 +204,34 @@ public abstract class Clock {
|
||||
return new SystemClock(zone);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a clock that returns the current instant ticking in whole milliseconds
|
||||
* using the best available system clock.
|
||||
* <p>
|
||||
* This clock will always have the nano-of-second field truncated to milliseconds.
|
||||
* This ensures that the visible time ticks in whole milliseconds.
|
||||
* The underlying clock is the best available system clock, equivalent to
|
||||
* using {@link #system(ZoneId)}.
|
||||
* <p>
|
||||
* Implementations may use a caching strategy for performance reasons.
|
||||
* As such, it is possible that the start of the millisecond observed via this
|
||||
* clock will be later than that observed directly via the underlying clock.
|
||||
* <p>
|
||||
* The returned implementation is immutable, thread-safe and {@code Serializable}.
|
||||
* It is equivalent to {@code tick(system(zone), Duration.ofMillis(1))}.
|
||||
*
|
||||
* @param zone the time-zone to use to convert the instant to date-time, not null
|
||||
* @return a clock that ticks in whole milliseconds using the specified zone, not null
|
||||
*/
|
||||
public static Clock tickMillis(ZoneId zone) {
|
||||
return new TickClock(system(zone), NANOS_PER_MILLI);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains a clock that returns the current instant ticking in whole seconds
|
||||
* using best available system clock.
|
||||
* using the best available system clock.
|
||||
* <p>
|
||||
* This clock will always have the nano-of-second field set to zero.
|
||||
* This ensures that the visible time ticks in whole seconds.
|
||||
@ -230,7 +254,7 @@ public abstract class Clock {
|
||||
|
||||
/**
|
||||
* Obtains a clock that returns the current instant ticking in whole minutes
|
||||
* using best available system clock.
|
||||
* using the best available system clock.
|
||||
* <p>
|
||||
* This clock will always have the nano-of-second and second-of-minute fields set to zero.
|
||||
* This ensures that the visible time ticks in whole minutes.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -359,8 +359,8 @@ public final class Duration
|
||||
* there must be at least one section after the "T".
|
||||
* The number part of each section must consist of one or more ASCII digits.
|
||||
* The number may be prefixed by the ASCII negative or positive symbol.
|
||||
* The number of days, hours and minutes must parse to an {@code long}.
|
||||
* The number of seconds must parse to an {@code long} with optional fraction.
|
||||
* The number of days, hours and minutes must parse to a {@code long}.
|
||||
* The number of seconds must parse to a {@code long} with optional fraction.
|
||||
* The decimal point may be either a dot or a comma.
|
||||
* The fractional part may have from zero to 9 digits.
|
||||
* <p>
|
||||
@ -374,9 +374,9 @@ public final class Duration
|
||||
* "PT10H" -- parses as "10 hours" (where an hour is 3600 seconds)
|
||||
* "P2D" -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
|
||||
* "P2DT3H4M" -- parses as "2 days, 3 hours and 4 minutes"
|
||||
* "P-6H3M" -- parses as "-6 hours and +3 minutes"
|
||||
* "-P6H3M" -- parses as "-6 hours and -3 minutes"
|
||||
* "-P-6H+3M" -- parses as "+6 hours and -3 minutes"
|
||||
* "PT-6H3M" -- parses as "-6 hours and +3 minutes"
|
||||
* "-PT6H3M" -- parses as "-6 hours and -3 minutes"
|
||||
* "-PT-6H+3M" -- parses as "+6 hours and -3 minutes"
|
||||
* </pre>
|
||||
*
|
||||
* @param text the text to parse, not null
|
||||
@ -402,7 +402,8 @@ public final class Duration
|
||||
long hoursAsSecs = parseNumber(text, hourStart, hourEnd, SECONDS_PER_HOUR, "hours");
|
||||
long minsAsSecs = parseNumber(text, minuteStart, minuteEnd, SECONDS_PER_MINUTE, "minutes");
|
||||
long seconds = parseNumber(text, secondStart, secondEnd, 1, "seconds");
|
||||
int nanos = parseFraction(text, fractionStart, fractionEnd, seconds < 0 ? -1 : 1);
|
||||
boolean negativeSecs = secondStart >= 0 && text.charAt(secondStart) == '-';
|
||||
int nanos = parseFraction(text, fractionStart, fractionEnd, negativeSecs ? -1 : 1);
|
||||
try {
|
||||
return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
|
||||
} catch (ArithmeticException ex) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -81,7 +81,7 @@ import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.time.chrono.ChronoLocalDate;
|
||||
import java.time.chrono.Era;
|
||||
import java.time.chrono.IsoEra;
|
||||
import java.time.chrono.IsoChronology;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
@ -220,12 +220,8 @@ public final class LocalDate
|
||||
*/
|
||||
public static LocalDate now(Clock clock) {
|
||||
Objects.requireNonNull(clock, "clock");
|
||||
// inline to avoid creating object and Instant checks
|
||||
final Instant now = clock.instant(); // called once
|
||||
ZoneOffset offset = clock.getZone().getRules().getOffset(now);
|
||||
long epochSec = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
|
||||
long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY);
|
||||
return LocalDate.ofEpochDay(epochDay);
|
||||
return ofInstant(now, clock.getZone());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -298,6 +294,30 @@ public final class LocalDate
|
||||
return new LocalDate(year, moy.getValue(), dom);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDate} from an {@code Instant} and zone ID.
|
||||
* <p>
|
||||
* This creates a local date based on the specified instant.
|
||||
* First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
|
||||
* which is simple as there is only one valid offset for each instant.
|
||||
* Then, the instant and offset are used to calculate the local date.
|
||||
*
|
||||
* @param instant the instant to create the date from, not null
|
||||
* @param zone the time-zone, which may be an offset, not null
|
||||
* @return the local date, not null
|
||||
* @throws DateTimeException if the result exceeds the supported range
|
||||
*/
|
||||
public static LocalDate ofInstant(Instant instant, ZoneId zone) {
|
||||
Objects.requireNonNull(instant, "instant");
|
||||
Objects.requireNonNull(zone, "zone");
|
||||
ZoneRules rules = zone.getRules();
|
||||
ZoneOffset offset = rules.getOffset(instant);
|
||||
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
|
||||
long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
|
||||
return ofEpochDay(localEpochDay);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code LocalDate} from the epoch day count.
|
||||
@ -712,15 +732,12 @@ public final class LocalDate
|
||||
* Users of this class should typically ignore this method as it exists primarily
|
||||
* to fulfill the {@link ChronoLocalDate} contract where it is necessary to support
|
||||
* the Japanese calendar system.
|
||||
* <p>
|
||||
* The returned era will be a singleton capable of being compared with the constants
|
||||
* in {@link IsoChronology} using the {@code ==} operator.
|
||||
*
|
||||
* @return the {@code IsoChronology} era constant applicable at this date, not null
|
||||
* @return the IsoEra applicable at this date, not null
|
||||
*/
|
||||
@Override // override for Javadoc
|
||||
public Era getEra() {
|
||||
return ChronoLocalDate.super.getEra();
|
||||
public IsoEra getEra() {
|
||||
return (getYear() >= 1 ? IsoEra.CE : IsoEra.BCE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -189,10 +189,14 @@ public final class LocalTime
|
||||
* Microseconds per day.
|
||||
*/
|
||||
static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
|
||||
/**
|
||||
* Nanos per millisecond.
|
||||
*/
|
||||
static final long NANOS_PER_MILLI = 1000_000L;
|
||||
/**
|
||||
* Nanos per second.
|
||||
*/
|
||||
static final long NANOS_PER_SECOND = 1000_000_000L;
|
||||
static final long NANOS_PER_SECOND = 1000_000_000L;
|
||||
/**
|
||||
* Nanos per minute.
|
||||
*/
|
||||
@ -272,12 +276,8 @@ public final class LocalTime
|
||||
*/
|
||||
public static LocalTime now(Clock clock) {
|
||||
Objects.requireNonNull(clock, "clock");
|
||||
// inline OffsetTime factory to avoid creating object and InstantProvider checks
|
||||
final Instant now = clock.instant(); // called once
|
||||
ZoneOffset offset = clock.getZone().getRules().getOffset(now);
|
||||
long localSecond = now.getEpochSecond() + offset.getTotalSeconds(); // overflow caught later
|
||||
int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
|
||||
return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + now.getNano());
|
||||
return ofInstant(now, clock.getZone());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -343,6 +343,27 @@ public final class LocalTime
|
||||
return create(hour, minute, second, nanoOfSecond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains an instance of {@code LocalTime} from an {@code Instant} and zone ID.
|
||||
* <p>
|
||||
* This creates a local time based on the specified instant.
|
||||
* First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
|
||||
* which is simple as there is only one valid offset for each instant.
|
||||
* Then, the instant and offset are used to calculate the local time.
|
||||
*
|
||||
* @param instant the instant to create the time from, not null
|
||||
* @param zone the time-zone, which may be an offset, not null
|
||||
* @return the local time, not null
|
||||
*/
|
||||
public static LocalTime ofInstant(Instant instant, ZoneId zone) {
|
||||
Objects.requireNonNull(instant, "instant");
|
||||
Objects.requireNonNull(zone, "zone");
|
||||
ZoneOffset offset = zone.getRules().getOffset(instant);
|
||||
long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
|
||||
int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
|
||||
return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Obtains an instance of {@code LocalTime} from a second-of-day value.
|
||||
|
@ -310,8 +310,7 @@ public abstract class ZoneId implements Serializable {
|
||||
public static ZoneId of(String zoneId, Map<String, String> aliasMap) {
|
||||
Objects.requireNonNull(zoneId, "zoneId");
|
||||
Objects.requireNonNull(aliasMap, "aliasMap");
|
||||
String id = aliasMap.get(zoneId);
|
||||
id = (id != null ? id : zoneId);
|
||||
String id = Objects.requireNonNullElse(aliasMap.get(zoneId), zoneId);
|
||||
return of(id);
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ public interface Chronology extends Comparable<Chronology> {
|
||||
static Chronology from(TemporalAccessor temporal) {
|
||||
Objects.requireNonNull(temporal, "temporal");
|
||||
Chronology obj = temporal.query(TemporalQueries.chronology());
|
||||
return (obj != null ? obj : IsoChronology.INSTANCE);
|
||||
return Objects.requireNonNullElse(obj, IsoChronology.INSTANCE);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
@ -2892,7 +2892,8 @@ public final class DateTimeFormatterBuilder {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ReducedValue(" + field + "," + minWidth + "," + maxWidth + "," + (baseDate != null ? baseDate : baseValue) + ")";
|
||||
return "ReducedValue(" + field + "," + minWidth + "," + maxWidth +
|
||||
"," + Objects.requireNonNullElse(baseDate, baseValue) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@ -3851,6 +3852,10 @@ public final class DateTimeFormatterBuilder {
|
||||
return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
|
||||
} else if (context.charEquals(nextChar, 'G') && length >= position + 3 &&
|
||||
context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) {
|
||||
if (length >= position + 4 && context.charEquals(text.charAt(position + 3), '0')) {
|
||||
context.setParsed(ZoneId.of("GMT0"));
|
||||
return position + 4;
|
||||
}
|
||||
return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
|
||||
}
|
||||
}
|
||||
@ -4328,7 +4333,7 @@ public final class DateTimeFormatterBuilder {
|
||||
private String getChronologyName(Chronology chrono, Locale locale) {
|
||||
String key = "calendarname." + chrono.getCalendarType();
|
||||
String name = DateTimeTextProvider.getLocalizedResource(key, locale);
|
||||
return name != null ? name : chrono.getId();
|
||||
return Objects.requireNonNullElseGet(name, () -> chrono.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ final class DateTimePrintContext {
|
||||
if (overrideZone != null) {
|
||||
// if have zone and instant, calculation is simple, defaulting chrono if necessary
|
||||
if (temporal.isSupported(INSTANT_SECONDS)) {
|
||||
Chronology chrono = (effectiveChrono != null ? effectiveChrono : IsoChronology.INSTANCE);
|
||||
Chronology chrono = Objects.requireNonNullElse(effectiveChrono, IsoChronology.INSTANCE);
|
||||
return chrono.zonedDateTime(Instant.from(temporal), overrideZone);
|
||||
}
|
||||
// block changing zone on OffsetTime, and similar problem cases
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -102,7 +102,7 @@ import sun.util.locale.provider.LocaleResources;
|
||||
* The complete date is expressed using three fields:
|
||||
* <ul>
|
||||
* <li>{@link #DAY_OF_QUARTER DAY_OF_QUARTER} - the day within the quarter, from 1 to 90, 91 or 92
|
||||
* <li>{@link #QUARTER_OF_YEAR QUARTER_OF_YEAR} - the week within the week-based-year
|
||||
* <li>{@link #QUARTER_OF_YEAR QUARTER_OF_YEAR} - the quarter within the year, from 1 to 4
|
||||
* <li>{@link ChronoField#YEAR YEAR} - the standard ISO year
|
||||
* </ul>
|
||||
*
|
||||
@ -571,9 +571,6 @@ public final class IsoFields {
|
||||
//-------------------------------------------------------------------------
|
||||
private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274};
|
||||
|
||||
private static boolean isIso(TemporalAccessor temporal) {
|
||||
return Chronology.from(temporal).equals(IsoChronology.INSTANCE);
|
||||
}
|
||||
|
||||
private static void ensureIso(TemporalAccessor temporal) {
|
||||
if (isIso(temporal) == false) {
|
||||
@ -681,7 +678,7 @@ public final class IsoFields {
|
||||
|
||||
@Override
|
||||
public boolean isSupportedBy(Temporal temporal) {
|
||||
return temporal.isSupported(EPOCH_DAY);
|
||||
return temporal.isSupported(EPOCH_DAY) && isIso(temporal);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -721,4 +718,8 @@ public final class IsoFields {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isIso(TemporalAccessor temporal) {
|
||||
return Chronology.from(temporal).equals(IsoChronology.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
@ -2882,6 +2882,7 @@ public class Arrays {
|
||||
* @param a2 the other array to be tested for equality
|
||||
* @return {@code true} if the two arrays are equal
|
||||
*/
|
||||
@HotSpotIntrinsicCandidate
|
||||
public static boolean equals(byte[] a, byte[] a2) {
|
||||
if (a==a2)
|
||||
return true;
|
||||
@ -3304,6 +3305,103 @@ public class Arrays {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the two specified arrays of Objects are
|
||||
* <i>equal</i> to one another.
|
||||
*
|
||||
* <p>Two arrays are considered equal if both arrays contain the same number
|
||||
* of elements, and all corresponding pairs of elements in the two arrays
|
||||
* are equal. In other words, the two arrays are equal if they contain the
|
||||
* same elements in the same order. Also, two array references are
|
||||
* considered equal if both are {@code null}.
|
||||
*
|
||||
* <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
|
||||
* given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
|
||||
*
|
||||
* @param a one array to be tested for equality
|
||||
* @param a2 the other array to be tested for equality
|
||||
* @param cmp the comparator to compare array elements
|
||||
* @param <T> the type of array elements
|
||||
* @return {@code true} if the two arrays are equal
|
||||
* @throws NullPointerException if the comparator is {@code null}
|
||||
* @since 9
|
||||
*/
|
||||
public static <T> boolean equals(T[] a, T[] a2, Comparator<? super T> cmp) {
|
||||
Objects.requireNonNull(cmp);
|
||||
if (a==a2)
|
||||
return true;
|
||||
if (a==null || a2==null)
|
||||
return false;
|
||||
|
||||
int length = a.length;
|
||||
if (a2.length != length)
|
||||
return false;
|
||||
|
||||
for (int i=0; i<length; i++) {
|
||||
if (cmp.compare(a[i], a2[i]) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the two specified arrays of Objects, over the specified
|
||||
* ranges, are <i>equal</i> to one another.
|
||||
*
|
||||
* <p>Two arrays are considered equal if the number of elements covered by
|
||||
* each range is the same, and all corresponding pairs of elements over the
|
||||
* specified ranges in the two arrays are equal. In other words, two arrays
|
||||
* are equal if they contain, over the specified ranges, the same elements
|
||||
* in the same order.
|
||||
*
|
||||
* <p>Two objects {@code e1} and {@code e2} are considered <i>equal</i> if,
|
||||
* given the specified comparator, {@code cmp.compare(e1, e2) == 0}.
|
||||
*
|
||||
* @param a the first array to be tested for equality
|
||||
* @param aFromIndex the index (inclusive) of the first element in the
|
||||
* first array to be tested
|
||||
* @param aToIndex the index (exclusive) of the last element in the
|
||||
* first array to be tested
|
||||
* @param b the second array to be tested fro equality
|
||||
* @param bFromIndex the index (inclusive) of the first element in the
|
||||
* second array to be tested
|
||||
* @param bToIndex the index (exclusive) of the last element in the
|
||||
* second array to be tested
|
||||
* @param cmp the comparator to compare array elements
|
||||
* @param <T> the type of array elements
|
||||
* @return {@code true} if the two arrays, over the specified ranges, are
|
||||
* equal
|
||||
* @throws IllegalArgumentException
|
||||
* if {@code aFromIndex > aToIndex} or
|
||||
* if {@code bFromIndex > bToIndex}
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* if {@code aFromIndex < 0 or aToIndex > a.length} or
|
||||
* if {@code bFromIndex < 0 or bToIndex > b.length}
|
||||
* @throws NullPointerException
|
||||
* if either array or the comparator is {@code null}
|
||||
* @since 9
|
||||
*/
|
||||
public static <T> boolean equals(T[] a, int aFromIndex, int aToIndex,
|
||||
T[] b, int bFromIndex, int bToIndex,
|
||||
Comparator<? super T> cmp) {
|
||||
Objects.requireNonNull(cmp);
|
||||
rangeCheck(a.length, aFromIndex, aToIndex);
|
||||
rangeCheck(b.length, bFromIndex, bToIndex);
|
||||
|
||||
int aLength = aToIndex - aFromIndex;
|
||||
int bLength = bToIndex - bFromIndex;
|
||||
if (aLength != bLength)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < aLength; i++) {
|
||||
if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Filling
|
||||
|
||||
/**
|
||||
@ -8743,9 +8841,7 @@ public class Arrays {
|
||||
* <pre>{@code
|
||||
* pl >= 0 &&
|
||||
* pl < Math.min(a.length, b.length) &&
|
||||
* IntStream.range(0, pl).
|
||||
* map(i -> cmp.compare(a[i], b[i])).
|
||||
* allMatch(c -> c == 0) &&
|
||||
* Arrays.equals(a, 0, pl, b, 0, pl, cmp)
|
||||
* cmp.compare(a[pl], b[pl]) != 0
|
||||
* }</pre>
|
||||
* Note that a common prefix length of {@code 0} indicates that the first
|
||||
@ -8755,9 +8851,9 @@ public class Arrays {
|
||||
* prefix if the following expression is true:
|
||||
* <pre>{@code
|
||||
* a.length != b.length &&
|
||||
* IntStream.range(0, Math.min(a.length, b.length)).
|
||||
* map(i -> cmp.compare(a[i], b[i])).
|
||||
* allMatch(c -> c == 0) &&
|
||||
* Arrays.equals(a, 0, Math.min(a.length, b.length),
|
||||
* b, 0, Math.min(a.length, b.length),
|
||||
* cmp)
|
||||
* }</pre>
|
||||
*
|
||||
* @param a the first array to be tested for a mismatch
|
||||
@ -8814,9 +8910,7 @@ public class Arrays {
|
||||
* <pre>{@code
|
||||
* pl >= 0 &&
|
||||
* pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
|
||||
* IntStream.range(0, pl).
|
||||
* map(i -> cmp.compare(a[aFromIndex + i], b[bFromIndex + i])).
|
||||
* allMatch(c -> c == 0) &&
|
||||
* Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
|
||||
* cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
|
||||
* }</pre>
|
||||
* Note that a common prefix length of {@code 0} indicates that the first
|
||||
@ -8828,9 +8922,9 @@ public class Arrays {
|
||||
* if the following expression is true:
|
||||
* <pre>{@code
|
||||
* (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
|
||||
* IntStream.range(0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex)).
|
||||
* map(i -> cmp.compare(a[aFromIndex + i], b[bFromIndex + i])).
|
||||
* allMatch(c -> c == 0)
|
||||
* Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
|
||||
* b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
|
||||
* cmp)
|
||||
* }</pre>
|
||||
*
|
||||
* @param a the first array to be tested for a mismatch
|
||||
|
@ -49,6 +49,7 @@ import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.Objects;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
@ -3860,7 +3861,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
ampm = dfs.getAmPmStrings();
|
||||
}
|
||||
String s = ampm[t.get(Calendar.AM_PM)];
|
||||
sb.append(s.toLowerCase(l != null ? l : Locale.US));
|
||||
sb.append(s.toLowerCase(Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
|
||||
@ -3893,7 +3894,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
TimeZone tz = t.getTimeZone();
|
||||
sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
|
||||
TimeZone.SHORT,
|
||||
(l == null) ? Locale.US : l));
|
||||
Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3901,7 +3902,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
case DateTime.NAME_OF_DAY_ABBREV: // 'a'
|
||||
case DateTime.NAME_OF_DAY: { // 'A'
|
||||
int i = t.get(Calendar.DAY_OF_WEEK);
|
||||
Locale lt = ((l == null) ? Locale.US : l);
|
||||
Locale lt = Objects.requireNonNullElse(l, Locale.US);
|
||||
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
|
||||
if (c == DateTime.NAME_OF_DAY)
|
||||
sb.append(dfs.getWeekdays()[i]);
|
||||
@ -3913,7 +3914,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
|
||||
case DateTime.NAME_OF_MONTH: { // 'B'
|
||||
int i = t.get(Calendar.MONTH);
|
||||
Locale lt = ((l == null) ? Locale.US : l);
|
||||
Locale lt = Objects.requireNonNullElse(l, Locale.US);
|
||||
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
|
||||
if (c == DateTime.NAME_OF_MONTH)
|
||||
sb.append(dfs.getMonths()[i]);
|
||||
@ -3984,7 +3985,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
StringBuilder tsb = new StringBuilder();
|
||||
print(tsb, t, DateTime.AM_PM, l);
|
||||
|
||||
sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
|
||||
sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
|
||||
@ -4092,7 +4093,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
ampm = dfs.getAmPmStrings();
|
||||
}
|
||||
String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
|
||||
sb.append(s.toLowerCase(l != null ? l : Locale.US));
|
||||
sb.append(s.toLowerCase(Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
|
||||
@ -4131,7 +4132,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
sb.append(TimeZone.getTimeZone(zid.getId())
|
||||
.getDisplayName(zid.getRules().isDaylightSavings(instant),
|
||||
TimeZone.SHORT,
|
||||
(l == null) ? Locale.US : l));
|
||||
Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
sb.append(zid.getId());
|
||||
@ -4141,7 +4142,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
case DateTime.NAME_OF_DAY_ABBREV: // 'a'
|
||||
case DateTime.NAME_OF_DAY: { // 'A'
|
||||
int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
|
||||
Locale lt = ((l == null) ? Locale.US : l);
|
||||
Locale lt = Objects.requireNonNullElse(l, Locale.US);
|
||||
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
|
||||
if (c == DateTime.NAME_OF_DAY)
|
||||
sb.append(dfs.getWeekdays()[i]);
|
||||
@ -4153,7 +4154,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
|
||||
case DateTime.NAME_OF_MONTH: { // 'B'
|
||||
int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
|
||||
Locale lt = ((l == null) ? Locale.US : l);
|
||||
Locale lt = Objects.requireNonNullElse(l, Locale.US);
|
||||
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
|
||||
if (c == DateTime.NAME_OF_MONTH)
|
||||
sb.append(dfs.getMonths()[i]);
|
||||
@ -4223,7 +4224,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
// this may be in wrong place for some locales
|
||||
StringBuilder tsb = new StringBuilder();
|
||||
print(tsb, t, DateTime.AM_PM, l);
|
||||
sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
|
||||
sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l, Locale.US)));
|
||||
break;
|
||||
}
|
||||
case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
|
||||
|
@ -295,7 +295,7 @@ public final class Objects {
|
||||
* {@code defaultObj} is {@code null}
|
||||
* @since 9
|
||||
*/
|
||||
public static <T> T nonNullElse(T obj, T defaultObj) {
|
||||
public static <T> T requireNonNullElse(T obj, T defaultObj) {
|
||||
return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
|
||||
}
|
||||
|
||||
@ -314,8 +314,9 @@ public final class Objects {
|
||||
* the {@code supplier.get()} value is {@code null}
|
||||
* @since 9
|
||||
*/
|
||||
public static <T> T nonNullElseGet(T obj, Supplier<? extends T> supplier) {
|
||||
return (obj != null) ? obj : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
|
||||
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
|
||||
return (obj != null) ? obj
|
||||
: requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,15 +352,16 @@ public final class Objects {
|
||||
* @param b the second out of bound value
|
||||
* @param oobe the exception mapping function that when applied with out of
|
||||
* bounds arguments returns a runtime exception. If {@code null}
|
||||
* then, it's as if an exception mapping function was supplied that
|
||||
* then, it is as if an exception mapping function was supplied that
|
||||
* returns {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* @return the runtime exception
|
||||
*/
|
||||
private static RuntimeException outOfBounds(
|
||||
int a, int b, BiFunction<Integer, Integer, ? extends RuntimeException> oobe) {
|
||||
return oobe == null
|
||||
? new IndexOutOfBoundsException(a, b)
|
||||
: oobe.apply(a, b);
|
||||
RuntimeException e = oobe == null
|
||||
? null : oobe.apply(a, b);
|
||||
return e == null
|
||||
? new IndexOutOfBoundsException(a, b) : e;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,8 +409,10 @@ public final class Objects {
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @param oobe the exception mapping function that when applied with out
|
||||
* of bounds arguments returns a runtime exception. If {@code null}
|
||||
* then, it's as if an exception mapping function was supplied that
|
||||
* returns {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* or returns {@code null} then, it is as if an exception mapping
|
||||
* function was supplied that returns
|
||||
* {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* Exceptions thrown by the function are relayed to the caller.
|
||||
* @return {@code index} if it is within bounds of the range
|
||||
* @throws T if the {@code index} is out of bounds, then a runtime exception
|
||||
* is thrown that is the result of applying the out of bounds
|
||||
@ -483,8 +487,10 @@ public final class Objects {
|
||||
* @param length the upper-bound (exclusive) the range
|
||||
* @param oobe the exception mapping function that when applied with out
|
||||
* of bounds arguments returns a runtime exception. If {@code null}
|
||||
* then, it's as if an exception mapping function was supplied that
|
||||
* returns {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* or returns {@code null} then, it is as if an exception mapping
|
||||
* function was supplied that returns
|
||||
* {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* Exceptions thrown by the function are relayed to the caller.
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws T if the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the out of bounds arguments
|
||||
@ -552,8 +558,10 @@ public final class Objects {
|
||||
* @param length the upper-bound (exclusive) of the range
|
||||
* @param oobe the exception mapping function that when applied with out
|
||||
* of bounds arguments returns a runtime exception. If {@code null}
|
||||
* then, it's as if an exception mapping function was supplied that
|
||||
* returns {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* or returns {@code null} then, it is as if an exception mapping
|
||||
* function was supplied that returns
|
||||
* {@link IndexOutOfBoundsException} for any given arguments.
|
||||
* Exceptions thrown by the function are relayed to the caller.
|
||||
* @return {@code fromIndex} if the sub-range within bounds of the range
|
||||
* @throws T if the sub-range is out of bounds, then a runtime exception is
|
||||
* thrown that is the result of applying the out of bounds arguments
|
||||
|
@ -34,7 +34,7 @@ import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* An instance of this class is used to generate a stream of
|
||||
|
@ -2775,7 +2775,7 @@ public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
private static final long RESULT;
|
||||
private static final long STACK;
|
||||
private static final long NEXT;
|
||||
|
@ -297,7 +297,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
* Table accesses require volatile/atomic reads, writes, and
|
||||
* CASes. Because there is no other way to arrange this without
|
||||
* adding further indirections, we use intrinsics
|
||||
* (sun.misc.Unsafe) operations.
|
||||
* (jdk.internal.misc.Unsafe) operations.
|
||||
*
|
||||
* We use the top (sign) bit of Node hash fields for control
|
||||
* purposes -- it is available anyway because of addressing
|
||||
@ -3287,7 +3287,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
private static final long LOCKSTATE;
|
||||
static {
|
||||
try {
|
||||
@ -6330,7 +6330,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
|
||||
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
|
||||
private static final long SIZECTL;
|
||||
private static final long TRANSFERINDEX;
|
||||
private static final long BASECOUNT;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user