openjdk-1.8.0/0041-Reuse-translet-in-XSLTC-for-specjvm-xml-transform.patch

277 lines
12 KiB
Diff

Date: Fri, 9 Jun 2023 10:29:38 +0800
Subject: Reuse translet in XSLTC for XML
---
.../share/vm/classfile/classFileParser.cpp | 52 +++++++++++-
.../share/vm/classfile/classFileParser.hpp | 2 +-
hotspot/src/share/vm/classfile/vmSymbols.hpp | 4 +-
hotspot/src/share/vm/runtime/arguments.cpp | 2 +
hotspot/src/share/vm/runtime/arguments.hpp | 3 +
.../src/share/vm/utilities/accessFlags.hpp | 1 +
.../transform/TestXmlTransletEnhance.java | 83 +++++++++++++++++++
8 files changed, 144 insertions(+), 3 deletions(-)
create mode 100644 jdk/test/javax/xml/jaxp/transform/TestXmlTransletEnhance.java
diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp
index d8e99e622..b9fde38dc 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp
@@ -59,12 +59,13 @@
#include "runtime/reflection.hpp"
#include "runtime/signature.hpp"
#include "runtime/timer.hpp"
+#include "runtime/arguments.hpp"
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
#include "utilities/array.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
-
+#include "interpreter/bytecodeStream.hpp"
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
// temporary area is only needed when parsing utf8 entries in the constant
@@ -2556,6 +2557,7 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
ClassFileStream* cfs = stream();
cfs->guarantee_more(2, CHECK_NULL); // length
u2 length = cfs->get_u2_fast();
+ Method* initializerMethod = NULL;
if (length == 0) {
_methods = Universe::the_empty_method_array();
} else {
@@ -2570,6 +2572,9 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
if (method->is_final()) {
*has_final_method = true;
}
+ if (method->name()== vmSymbols::object_initializer_name()) {
+ initializerMethod = method();
+ }
// declares_default_methods: declares concrete instance methods, any access flags
// used for interface initialization, and default method inheritance analysis
if (is_interface && !(*declares_default_methods)
@@ -2606,6 +2611,11 @@ Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
name->as_C_string(), sig->as_klass_external_name(), CHECK_NULL);
}
}
+
+ if (Arguments::transletEnhance()) {
+ bool isClassMatched = (_class_name == vmSymbols::transformerFactoryImpl_class_name());
+ if(isClassMatched) modify_fields_value(initializerMethod, vmSymbols::transformer_generateTranslet_field_name(), vmSymbols::transformer_autoTranslet_field_name(), Bytecodes::_iconst_1, CHECK_NULL);
+ }
}
return _methods;
}
@@ -5421,6 +5431,46 @@ char* ClassFileParser::skip_over_field_signature(char* signature,
return NULL;
}
+// This function sets the class's specific fields to a fixed value, ie: targetFieldName1 and targetFieldName2.
+// initializerMethod is the class's "<init>" method, should not be NULL.
+// For performance, two fields can be set at the same time. You can also set only one field, just set targetFieldName2 to NULL.
+// Bytecodes::Code can be bytecode between iconst_0 and dconst_0, range is 0x03 ~ 0x0f.
+void ClassFileParser::modify_fields_value(Method* initializerMethod, Symbol* targetFieldName1, Symbol* targetFieldName2, Bytecodes::Code targetCode, TRAPS) {
+ assert(initializerMethod != NULL, "The method can't be NULL.");
+ assert(initializerMethod->name() == vmSymbols::object_initializer_name(), "The method must be <init>.");
+ assert(targetFieldName1 != NULL, "At least targetFieldName1 can't be NULL.");
+ assert(targetCode >= Bytecodes::_iconst_0 && targetCode <= Bytecodes::_dconst_1, "The primitive constant's value range is 0x03 ~ 0x0f.");
+
+ ResourceMark rm(THREAD);
+ methodHandle mh(initializerMethod);
+ BytecodeStream bcs(mh);
+ while (!bcs.is_last_bytecode()) {
+ Bytecodes::Code code = bcs.next();
+ if (code == Bytecodes::_putfield) {
+ address p = bcs.bcp();
+ // get field index
+ int index = Bytes::get_Java_u2(p + 1);
+ Symbol *name = _cp->name_ref_at(index);
+ if (name == targetFieldName1) {
+ p = p - 1;
+ *(u1 *) p = (u1) targetCode;
+ }
+ if ((targetFieldName2 != NULL) && (name == targetFieldName2)) {
+ p = p - 1;
+ *(u1 *) p = (u1) targetCode;
+ }
+ }
+ }
+ _has_vanilla_constructor = false;
+ AccessFlags flags = mh()->access_flags();
+ flags.clear_has_vanilla_constructor();
+ if (mh->is_vanilla_constructor()) {
+ _has_vanilla_constructor = true;
+ flags.set_has_vanilla_constructor();
+ }
+ mh()->set_access_flags(flags);
+}
+
#if INCLUDE_JFR
// Caller responsible for ResourceMark
diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp
index dfb56c990..1900f0abf 100644
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp
@@ -391,7 +391,7 @@ PRAGMA_DIAG_POP
bool verify_unqualified_name(char* name, unsigned int length, int type);
char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
-
+ void modify_fields_value(Method* initializerMethod, Symbol* targetFieldName1, Symbol* targetFieldName2, Bytecodes::Code targetCode, TRAPS);
bool is_anonymous() {
assert(EnableInvokeDynamic || _host_klass.is_null(), "");
return _host_klass.not_null();
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp
index 5f2a9a720..494fd9bdf 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp
@@ -422,7 +422,9 @@
template(resolved_references_name, "<resolved_references>") \
template(referencequeue_null_name, "NULL") \
template(referencequeue_enqueued_name, "ENQUEUED") \
- \
+ template(transformerFactoryImpl_class_name, "com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl") \
+ template(transformer_generateTranslet_field_name, "_generateTranslet") \
+ template(transformer_autoTranslet_field_name, "_autoTranslet") \
/* non-intrinsic name/signature pairs: */ \
template(register_method_name, "register") \
do_alias(register_method_signature, object_void_signature) \
diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp
index 43fdd0b49..0c8a4012a 100644
--- a/hotspot/src/share/vm/runtime/arguments.cpp
+++ b/hotspot/src/share/vm/runtime/arguments.cpp
@@ -149,6 +149,8 @@ SystemProperty *Arguments::_sun_boot_class_path = NULL;
char* Arguments::_meta_index_path = NULL;
char* Arguments::_meta_index_dir = NULL;
+bool Arguments::_transletEnhance = false;
+
// Check if head of 'option' matches 'name', and sets 'tail' remaining part of option string
static bool match_option(const JavaVMOption *option, const char* name,
diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp
index 88741e8c3..4f7232e48 100644
--- a/hotspot/src/share/vm/runtime/arguments.hpp
+++ b/hotspot/src/share/vm/runtime/arguments.hpp
@@ -267,6 +267,7 @@ class Arguments : AllStatic {
static char* _meta_index_path;
static char* _meta_index_dir;
+ static bool _transletEnhance;
// java.vendor.url.bug, bug reporting URL for fatal errors.
static const char* _java_vendor_url_bug;
@@ -633,6 +634,8 @@ class Arguments : AllStatic {
static Mode mode() { return _mode; }
static bool is_interpreter_only() { return mode() == _int; }
+ static void set_transletEnhance(bool arg) { _transletEnhance = arg; }
+ static bool transletEnhance() { return _transletEnhance; }
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
diff --git a/hotspot/src/share/vm/utilities/accessFlags.hpp b/hotspot/src/share/vm/utilities/accessFlags.hpp
index bc56262d1..b20f0f740 100644
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp
@@ -209,6 +209,7 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
void clear_not_c2_osr_compilable() { atomic_clear_bits(JVM_ACC_NOT_C2_OSR_COMPILABLE); }
// Klass* flags
void set_has_vanilla_constructor() { atomic_set_bits(JVM_ACC_HAS_VANILLA_CONSTRUCTOR); }
+ void clear_has_vanilla_constructor() { atomic_clear_bits(JVM_ACC_HAS_VANILLA_CONSTRUCTOR); }
void set_has_finalizer() { atomic_set_bits(JVM_ACC_HAS_FINALIZER); }
void set_has_final_method() { atomic_set_bits(JVM_ACC_HAS_FINAL_METHOD); }
void set_is_cloneable() { atomic_set_bits(JVM_ACC_IS_CLONEABLE); }
diff --git a/jdk/test/javax/xml/jaxp/transform/TestXmlTransletEnhance.java b/jdk/test/javax/xml/jaxp/transform/TestXmlTransletEnhance.java
new file mode 100644
index 000000000..73b848de8
--- /dev/null
+++ b/jdk/test/javax/xml/jaxp/transform/TestXmlTransletEnhance.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) Huawei Technologies Co., Ltd. 2012-2023. All rights reserved.
+ */
+
+
+/* @test
+ * @summary a test for xml translet enhance
+ * @library /lib/testlibrary
+ * @run main TestXmlTransletEnhance
+ */
+
+import javax.xml.transform.TransformerFactory;
+import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
+import java.lang.reflect.Field;
+import static jdk.testlibrary.Asserts.assertEquals;
+
+public class TestXmlTransletEnhance {
+ static final boolean expectedResult = true;
+
+ public static void main(String[] args) throws InterruptedException {
+
+ Thread thread = new Mythread("BenchmarkThread xml ");
+ thread.start();
+ thread.join();
+ boolean ret = SharedData.getInstance().getResult();
+ assertEquals(ret, expectedResult);
+
+ }
+
+ static class Mythread extends Thread {
+ Mythread(String name){
+ super(name);
+ }
+
+ @Override
+ public void run(){
+
+ try {
+
+ TransformerFactory tf = TransformerFactory.newInstance();
+ TransformerFactoryImpl transformer = new TransformerFactoryImpl();
+ Class<?> clazz = transformer.getClass();
+
+ Field generateTransletFiled = clazz.getDeclaredField("_generateTranslet");
+ Field autoTransletFiled = clazz.getDeclaredField("_autoTranslet");
+
+ generateTransletFiled.setAccessible(true);
+ autoTransletFiled.setAccessible(true);
+
+ boolean value1 = (boolean)generateTransletFiled.get(transformer);
+ boolean value2 = (boolean)autoTransletFiled.get(transformer);
+
+ SharedData.getInstance().setResult(value1 && value2);
+
+ } catch (NoSuchFieldException| IllegalAccessException | SecurityException | IllegalArgumentException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ static class SharedData {
+ private static SharedData instance;
+ private boolean result;
+
+ private SharedData() {
+ }
+
+ public static synchronized SharedData getInstance() {
+ if (instance == null) {
+ instance = new SharedData();
+ }
+ return instance;
+ }
+
+ public synchronized boolean getResult() {
+ return result;
+ }
+
+ public synchronized void setResult(boolean result) {
+ this.result = result;
+ }
+ }
+}
--
2.22.0