Unsafe value access

Paul Sandoz paul.sandoz at oracle.com
Tue Jun 27 16:47:23 UTC 2017


Thanks, Ah ValueTypeReturnedAsFields is enabled by default! i was playing around with that.

Roland, if you need a test case i can send you something.

Using -XX:-ValueTypeReturnedAsFields got me further, i have this for Unsafe.getValue:

UNSAFE_ENTRY(jobject, Unsafe_GetValue(JNIEnv *env, jobject unsafe, jobject jbase, jlong offset)) {
  oop base = JNIHandles::resolve(jbase);
  Handle base_h(THREAD, base); // is this necessary?

  InstanceKlass* base_klass = InstanceKlass::cast(base->klass());

  fieldDescriptor fd;
  base_klass->find_field_from_offset(offset, false, &fd);
  Klass* field_k = base_klass->get_value_field_klass(fd.index());
  ValueKlass* field_vklass = ValueKlass::cast(field_k);

  // allocate instance
  instanceOop res = field_vklass->allocate_instance(CHECK_NULL);
  // copy value
  int size = field_vklass->layout_helper_size_in_bytes(field_vklass->layout_helper()); // redundant?
  field_vklass->value_store(
    ((char*)(oopDesc*)base_h()) + offset, // offset in memory from base to the exploded value components
    ((char*)(oopDesc*)res) + field_vklass->first_field_offset(),
    true, false);

  ((instanceOopDesc*)res)->print();

  return JNIHandles::make_local(env, res);
} UNSAFE_END

The print verifies the value is being copied in the instanceOop “buffer".

But the value returned in Java is null. Same applies for the identity function i showed previously.

Paul.

P.S. do you use lldb on a mac, if so how does not enable the debugger to get access to the HS sources. Perhaps i need to enable a full debug build?


