277 lines
12 KiB
Diff
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
|
||
|
|
|