Skip to content

Commit

Permalink
Compiler Prototyping for Deconstructors
Browse files Browse the repository at this point in the history
Co-authored-by: Angelos Bimpoudis <[email protected]>
Co-authored-by: Jan Lahoda <[email protected]>
Co-authored-by: Vicente Romero <[email protected]>
  • Loading branch information
3 people committed Jun 6, 2024
1 parent 3634a91 commit 5246297
Show file tree
Hide file tree
Showing 121 changed files with 5,312 additions and 199 deletions.
66 changes: 65 additions & 1 deletion src/hotspot/share/classfile/classFileParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2341,6 +2341,11 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
const u1* annotation_default = nullptr;
int annotation_default_length = 0;

int pattern_length = 0;
const u1* pattern_runtime_visible_parameter_annotations = nullptr;
int pattern_runtime_visible_parameter_annotations_length = 0;
bool is_pattern = false;

// Parse code and exceptions attribute
u2 method_attributes_count = cfs->get_u2_fast();
while (method_attributes_count--) {
Expand Down Expand Up @@ -2675,7 +2680,64 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
assert(runtime_invisible_type_annotations != nullptr, "null invisible type annotations");
}
cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else {
}
else if (method_attribute_name == vmSymbols::tag_pattern()) {
cfs->guarantee_more(6, CHECK_NULL); // pattern_name_index, pattern_flags, pattern_methodtype_index

const u2 pattern_name_index = cfs->get_u2_fast();
check_property(
valid_symbol_at(pattern_name_index),
"Invalid pattern attribute name index %u in class file %s",
pattern_name_index, CHECK_NULL);
const Symbol *const pattern_name = cp->symbol_at(pattern_name_index);

const u2 pattern_flags = cfs->get_u2_fast();

const u2 pattern_methodtype_index = cfs->get_u2_fast();
guarantee_property(
valid_symbol_at(pattern_methodtype_index),
"Illegal constant pool index %u for pattern method type in class file %s",
pattern_methodtype_index, CHECK_NULL);
const Symbol* const signature = cp->symbol_at(pattern_methodtype_index);

is_pattern = true;

cfs->guarantee_more(2, CHECK_NULL); // pattern_method_attributes_count

u2 pattern_method_attributes_count = cfs->get_u2_fast();
while (pattern_method_attributes_count--) {
cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length
const u2 pattern_method_attribute_name_index = cfs->get_u2_fast();
const u4 pattern_method_attribute_length = cfs->get_u4_fast();
check_property(
valid_symbol_at(pattern_method_attribute_name_index),
"Invalid pattern method attribute name index %u in class file %s",
pattern_method_attribute_name_index, CHECK_NULL);

const Symbol *const pattern_method_attribute_name = cp->symbol_at(pattern_method_attribute_name_index);

if (pattern_method_attribute_name == vmSymbols::tag_method_parameters()) {
const int pattern_method_parameters_length = cfs->get_u1_fast();

cfs->skip_u2_fast(pattern_method_parameters_length);
cfs->skip_u2_fast(pattern_method_parameters_length);
}
else if (pattern_method_attribute_name == vmSymbols::tag_signature()) {
const int pattern_signature_data = parse_generic_signature_attribute(cfs, CHECK_NULL);
} else if (pattern_method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
if (runtime_visible_type_annotations != nullptr) {
classfile_parse_error(
"Multiple RuntimeVisibleTypeAnnotations attributes for pattern method in class file %s",
THREAD);
return nullptr;
}
pattern_runtime_visible_parameter_annotations_length = pattern_method_attribute_length;
pattern_runtime_visible_parameter_annotations = cfs->current();
cfs->skip_u1(pattern_runtime_visible_parameter_annotations_length, CHECK_NULL);
}
}
}
else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_NULL);
}
Expand Down Expand Up @@ -2730,6 +2792,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
m->set_constants(_cp);
m->set_name_index(name_index);
m->set_signature_index(signature_index);
m->set_is_pattern(is_pattern);

m->constMethod()->compute_from_signature(cp->symbol_at(signature_index), access_flags.is_static());
assert(args_size < 0 || args_size == m->size_of_parameters(), "");

Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class SerializeClosure;
template(tag_enclosing_method, "EnclosingMethod") \
template(tag_bootstrap_methods, "BootstrapMethods") \
template(tag_permitted_subclasses, "PermittedSubclasses") \
template(tag_pattern, "Pattern") \
\
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/include/jvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,8 @@ JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly);
JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly);

JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredDeconstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly);

