6580131: 3/4 CompiledMethodLoad events don't produce the expected extra notifications to describe inlining
authordcubed
Wed, 13 Jan 2010 09:39:46 -0700 (2010-01-13)
changeset 4732 a70548606f73
parent 4491 212bd48525d4
child 4733 27a7366e12da
child 4762 c75b48e6b250
6580131: 3/4 CompiledMethodLoad events don't produce the expected extra notifications to describe inlining Summary: Add support for additional implementation specific info to the JVM/TI CompiledMethodLoad event via the compile_info parameter. Reviewed-by: never, ohair, tbell, tdeneau Contributed-by: Vasanth Venkatachalam <vasanth.venkatachalam@amd.com>
hotspot/make/Makefile
hotspot/make/defs.make
hotspot/src/share/vm/code/jvmticmlr.h
hotspot/src/share/vm/includeDB_core
hotspot/src/share/vm/prims/jvmtiExport.cpp
--- a/hotspot/make/Makefile	Mon Dec 14 10:05:36 2009 -0700
+++ b/hotspot/make/Makefile	Wed Jan 13 09:39:46 2010 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2005-2010 Sun Microsystems, Inc.  All Rights Reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -281,10 +281,13 @@
 $(EXPORT_LIB_DIR)/%.jar: $(GEN_DIR)/%.jar
 	$(install-file)
 
-# Include files (jvmti.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h)
+# Include files (jvmti.h, jvmticmlr.h, jni.h, $(JDK_INCLUDE_SUBDIR)/jni_md.h, jmm.h)
 $(EXPORT_INCLUDE_DIR)/%: $(GEN_DIR)/jvmtifiles/%
 	$(install-file)
 
+$(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/code/%
+	$(install-file)
+
 $(EXPORT_INCLUDE_DIR)/%: $(HS_SRC_DIR)/share/vm/prims/%
 	$(install-file)
 
--- a/hotspot/make/defs.make	Mon Dec 14 10:05:36 2009 -0700
+++ b/hotspot/make/defs.make	Wed Jan 13 09:39:46 2010 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright 2006-2008 Sun Microsystems, Inc.  All Rights Reserved.
+# Copyright 2006-2010 Sun Microsystems, Inc.  All Rights Reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -259,6 +259,7 @@
 
 # Common export list of files
 EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jvmti.h
+EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jvmticmlr.h
 EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jni.h
 EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/$(JDK_INCLUDE_SUBDIR)/jni_md.h
 EXPORT_LIST += $(EXPORT_INCLUDE_DIR)/jmm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/code/jvmticmlr.h	Wed Jan 13 09:39:46 2010 -0700
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This header file defines the data structures sent by the VM
+ * through the JVMTI CompiledMethodLoad callback function via the
+ * "void * compile_info" parameter. The memory pointed to by the
+ * compile_info parameter may not be referenced after returning from
+ * the CompiledMethodLoad callback. These are VM implementation
+ * specific data structures that may evolve in future releases. A
+ * JVMTI agent should interpret a non-NULL compile_info as a pointer
+ * to a region of memory containing a list of records. In a typical
+ * usage scenario, a JVMTI agent would cast each record to a
+ * jvmtiCompiledMethodLoadRecordHeader, a struct that represents
+ * arbitrary information. This struct contains a kind field to indicate
+ * the kind of information being passed, and a pointer to the next
+ * record. If the kind field indicates inlining information, then the
+ * agent would cast the record to a jvmtiCompiledMethodLoadInlineRecord.
+ * This record contains an array of PCStackInfo structs, which indicate
+ * for every pc address what are the methods on the invocation stack.
+ * The "methods" and "bcis" fields in each PCStackInfo struct specify a
+ * 1-1 mapping between these inlined methods and their bytecode indices.
+ * This can be used to derive the proper source lines of the inlined
+ * methods.
+ */
+
+#ifndef _JVMTI_CMLR_H_
+#define _JVMTI_CMLR_H_
+
+enum {
+    JVMTI_CMLR_MAJOR_VERSION_1 = 0x00000001,
+    JVMTI_CMLR_MINOR_VERSION_0 = 0x00000000,
+
+    JVMTI_CMLR_MAJOR_VERSION   = 0x00000001,
+    JVMTI_CMLR_MINOR_VERSION   = 0x00000000
+
+    /*
+     * This comment is for the "JDK import from HotSpot" sanity check:
+     * version: 1.0.0
+     */
+};
+
+typedef enum {
+    JVMTI_CMLR_DUMMY       = 1,
+    JVMTI_CMLR_INLINE_INFO = 2
+} jvmtiCMLRKind;
+
+/*
+ * Record that represents arbitrary information passed through JVMTI
+ * CompiledMethodLoadEvent void pointer.
+ */
+typedef struct _jvmtiCompiledMethodLoadRecordHeader {
+  jvmtiCMLRKind kind;     /* id for the kind of info passed in the record */
+  jint majorinfoversion;  /* major and minor info version values. Init'ed */
+  jint minorinfoversion;  /* to current version value in jvmtiExport.cpp. */
+
+  struct _jvmtiCompiledMethodLoadRecordHeader* next;
+} jvmtiCompiledMethodLoadRecordHeader;
+
+/*
+ * Record that gives information about the methods on the compile-time
+ * stack at a specific pc address of a compiled method. Each element in
+ * the methods array maps to same element in the bcis array.
+ */
+typedef struct _PCStackInfo {
+  void* pc;             /* the pc address for this compiled method */
+  jint numstackframes;  /* number of methods on the stack */
+  jmethodID* methods;   /* array of numstackframes method ids */
+  jint* bcis;           /* array of numstackframes bytecode indices */
+} PCStackInfo;
+
+/*
+ * Record that contains inlining information for each pc address of
+ * an nmethod.
+ */
+typedef struct _jvmtiCompiledMethodLoadInlineRecord {
+  jvmtiCompiledMethodLoadRecordHeader header;  /* common header for casting */
+  jint numpcs;          /* number of pc descriptors in this nmethod */
+  PCStackInfo* pcinfo;  /* array of numpcs pc descriptors */
+} jvmtiCompiledMethodLoadInlineRecord;
+
+/*
+ * Dummy record used to test that we can pass records with different
+ * information through the void pointer provided that they can be cast
+ * to a jvmtiCompiledMethodLoadRecordHeader.
+ */
+
+typedef struct _jvmtiCompiledMethodLoadDummyRecord {
+  jvmtiCompiledMethodLoadRecordHeader header;  /* common header for casting */
+  char message[50];
+} jvmtiCompiledMethodLoadDummyRecord;
+
+#endif
--- a/hotspot/src/share/vm/includeDB_core	Mon Dec 14 10:05:36 2009 -0700
+++ b/hotspot/src/share/vm/includeDB_core	Wed Jan 13 09:39:46 2010 -0700
@@ -1,5 +1,5 @@
 //
-// Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+// Copyright 1997-2010 Sun Microsystems, Inc.  All Rights Reserved.
 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 //
 // This code is free software; you can redistribute it and/or modify it
@@ -2500,6 +2500,7 @@
 jvmtiExport.hpp                         handles.hpp
 jvmtiExport.hpp                         iterator.hpp
 jvmtiExport.hpp                         jvmti.h
+jvmtiExport.hpp                         jvmticmlr.h
 jvmtiExport.hpp                         oop.hpp
 jvmtiExport.hpp                         oopsHierarchy.hpp
 
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp	Mon Dec 14 10:05:36 2009 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp	Wed Jan 13 09:39:46 2010 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2010 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -686,11 +686,11 @@
   jvmtiAddrLocationMap *_map;
   const void *_compile_info;
  public:
-  JvmtiCompiledMethodLoadEventMark(JavaThread *thread, nmethod *nm)
+  JvmtiCompiledMethodLoadEventMark(JavaThread *thread, nmethod *nm, void* compile_info_ptr = NULL)
           : JvmtiMethodEventMark(thread,methodHandle(thread, nm->method())) {
     _code_data = nm->code_begin();
     _code_size = nm->code_size();
-    _compile_info = NULL; /* no info for our VM. */
+    _compile_info = compile_info_ptr; // Set void pointer of compiledMethodLoad Event. Default value is NULL.
     JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &_map, &_map_length);
   }
   ~JvmtiCompiledMethodLoadEventMark() {
@@ -1752,6 +1752,46 @@
   }
 }
 
