Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8261956: [type-restrictions] Support RestrictedMethod in the interpreter #341

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -2722,6 +2722,18 @@ void TemplateTable::_return(TosState state) {
__ bind(skip_register_finalizer);
}

if (_desc->bytecode() == Bytecodes::_areturn) { // or should the test be state == atos ?
Label not_restricted;
__ get_method(rscratch1);
__ movzwl(rscratch1, Address(rscratch1, Method::flags_offset()));
__ andl(rscratch1, Method::_restricted_method);
__ jcc(Assembler::zero, not_restricted);
Register robj = LP64_ONLY(c_rarg1) NOT_LP64(rax);
__ movptr(robj, aaddress(0));
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::restricted_return_value_check), robj);
__ bind(not_restricted);
}

if (_desc->bytecode() != Bytecodes::_return_register_finalizer) {
Label no_safepoint;
NOT_PRODUCT(__ block_comment("Thread-local Safepoint poll"));
@@ -3916,6 +3928,19 @@ void TemplateTable::fast_xaccess(TosState state) {
//-----------------------------------------------------------------------------
// Calls

void TemplateTable::restricted_method_check(Register method) {
Label not_restricted;
__ movptr(rscratch1, method);
__ movzwl(rscratch1, Address(rscratch1, Method::flags_offset()));
__ andl(rscratch1, Method::_restricted_method);
__ jcc(Assembler::zero, not_restricted);
__ restore_bcp();
__ push(method);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::restricted_parameter_checks));
__ pop(method);
__ bind(not_restricted);
}

void TemplateTable::prepare_invoke(int byte_no,
Register method, // linked method (or i-klass)
Register index, // itable index, MethodType, etc.
@@ -4029,7 +4054,7 @@ void TemplateTable::invokevirtual_helper(Register index,
// profile this call
__ profile_final_call(rax);
__ profile_arguments_type(rax, method, rbcp, true);

restricted_method_check(method);
__ jump_from_interpreted(method, rax);

__ bind(notFinal);
@@ -4043,8 +4068,8 @@ void TemplateTable::invokevirtual_helper(Register index,
__ profile_virtual_call(rax, rlocals, rdx);
// get target Method* & entry point
__ lookup_virtual_method(rax, index, method);

__ profile_arguments_type(rdx, method, rbcp, true);
restricted_method_check(method);
__ jump_from_interpreted(method, rdx);
}

@@ -4073,6 +4098,7 @@ void TemplateTable::invokespecial(int byte_no) {
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rbcp, false);
restricted_method_check(rbx);
__ jump_from_interpreted(rbx, rax);
}

@@ -4083,6 +4109,7 @@ void TemplateTable::invokestatic(int byte_no) {
// do the call
__ profile_call(rax);
__ profile_arguments_type(rax, rbx, rbcp, false);
restricted_method_check(rbx);
__ jump_from_interpreted(rbx, rax);
}

@@ -4145,7 +4172,7 @@ void TemplateTable::invokeinterface(int byte_no) {

__ profile_final_call(rdx);
__ profile_arguments_type(rdx, rbx, rbcp, true);

restricted_method_check(rbx);
__ jump_from_interpreted(rbx, rdx);
// no return from above
__ bind(notVFinal);
@@ -4197,6 +4224,8 @@ void TemplateTable::invokeinterface(int byte_no) {

__ profile_arguments_type(rdx, rbx, rbcp, true);

restricted_method_check(rbx);

// do the call
// rcx: receiver
// rbx,: Method*
@@ -45,4 +45,6 @@

static void invoke_is_substitutable(Register aobj, Register bobj, Label& is_subst, Label& not_subst);

static void restricted_method_check(Register method);

#endif // CPU_X86_TEMPLATETABLE_X86_HPP
@@ -1472,18 +1472,6 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
_can_access_vm_annotations,
CHECK);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} else if (attribute_name == vmSymbols::tag_restricted_field()) {
check_property(
attribute_length == 2,
"Invalid RestrictedField field attribute length %u in class file %s",
attribute_length, CHECK);
const u2 type_index = cfs->get_u2_fast();
check_property(valid_symbol_at(type_index),
"Invalid constant pool index %u for field restricted type signature in class file %s",
type_index, CHECK);
*restricted_field_info = type_index;
*has_restricted_type = true;
set_has_restricted_fields();
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
@@ -1521,6 +1509,22 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(attribute_length, CHECK);
} else if (_major_version >= JAVA_17_VERSION) {
if (attribute_name == vmSymbols::tag_restricted_field()) {
check_property(
attribute_length == 2,
"Invalid RestrictedField field attribute length %u in class file %s",
attribute_length, CHECK);
const u2 type_index = cfs->get_u2_fast();
check_property(valid_symbol_at(type_index),
"Invalid constant pool index %u for field restricted type signature in class file %s",
type_index, CHECK);
*restricted_field_info = type_index;
*has_restricted_type = true;
set_has_restricted_fields();
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
@@ -2681,6 +2685,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
bool runtime_invisible_parameter_annotations_exists = false;
const u1* annotation_default = NULL;
int annotation_default_length = 0;
bool has_restricted_method_attribute = false;
const u1* restricted_param_types_start = NULL;
u2 restricted_return_type_index = 0;
u1 restricted_num_params = 0;

// Parse code and exceptions attribute
u2 method_attributes_count = cfs->get_u2_fast();
@@ -3017,6 +3025,29 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_restricted_method()) {
const u1* const current_start = cfs->current();

// RestrictedMethod_attribute {
// u2 name_index;
// u4 length;
// u1 num_params;
// u2 restricted_param_type[num_params];
// u2 restricted_return_type;
// }

has_restricted_method_attribute = true;
cfs->guarantee_more(1, CHECK_NULL); // num_params
restricted_num_params = cfs->get_u1_fast();
guarantee_property((int)method_attribute_length == restricted_num_params * 2 + 3,
"Invalid RestrictedMethod attribute length %u in class file %s",
method_attribute_length,
CHECK_NULL);

restricted_param_types_start = cfs->current();
cfs->skip_u2_fast(restricted_num_params);
cfs->guarantee_more(2, CHECK_NULL); // restricted_return_type
restricted_return_type_index = cfs->get_u2_fast();
} else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_NULL);
@@ -3056,6 +3087,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
runtime_visible_type_annotations_length +
runtime_invisible_type_annotations_length,
annotation_default_length,
// RestrictedMethod atribute requires a more complex protocol because num_params can be zeo
// but the attribute still be there because of a restricted return value
// So -1 is passed if the attribute is absent, otherwise num_params is passed
has_restricted_method_attribute ? restricted_num_params : -1 ,
0);