/* Differs from JVM_GetClassModifiers in treatment of inner classes.
This returns the access flags for the class as specified in the
Expand Down
28 changes: 28 additions & 0 deletions src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2161,6 +2161,33 @@ C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, ARGUME
return JVMCIENV->get_jobjectArray(methods);
C2V_END

C2V_VMENTRY_NULL(jobjectArray, getDeclaredDeconstructors, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
Klass* klass = UNPACK_PAIR(Klass, klass);
if (klass == nullptr) {
JVMCI_THROW_0(NullPointerException);
}
if (!klass->is_instance_klass()) {
JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(0, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobjectArray(methods);
}

InstanceKlass* iklass = InstanceKlass::cast(klass);
GrowableArray<Method*> methods_array;
for (int i = 0; i < iklass->methods()->length(); i++) {
Method* m = iklass->methods()->at(i);
if (!m->is_initializer() && !m->is_overpass() && m->is_pattern()) {
methods_array.append(m);
}
}
JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(methods_array.length(), JVMCI_CHECK_NULL);
for (int i = 0; i < methods_array.length(); i++) {
methodHandle mh(THREAD, methods_array.at(i));
JVMCIObject method = JVMCIENV->get_jvmci_method(mh, JVMCI_CHECK_NULL);
JVMCIENV->put_object_at(methods, i, method);
}
return JVMCIENV->get_jobjectArray(methods);
C2V_END

C2V_VMENTRY_NULL(jobjectArray, getDeclaredFieldsInfo, (JNIEnv* env, jobject, ARGUMENT_PAIR(klass)))
Klass* klass = UNPACK_PAIR(Klass, klass);
if (klass == nullptr) {
Expand Down Expand Up @@ -3285,6 +3312,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "boxPrimitive", CC "(" OBJECT ")" OBJECTCONSTANT, FN_PTR(boxPrimitive)},
{CC "getDeclaredConstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredConstructors)},
{CC "getDeclaredMethods", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredMethods)},
{CC "getDeclaredDeconstructors", CC "(" HS_KLASS2 ")[" RESOLVED_METHOD, FN_PTR(getDeclaredDeconstructors)},
{CC "getDeclaredFieldsInfo", CC "(" HS_KLASS2 ")[" FIELDINFO, FN_PTR(getDeclaredFieldsInfo)},
{CC "readStaticFieldValue", CC "(" HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readStaticFieldValue)},
{CC "readFieldValue", CC "(" OBJECTCONSTANT HS_KLASS2 "JC)" JAVACONSTANT, FN_PTR(readFieldValue)},
Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/oops/constMethod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ class ConstMethod : public MetaspaceObj {
u2 _code_size;
u2 _name_index; // Method name (index in constant pool)
u2 _signature_index; // Method signature (index in constant pool)
bool _is_pattern_flag; // Pattern method (index in constant pool)

u2 _method_idnum; // unique identification number for the method within the class
// initially corresponds to the index into the methods array.
// but this may change with redefinition
Expand Down Expand Up @@ -296,6 +298,10 @@ class ConstMethod : public MetaspaceObj {
u2 signature_index() const { return _signature_index; }
void set_signature_index(int index) { _signature_index = checked_cast<u2>(index); }

// pattern
bool is_pattern() const { return _is_pattern_flag; }
void set_is_pattern(bool b) { _is_pattern_flag = b; }

// generics support
u2 generic_signature_index() const {
if (has_generic_signature()) {
Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/oops/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ class Method : public Metadata {
u2 signature_index() const { return constMethod()->signature_index(); }
void set_signature_index(int index) { constMethod()->set_signature_index(index); }

// pattern
u2 is_pattern() const { return constMethod()->is_pattern(); }
void set_is_pattern(bool b) { constMethod()->set_is_pattern(b); }

// generics support
Symbol* generic_signature() const { int idx = generic_signature_index(); return ((idx != 0) ? constants()->symbol_at(idx) : nullptr); }
u2 generic_signature_index() const { return constMethod()->generic_signature_index(); }
Expand Down
78 changes: 78 additions & 0 deletions src/hotspot/share/prims/jvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,84 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredMethods(JNIEnv *env, jclass ofClass,
}
JVM_END

static jobjectArray get_class_declared_deconstructors_helper(
JNIEnv *env,
jclass ofClass, jboolean publicOnly,
bool want_constructor,
Klass* klass, TRAPS) {

JvmtiVMObjectAllocEventCollector oam;

oop ofMirror = JNIHandles::resolve_non_null(ofClass);
// Exclude primitive types and array types
if (java_lang_Class::is_primitive(ofMirror)
|| java_lang_Class::as_Klass(ofMirror)->is_array_klass()) {
// Return empty array
oop res = oopFactory::new_objArray(klass, 0, CHECK_NULL);
return (jobjectArray) JNIHandles::make_local(THREAD, res);
}

InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(ofMirror));

// Ensure class is linked
k->link_class(CHECK_NULL);

Array<Method*>* methods = k->methods();
int methods_length = methods->length();

// Save original method_idnum in case of redefinition, which can change
// the idnum of obsolete methods. The new method will have the same idnum
// but if we refresh the methods array, the counts will be wrong.
ResourceMark rm(THREAD);
GrowableArray<int>* idnums = new GrowableArray<int>(methods_length);
int num_methods = 0;

for (int i = 0; i < methods_length; i++) {
methodHandle method(THREAD, methods->at(i));
if (select_method(method, want_constructor)) {
if ((!publicOnly || method->is_public()) && method->is_pattern()) {
idnums->push(method->method_idnum());
++num_methods;
}
}
}

// Allocate result
objArrayOop r = oopFactory::new_objArray(klass, num_methods, CHECK_NULL);
objArrayHandle result (THREAD, r);

// Now just put the methods that we selected above, but go by their idnum
// in case of redefinition. The methods can be redefined at any safepoint,
// so above when allocating the oop array and below when creating reflect
// objects.
for (int i = 0; i < num_methods; i++) {
methodHandle method(THREAD, k->method_with_idnum(idnums->at(i)));
if (method.is_null()) {
// Method may have been deleted and seems this API can handle null
// Otherwise should probably put a method that throws NSME
result->obj_at_put(i, nullptr);
} else {
oop m;
if (want_constructor) {
m = Reflection::new_constructor(method, CHECK_NULL);
} else {
m = Reflection::new_method(method, false, CHECK_NULL);
}
result->obj_at_put(i, m);
}
}

return (jobjectArray) JNIHandles::make_local(THREAD, result());
}

JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredDeconstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
return get_class_declared_deconstructors_helper(env, ofClass, publicOnly,
/*want_constructor*/ false,
vmClasses::reflect_Method_klass(), THREAD);
}
JVM_END

JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly))
{
return get_class_declared_methods_helper(env, ofClass, publicOnly,
Expand Down
Loading

0 comments on commit 5246297

Please sign in to comment.