> On 27 Jun 2017, at 08:36, Frederic Parain <frederic.parain at oracle.com> wrote:
> 
> Paul,
> 
> This looks like an issue with the calling convention returning values
> in registers. The store_value_type_fields_to_buf stub is trying the
> reconstruct a value types from fields in registers, it calls into
> the runtime without changing the thread state (which remains
> _thread_in_Java) and the method in sharedRuntime then tries to
> lock the SystemDictionary which causes the assertion failure.
> 
> You can try -XX:-ValueTypeReturnedAsFields to test if this is
> effectively the return convention that causes the issue.
> 
> If this is the case, I'd recommend to contact Roland, as the
> author of the calling/returning convention, he knows all the
> details of this code.
> 
> Regards,
> 
> Fred
> 
> On 06/27/2017 10:57 AM, Paul Sandoz wrote:
>> Hi Fred,
>> I am running into a crash that i think is related to returning a __Value from a JNI method.
>> Say i have the simplest of methods, an identity function:
>>   public native __Value getValueIdentity(__Value o);
>> Implementing that in unsafe.cpp:
>>   UNSAFE_ENTRY(jobject, Unsafe_GetValueIdentity(JNIEnv *env, jobject unsafe, jobject jbase)) {
>>       return jbase;
>>   } UNSAFE_END
>> And calling from Java i get a crash, after calling the call of the Java method but AFAICT before the next Java expression/statement is executed, i think in generated stub code trying to handle the returned value:
>> #  Internal Error (/Users/sandoz/Projects/jdk10/valhalla/hotspot/src/share/vm/runtime/mutex.cpp:1384), pid=75592, tid=5123
>> #  assert((!thread->is_Java_thread() || ((JavaThread *)thread)->thread_state() == _thread_in_vm) || rank() == Mutex::special) failed: wrong thread state for using locks
>> ...
>> V  [libjvm.dylib+0xc9e274]  VMError::report_and_die(int, char const*, char const*, __va_list_tag*, Thread*, unsigned char*, void*, void*, char const*, int, unsigned long)+0x4d4
>> V  [libjvm.dylib+0xc9ea36]  VMError::report_and_die(Thread*, char const*, int, char const*, char const*, __va_list_tag*)+0x4a
>> V  [libjvm.dylib+0x4cc421]  report_vm_error(char const*, int, char const*, char const*, ...)+0xcd
>> V  [libjvm.dylib+0xa45f8b]  Monitor::check_prelock_state(Thread*)+0x67
>> V  [libjvm.dylib+0xa45c39]  Monitor::lock(Thread*)+0x97
>> V  [libjvm.dylib+0xbf4b4a]  SystemDictionary::add_loader_constraint(Symbol*, Handle, Handle, Thread*)+0x138
>> V  [libjvm.dylib+0xbf4ec0]  SystemDictionary::check_signature_loaders(Symbol*, Handle, Handle, bool, Thread*)+0xde
>> V  [libjvm.dylib+0x8e45eb]  LinkResolver::check_method_loader_constraints(LinkInfo const&, methodHandle const&, char const*, Thread*)+0x283
>> V  [libjvm.dylib+0x8e3c07]  LinkResolver::resolve_method(LinkInfo const&, Bytecodes::Code, Thread*)+0x48f
>> V  [libjvm.dylib+0x8e3752]  LinkResolver::resolve_method_statically(Bytecodes::Code, constantPoolHandle const&, int, Thread*)+0x210
>> V  [libjvm.dylib+0x28ee39]  Bytecode_invoke::static_target(Thread*)+0x7b
>> V  [libjvm.dylib+0xb666a2]  SharedRuntime::store_value_type_fields_to_buf(JavaThread*, long)+0x1b2
>> v  ~RuntimeStub::store_value_type_fields_to_buf
>> j  UnsafeTest.main([Ljava/lang/String;)V+40
>> Any clues to what is going on or how to further debug?
>> Paul.
>>> On 22 Jun 2017, at 12:28, Frederic Parain <frederic.parain at oracle.com> wrote:
>>> 
>>> Paul,
>>> 
>>> For the interpreter, the implementation of getfield/putfield for value fields is split
>>> between an assembly template and some runtime methods.
>>> 
>>> The assembly template can be found in src/cpu/x86/vm/templateTable_x86.cpp,
>>> look for this method:
>>> 
>>> void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc, bool is_vgetfield)
>>> 
>>> The runtime support can be found in src/share/vm/interpreter/interpreterRuntime.cpp,
>>> look for methods InterpreterRuntime::qgetfield(JavaThread* thread, oopDesc* value, int offset)
>>> and InterpreterRuntime::qputfield(JavaThread* thread, oopDesc* obj, oopDesc* value, int offset).
>>> 
>>> Mr Simms did a number of experiments at the beginning of the project to measure
>>> the cost of the different solutions to provide atomicity, I would recommend to sync
>>> with him.
>>> 
>>> Regards,
>>> 
>>> Fred
>>> 
>>> 
>>>> On Jun 22, 2017, at 15:18, Paul Sandoz <paul.sandoz at oracle.com> wrote:
>>>> 
>>>> Hi,
>>>> 
>>>> To start working on VarHandle integration i first of all need unsafe access to values held within objects. For a most basic initial implementation we can use a global lock to preserve atomicity and memory ordering effects and defer the thinking about more sophisticated locking (seq locks etc), read-mody-write operations and other memory order effects to a another day.
>>>> 
>>>> For these purposes we just require two methods:
>>>> 
>>>> __Value getValue(Object base, long offset, Class<? extends Value> vt)
>>>> 
>>>> void putValue(Object base, long offset, Class<? extends Value> vt, __Value v);
>>>> 
>>>> I included Class parameter for the value type token.
>>>> 
>>>> How feasible would it be to implement such methods?
>>>> 
>>>> If people point me to the hotspot interpreter code for getfield/putfield implementations for values i might be able to make some progress. Once that is done we could then consider C1/C2 support.
>>>> 
>>>> Thoughts?
>>>> 
>>>> Thanks,
>>>> Paul.
>>>> 
>>>> 
>>> 



More information about the valhalla-dev mailing list