Method* const m = Method::allocate(_loader_data,
@@ -3159,6 +3194,18 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
annotation_default_length,
CHECK_NULL);

// Copy RestrictedMethod attribute if present
if (has_restricted_method_attribute) {
m->set_restricted_method(true);
*(m->constMethod()->restricted_num_params_addr()) = restricted_num_params;
*(m->constMethod()->restricted_return_type_index_addr()) = restricted_return_type_index;
u2* cursor = m->constMethod()->restricted_param_type_start();
for (int i = 0; i < restricted_num_params; i++) {
cursor[i] = Bytes::get_Java_u2((address)restricted_param_types_start);
restricted_param_types_start +=2;
}
}

if (name == vmSymbols::finalize_method_name() &&
signature == vmSymbols::void_method_signature()) {
if (m->is_empty_method()) {
@@ -191,6 +191,7 @@
template(tag_bootstrap_methods, "BootstrapMethods") \
template(tag_permitted_subclasses, "PermittedSubclasses") \
template(tag_restricted_field, "RestrictedField") \
template(tag_restricted_method, "RestrictedMethod") \
\
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
@@ -534,6 +534,51 @@ JRT_ENTRY(jboolean, InterpreterRuntime::is_substitutable(JavaThread* thread, oop
return result.get_jboolean();
JRT_END

JRT_ENTRY(void, InterpreterRuntime::restricted_parameter_checks(JavaThread* thread))
LastFrameAccessor last_frame(thread);
Method* caller = last_frame.method();
constantPoolHandle cph(THREAD, caller->constants());
Method* callee = last_frame.cache_entry()->method_if_resolved(cph);
assert(callee != NULL, "Something bad happened");
if (callee->has_restricted_method()) {
ResourceMark rm(THREAD);
Symbol* signature = callee->signature();
ArgumentCount args(signature);
int arg_count = args.size();
ResourceArea *area = Thread::current()->resource_area();
int* sizes = NEW_ARENA_ARRAY(area, int, arg_count);
int i = 0;
for (SignatureStream ss(signature); !ss.at_return_type(); ss.next()) {
sizes[i] = parameter_type_word_count(ss.type());
i++;
}
int tos_idx = (int)last_frame.get_frame().interpreter_frame_expression_stack_size() - 3;
for (int i = arg_count - 1; i >=0; --i) {
Klass* k = callee->restricted_param_type_at(i);
if (k != NULL) {
oop arg = *(oop*)last_frame.get_frame().interpreter_frame_expression_stack_at(tos_idx);
if (!arg->klass()->is_subtype_of(k)) {
THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
}
}
tos_idx -= sizes[i];
}
}
JRT_END

JRT_ENTRY(void, InterpreterRuntime::restricted_return_value_check(JavaThread* thread, oopDesc* obj))
LastFrameAccessor last_frame(thread);
assert(last_frame.bytecode().code() == Bytecodes::_areturn, "Only areturn should have such checks");
Method* method = last_frame.method();
constantPoolHandle cph(THREAD, method->constants());
if (method->constMethod()->has_restricted_method()) {
Klass* k = method->restricted_return_value();
if (k != NULL && !obj->klass()->is_subtype_of(k)) {
THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
}
}
JRT_END

JRT_ENTRY(void, InterpreterRuntime::check_restricted_type(JavaThread* thread))
LastFrameAccessor last_frame(thread);
ConstantPoolCacheEntry* cp_entry = last_frame.cache_entry();
@@ -75,6 +75,9 @@ class InterpreterRuntime: AllStatic {
static jboolean is_substitutable(JavaThread* thread, oopDesc* aobj, oopDesc* bobj);
static void check_restricted_type(JavaThread* thread);

static void restricted_parameter_checks(JavaThread* thread);
static void restricted_return_value_check(JavaThread* thread, oopDesc* obj);

// Quicken instance-of and check-cast bytecodes
static void quicken_io_cc(JavaThread* thread);