ARM: Support for JVMTI notifications from JIT compiler on code generation

Andrew Haley aph at redhat.com
Wed Apr 25 06:28:38 PDT 2012


On 04/25/2012 01:49 PM, Andrew Dinn wrote:
> This is a patch against
> http://icedtea.classpath.org/hg/release/icedtea7-forest-2.1/hotspot
> 
> It modifies the ARM JIT to post JVMTI events whenever native code is
> generated from Java method bytecode, providing details of the class
> andmethod name, the generated code address range and a mapping from
> address subranges to bytecode indices. That's enough to allow oprofile
> to provide line by line profiling information.
> 
> This has been tested with the oprofile Java agent and the resulting
> behaviour appears to be compatible with behaviour on x86. However, this
> is not a full test as oprofile is not fully working in the latest
> available ARM kernel. This means that the data generated by the agent in
> response to the JVMTI events has not yet been properly consumed and
> processed.
> 
> I have asked Andrew Haley to review this patch.

But if anyone else wants to join in...

> diff -r a5d04cb60a5c -r fada6a7d5e89 src/cpu/zero/vm/thumb2.cpp
> --- a/src/cpu/zero/vm/thumb2.cpp	Wed Apr 11 09:24:03 2012 -0400
> +++ b/src/cpu/zero/vm/thumb2.cpp	Wed Apr 25 13:43:33 2012 +0100
> @@ -440,6 +440,12 @@
>  unsigned stack[1000];
>  unsigned r_local[1000];
>  
> +// jvmti needs to map start address of generated code for a bytecode
> +// to corrsponding bytecode index so agents can correlate code address
> +// ranges with bci and thence line number
> +jvmtiAddrLocationMap address_bci_map[THUMB2_MAX_BYTECODE_SIZE];

I presume that there need only be one of these because it is only
accessed under lock.  However, it's 160kbytes in size.  It
might be a better idea to allocate the space at runtime: not every
VM runs the JIT.

>    jinfo_str.code_base = code_base;
> @@ -7580,6 +7597,27 @@
>    if (compiled_offset == 0) return 0;
>    thumb_entry.compiled_entrypoint = slow_entry + compiled_offset;
>    thumb_entry.osr_entry = (unsigned)cmethod->osr_entry | TBIT;
> +  {
> +    // we need to notify a Jvmti compiled_method_load event
> +
> +    // notify the whole generated code region for this Java method
> +    // from slow_entry through to the end of the osr table. some
> +    // of it is data not code but that's not a problem.

I have a personal preference for sentences in comments.


> +
> +    const void *gen_code_start = (const void *)(slow_entry ^ TBIT);
> +    unsigned gen_code_size = codebuf_str.idx * 2;
> +
> +    // address_bci_map translates start addresses for generated code
> +    // sections to bytecode indices
> +
> +    // the final compile_info argument is supposed to contain
> +    // information about inlined code. we can supply NULL for now -
> +    // oprofile doesn't use it anyway
> +
> +    void *compile_info = NULL;
> +
> +    JvmtiExport::post_compiled_method_load(method, gen_code_size, gen_code_start, address_bci_map_length, address_bci_map, NULL);

Please avoid lines so long that they wrap.

> +  }
>    return *(unsigned long long *)&thumb_entry;
>  }
>  
> diff -r a5d04cb60a5c -r fada6a7d5e89 src/share/vm/prims/jvmtiExport.cpp
> --- a/src/share/vm/prims/jvmtiExport.cpp	Wed Apr 11 09:24:03 2012 -0400
> +++ b/src/share/vm/prims/jvmtiExport.cpp	Wed Apr 25 13:43:33 2012 +0100
> @@ -1776,6 +1776,48 @@
>    }
>  }
>  
> +#ifdef __arm__
> +
> +// special compiled_method_load notify API for thumb2 compiler
> +
> +void JvmtiExport::post_compiled_method_load(const methodOop method, const jint length,
> +                                            const void *code_begin, const jint map_length,
> +                                            const jvmtiAddrLocationMap* map,
> +					    const void *compile_info)
> +{
> +  JavaThread* thread = JavaThread::current();
> +  jmethodID methodId = method->jmethod_id();
> +
> +  EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
> +                 ("JVMTI [%s] method compile load event triggered (by thumb2_compile)",
> +                 JvmtiTrace::safe_get_thread_name(thread)));
> +
> +  JvmtiEnvIterator it;
> +  for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
> +    if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) {
> +
> +      EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
> +                ("JVMTI [%s] class compile method load event sent %s.%s   (by thumb2_compile)",
> +                JvmtiTrace::safe_get_thread_name(thread),
> +                method->klass_name()->as_C_string(),
> +		 method->name()->as_C_string()));
> +
> +      // I think we need this to add a resource mark and handle for
> +      // the thread and record a vm to native (agent lib) transition
> +
> +      JvmtiJavaThreadEventTransition jet(thread);
> +      jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
> +
> +      if (callback != NULL) {
> +        (*callback)(env->jvmti_external(), methodId,
> +                    length, code_begin, map_length,
> +                    map, compile_info);
> +      }
> +    }
> +  }
> +}
> +
> +#endif // __arm__

This is a bit unfortunate.  I presume we have to do it because JvmtiExport
doesn't give us what we need.

Andrew.



More information about the distro-pkg-dev mailing list