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

8263776: [JVMCI] add helper to perform Java upcalls #279

Changes from 2 commits
File filter
Filter by extension
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -409,6 +409,115 @@ JRT_ENTRY(void, JVMCIRuntime::throw_class_cast_exception(JavaThread* thread, con
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);

class ArgumentPusher : public SignatureIterator {
JavaCallArguments* _jca;
jlong _argument;
bool _pushed;

jlong next_arg(BasicType expectedType) {
guarantee(!_pushed, "one argument");
_pushed = true;
return _argument;

float next_float() {
guarantee(!_pushed, "one argument");
_pushed = true;
jvalue v;
v.i = (jint) _argument;
return v.f;

double next_double() {
guarantee(!_pushed, "one argument");
_pushed = true;
jvalue v;
v.j = _argument;
return v.d;

Handle next_object() {
guarantee(!_pushed, "one argument");
_pushed = true;
return Handle(Thread::current(), (oop) (address) _argument);

ArgumentPusher(Symbol* signature, JavaCallArguments* jca, jlong argument, bool is_static) : SignatureIterator(signature) {
this->_return_type = T_ILLEGAL;
_jca = jca;
_argument = argument;
_pushed = false;

inline void do_object() { _jca->push_oop(next_object()); }

inline void do_bool() { if (!is_return_type()) _jca->push_int((jboolean) next_arg(T_BOOLEAN)); }
inline void do_char() { if (!is_return_type()) _jca->push_int((jchar) next_arg(T_CHAR)); }
inline void do_short() { if (!is_return_type()) _jca->push_int((jint) next_arg(T_SHORT)); }
inline void do_byte() { if (!is_return_type()) _jca->push_int((jbyte) next_arg(T_BYTE)); }
inline void do_int() { if (!is_return_type()) _jca->push_int((jint) next_arg(T_INT)); }

inline void do_long() { if (!is_return_type()) _jca->push_long((jlong) next_arg(T_LONG)); }
inline void do_float() { if (!is_return_type()) _jca->push_float(next_float()); }
inline void do_double() { if (!is_return_type()) _jca->push_double(next_double()); }

inline void do_object(int begin, int end) { if (!is_return_type()) do_object(); }
inline void do_array(int begin, int end) { if (!is_return_type()) do_object(); }

inline void do_void() { }

JRT_ENTRY(jlong, JVMCIRuntime::invoke_static_method_one_arg(JavaThread* thread, Method* method, jlong argument))
ResourceMark rm;
HandleMark hm;

methodHandle mh(thread, method);
if (mh->size_of_parameters() > 1 && !mh->is_static()) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Invoked method must be static and take at most one argument");

Symbol* signature = mh->signature();
JavaCallArguments jca(mh->size_of_parameters());
ArgumentPusher jap(signature, &jca, argument, mh->is_static());
JavaValue result(jap.get_ret_type());
JavaCalls::call(&result, mh, &jca, CHECK_0);

if (jap.get_ret_type() == T_VOID) {
return 0;
} else if (jap.get_ret_type() == T_OBJECT || jap.get_ret_type() == T_ARRAY) {
thread->set_vm_result((oop) result.get_jobject());
return 0;
} else {
jvalue *value = (jvalue *) result.get_value_addr();
// Narrow the value down if required (Important on big endian machines)
switch (jap.get_ret_type()) {
return (jboolean) value->i;
case T_BYTE:
return (jbyte) value->i;
case T_CHAR:
return (jchar) value->i;
case T_SHORT:
return (jshort) value->i;
case T_INT:
return value->i;
case T_LONG:
return value->j;
case T_FLOAT:
return value->f;
case T_DOUBLE:
return value->d;
This conversation was marked as resolved by jerboaa
Comment on lines +510 to +513

This comment has been minimized.


shipilev Aug 23, 2021
Contributor Outdated

The original commit uses value->i and value->j here. Of course, value->f and value->d look more correct, but do you understand why this difference?

This comment has been minimized.


jerboaa Aug 23, 2021
Author Contributor Outdated

The original change handles T_INT and T_FLOAT (same bit width) with a single case statement. Same for T_DOUBLE and T_LONG. Therefore returning the more generic union types value->i and value->j respectively. I'm not sure this actually makes any difference. This seems the cleaner way to handle it.

This comment has been minimized.


shipilev Aug 24, 2021
Contributor Outdated

Yeah, I don't see the difference, but I think this is how we do conversions: put the jdouble to value->d, read jlong from value->j. Since this method returns jlong, I would expect value->j here. See e.g. next_double() in this patch.

Note that if we do ->f, ->d for T_FLOAT and T_DOUBLE, then it is reasonable to expect T_BOOLEAN and friends also replaced by their own type-specific union fields.

I would personally like to match mainline here, and then maybe clean up mainline, then backport the cleanup as the follow-up.

This comment has been minimized.


jerboaa Aug 24, 2021
Author Contributor Outdated

Sure. I've also noticed that there are minor differences to the JDK 17 version (local return_type variable over jap.get_ret_type()). Will fix. Thanks!

return 0;

JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, bool as_string, bool newline))
ttyLocker ttyl;

@@ -160,6 +160,11 @@ class JVMCIRuntime: public AllStatic {
// Forces initialization of the JVMCI runtime.
static void force_initialization(TRAPS);

// A helper to allow invocation of an arbitrary Java method. For simplicity the method is
// restricted to a static method that takes at most one argument. For calling convention
// simplicty all types are passed by being converted into a jlong
static jlong invoke_static_method_one_arg(JavaThread* thread, Method* method, jlong argument);

// Test only function
static int test_deoptimize_call_int(JavaThread* thread, int value);
@@ -632,6 +632,8 @@
declare_function(JVMCIRuntime::dynamic_new_array) \
declare_function(JVMCIRuntime::dynamic_new_instance) \
declare_function(JVMCIRuntime::invoke_static_method_one_arg) \
declare_function(JVMCIRuntime::thread_is_interrupted) \
declare_function(JVMCIRuntime::vm_message) \
declare_function(JVMCIRuntime::identity_hash_code) \