+// Returns a record containing inlining information for the given nmethod
+jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) {
+  jint numstackframes = 0;
+  jvmtiCompiledMethodLoadInlineRecord* record = (jvmtiCompiledMethodLoadInlineRecord*)NEW_RESOURCE_OBJ(jvmtiCompiledMethodLoadInlineRecord);
+  record->header.kind = JVMTI_CMLR_INLINE_INFO;
+  record->header.next = NULL;
+  record->header.majorinfoversion = JVMTI_CMLR_MAJOR_VERSION_1;
+  record->header.minorinfoversion = JVMTI_CMLR_MINOR_VERSION_0;
+  record->numpcs = 0;
+  for(PcDesc* p = nm->scopes_pcs_begin(); p < nm->scopes_pcs_end(); p++) {
+   if(p->scope_decode_offset() == DebugInformationRecorder::serialized_null) continue;
+   record->numpcs++;
+  }
+  record->pcinfo = (PCStackInfo*)(NEW_RESOURCE_ARRAY(PCStackInfo, record->numpcs));
+  int scope = 0;
+  for(PcDesc* p = nm->scopes_pcs_begin(); p < nm->scopes_pcs_end(); p++) {
+    if(p->scope_decode_offset() == DebugInformationRecorder::serialized_null) continue;
+    void* pc_address = (void*)p->real_pc(nm);
+    assert(pc_address != NULL, "pc_address must be non-null");
+    record->pcinfo[scope].pc = pc_address;
+    numstackframes=0;
+    for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
+      numstackframes++;
+    }
+    assert(numstackframes != 0, "numstackframes must be nonzero.");
+    record->pcinfo[scope].methods = (jmethodID *)NEW_RESOURCE_ARRAY(jmethodID, numstackframes);
+    record->pcinfo[scope].bcis = (jint *)NEW_RESOURCE_ARRAY(jint, numstackframes);
+    record->pcinfo[scope].numstackframes = numstackframes;
+    int stackframe = 0;
+    for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
+      // sd->method() can be NULL for stubs but not for nmethods. To be completely robust, include an assert that we should never see a null sd->method()
+      assert(!sd->method().is_null(), "sd->method() cannot be null.");
+      record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id();
+      record->pcinfo[scope].bcis[stackframe] = sd->bci();
+      stackframe++;
+    }
+    scope++;
+  }
+  return record;
+}
 
 void JvmtiExport::post_compiled_method_load(nmethod *nm) {
   // If there are pending CompiledMethodUnload events then these are
@@ -1780,7 +1820,11 @@
                 (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string()));
 
       ResourceMark rm(thread);
-      JvmtiCompiledMethodLoadEventMark jem(thread, nm);
+
+      // Add inlining information
+      jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm);
+      // Pass inlining information through the void pointer
+      JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord);
       JvmtiJavaThreadEventTransition jet(thread);
       jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad;
       if (callback != NULL) {