changeset 1040:873ec3787992

6892186: SA does not dump debug info for scalar replaced objects Summary: Implement scalar replaced objects debug info dump in SA. Reviewed-by: twisti
author kvn
date Wed, 21 Oct 2009 09:15:33 -0700
parents 987e948ebbc8
children f875b4f472f7
files agent/make/saenv.sh agent/make/saenv64.sh agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js src/share/vm/opto/callnode.cpp src/share/vm/runtime/vmStructs.cpp
diffstat 11 files changed, 207 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/agent/make/saenv.sh	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/make/saenv.sh	Wed Oct 21 09:15:33 2009 -0700
@@ -48,8 +48,16 @@
      CPU=i386
    fi
 else
-   LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so
-   export LD_AUDIT_32
+   # configure audit helper library if SA_ALTROOT is set
+   if [ -n "$SA_ALTROOT" ]; then
+     LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so
+     export LD_AUDIT_32
+     if [ ! -f $LD_AUDIT_32 ]; then
+       echo "SA_ALTROOT is set and can't find libsaproc_audit.so."
+       echo "Make sure to build it with 'make natives'."
+       exit 1
+     fi
+   fi
    SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/solaris/`uname -p`
    OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"
    CPU=sparc
--- a/agent/make/saenv64.sh	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/make/saenv64.sh	Wed Oct 21 09:15:33 2009 -0700
@@ -43,8 +43,16 @@
   fi
 fi
 
-LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so
-export LD_AUDIT_64
+# configure audit helper library if SA_ALTROOT is set
+if [ -n "$SA_ALTROOT" ]; then
+  LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so
+  export LD_AUDIT_64
+  if [ ! -f $LD_AUDIT_64 ]; then
+      echo "SA_ALTROOT is set and can't find libsaproc_audit.so."
+      echo "Make sure to build it with 'make natives'."
+      exit 1
+  fi
+fi
 SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/$CPU:$STARTDIR/solaris/$CPU
 
 OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java	Wed Oct 21 09:15:33 2009 -0700
@@ -926,6 +926,28 @@
                 }
             }
         },
+        new Command("dumpcodecache", "dumpcodecache", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    final PrintStream fout = out;
+                    final HTMLGenerator gen = new HTMLGenerator(false);
+                    CodeCacheVisitor v = new CodeCacheVisitor() {
+                            public void prologue(Address start, Address end) {
+                            }
+                            public void visit(CodeBlob blob) {
+                                fout.println(gen.genHTML(blob.instructionsBegin()));
+                            }
+                            public void epilogue() {
+                            }
+
+
+                        };
+                    VM.getVM().getCodeCache().iterate(v);
+                }
+            }
+        },
         new Command("where", "where { -a | id }", false) {
             public void doit(Tokens t) {
                 if (t.countTokens() != 1) {
--- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java	Wed Oct 21 09:15:33 2009 -0700
@@ -173,7 +173,8 @@
     CodeBlob lastBlob = null;
     while (ptr != null && ptr.lessThan(end)) {
       try {
-        CodeBlob blob = findBlobUnsafe(ptr);
+        // Use findStart to get a pointer inside blob other findBlob asserts
+        CodeBlob blob = findBlobUnsafe(heap.findStart(ptr));
         if (blob != null) {
           visitor.visit(blob);
           if (blob == lastBlob) {
--- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Wed Oct 21 09:15:33 2009 -0700
@@ -42,7 +42,7 @@
   /** To support simple linked-list chaining of nmethods */
   private static AddressField  osrLinkField;
   private static AddressField  scavengeRootLinkField;
-  private static CIntegerField scavengeRootStateField;
+  private static JByteField    scavengeRootStateField;
 
   /** Offsets for different nmethod parts */
   private static CIntegerField exceptionOffsetField;
@@ -92,7 +92,7 @@
     entryBCIField               = type.getCIntegerField("_entry_bci");
     osrLinkField                = type.getAddressField("_osr_link");
     scavengeRootLinkField       = type.getAddressField("_scavenge_root_link");
-    scavengeRootStateField      = type.getCIntegerField("_scavenge_root_state");
+    scavengeRootStateField      = type.getJByteField("_scavenge_root_state");
 
     exceptionOffsetField        = type.getCIntegerField("_exception_offset");
     deoptOffsetField            = type.getCIntegerField("_deoptimize_offset");
@@ -274,7 +274,7 @@
     if (Assert.ASSERTS_ENABLED) {
       Assert.that(pd != null, "scope must be present");
     }
-    return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getReexecute());
+    return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
   }
 
   /** This is only for use by the debugging system, and is only
@@ -306,11 +306,11 @@
   public ScopeDesc getScopeDescNearDbg(Address pc) {
     PCDesc pd = getPCDescNearDbg(pc);
     if (pd == null) return null;
-    return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getReexecute());
+    return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
   }
 
-  public Map/*<Address, PcDesc>*/ getSafepoints() {
-    Map safepoints = new HashMap(); // Map<Address, PcDesc>
+  public Map/*<Address, PCDesc>*/ getSafepoints() {
+    Map safepoints = new HashMap(); // Map<Address, PCDesc>
     sun.jvm.hotspot.debugger.Address p = null;
     for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd());
          p = p.addOffsetTo(pcDescSize)) {
--- a/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java	Wed Oct 21 09:15:33 2009 -0700
@@ -36,6 +36,7 @@
 public class PCDesc extends VMObject {
   private static CIntegerField pcOffsetField;
   private static CIntegerField scopeDecodeOffsetField;
+  private static CIntegerField objDecodeOffsetField;
   private static CIntegerField pcFlagsField;
 
   static {
@@ -51,6 +52,7 @@
 
     pcOffsetField          = type.getCIntegerField("_pc_offset");
     scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset");
+    objDecodeOffsetField   = type.getCIntegerField("_obj_decode_offset");
     pcFlagsField           = type.getCIntegerField("_flags");
   }
 
@@ -68,6 +70,10 @@
     return ((int) scopeDecodeOffsetField.getValue(addr));
   }
 
+  public int getObjDecodeOffset() {
+    return ((int) objDecodeOffsetField.getValue(addr));
+  }
+
   public Address getRealPC(NMethod code) {
     return code.instructionsBegin().addOffsetTo(getPCOffset());
   }
--- a/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java	Wed Oct 21 09:15:33 2009 -0700
@@ -51,11 +51,10 @@
   /** Scalar replaced bjects pool */
   private List    objects; // ArrayList<ScopeValue>
 
-
-  public ScopeDesc(NMethod code, int decodeOffset, boolean reexecute) {
+  private ScopeDesc(NMethod code, int decodeOffset, List objects, boolean reexecute) {
     this.code = code;
     this.decodeOffset = decodeOffset;
-    this.objects      = decodeObjectValues(DebugInformationRecorder.SERIALIZED_NULL);
+    this.objects      = objects;
     this.reexecute    = reexecute;
 
     // Decode header
@@ -108,7 +107,7 @@
     return decodeMonitorValues(monitorsDecodeOffset);
   }
 
-  /** Returns a List&lt;MonitorValue&gt; */
+  /** Returns a List&lt;ObjectValue&gt; */
   public List getObjects() {
     return objects;
   }
@@ -119,7 +118,7 @@
       return null;
     }
 
-    return new ScopeDesc(code, senderDecodeOffset, false);
+    return new ScopeDesc(code, senderDecodeOffset, objects, false);
   }
 
   /** Returns where the scope was decoded */
--- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Wed Oct 21 09:15:33 2009 -0700
@@ -807,6 +807,9 @@
             Interpreter interp = VM.getVM().getInterpreter();
             if (interp.contains(pc)) {
                InterpreterCodelet codelet = interp.getCodeletContaining(pc);
+               if (codelet == null) {
+                  return "Unknown location in the Interpreter: " + pc;
+               }
                return genHTML(codelet);
             }
             return genHTML(blob);
@@ -969,16 +972,24 @@
    }
 
    protected String genSafepointInfo(NMethod nm, PCDesc pcDesc) {
-      ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
-      Formatter buf = new Formatter(genHTML);
-      Formatter tabs = new Formatter(genHTML);
+       ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
+       Formatter buf = new Formatter(genHTML);
+       Formatter tabs = new Formatter(genHTML);
+       tabs.append(tab + tab + tab); // Initial indent for debug info
 
-      buf.beginTag("pre");
-      genScope(buf, tabs, sd);
-      buf.endTag("pre");
-      buf.append(genOopMapInfo(nm, pcDesc));
+       buf.beginTag("pre");
+       genScope(buf, tabs, sd);
 
-      return buf.toString();
+       // Reset indent for scalar replaced objects
+       tabs = new Formatter(genHTML);
+       tabs.append(tab + tab + tab); // Initial indent for debug info
+
+       genScObjInfo(buf, tabs, sd);
+       buf.endTag("pre");
+
+       buf.append(genOopMapInfo(nm, pcDesc));
+
+       return buf.toString();
    }
 
     protected void genScope(Formatter buf, Formatter tabs, ScopeDesc sd) {
@@ -1022,8 +1033,95 @@
             buf.append(genHTMLForMonitors(sd, monitors));
         }
 
+        buf.br();
         tabs.append(tab);
-        buf.br();
+    }
+
+    protected void genScObjInfo(Formatter buf, Formatter tabs, ScopeDesc sd) {
+        if (sd == null) {
+            return;
+        }
+
+        List objects = sd.getObjects();
+        if (objects == null) {
+            return;
+        }
+        int length = objects.size();
+        for (int i = 0; i < length; i++) {
+            buf.append(tabs);
+            ObjectValue ov = (ObjectValue)objects.get(i);
+            buf.append("ScObj" + i);
+            ScopeValue sv = ov.getKlass();
+            if (Assert.ASSERTS_ENABLED) {
+                Assert.that(sv.isConstantOop(), "scalar replaced object klass must be constant oop");
+            }
+            ConstantOopReadValue klv = (ConstantOopReadValue)sv;
+            OopHandle klHandle = klv.getValue();
+            if (Assert.ASSERTS_ENABLED) {
+                Assert.that(klHandle != null, "scalar replaced object klass must be not NULL");
+            }
+            Oop obj = VM.getVM().getObjectHeap().newOop(klHandle);
+            if (obj instanceof InstanceKlass) {
+                InstanceKlass kls = (InstanceKlass) obj;
+                buf.append(" " + kls.getName().asString() + "={");
+                int flen = ov.fieldsSize();
+
+                TypeArray klfields = kls.getFields();
+                int klen = (int) klfields.getLength();
+
+                ConstantPool cp = kls.getConstants();
+                int findex = 0;
+                for (int index = 0; index < klen; index += kls.NEXT_OFFSET) {
+                    int accsFlags = klfields.getShortAt(index + kls.ACCESS_FLAGS_OFFSET);
+                    int nameIndex = klfields.getShortAt(index + kls.NAME_INDEX_OFFSET);
+                    AccessFlags access = new AccessFlags(accsFlags);
+                    if (!access.isStatic()) {
+                        ScopeValue svf = ov.getFieldAt(findex++);
+                        String    fstr = scopeValueAsString(sd, svf);
+                        Symbol f_name  = cp.getSymbolAt(nameIndex);
+                        buf.append(" [" + f_name.asString() + " :"+ index + "]=(#" + fstr + ")");
+                    }
+                }
+                buf.append(" }");
+            } else {
+                buf.append(" ");
+                int flen = ov.fieldsSize();
+                if (obj instanceof TypeArrayKlass) {
+                    TypeArrayKlass kls = (TypeArrayKlass) obj;
+                    buf.append(kls.getElementTypeName() + "[" + flen + "]");
+                } else if (obj instanceof ObjArrayKlass) {
+                    ObjArrayKlass kls = (ObjArrayKlass) obj;
+                    Klass elobj = kls.getBottomKlass();
+                    if (elobj instanceof InstanceKlass) {
+                        buf.append(elobj.getName().asString());
+                    } else if (elobj instanceof TypeArrayKlass) {
+                        TypeArrayKlass elkls = (TypeArrayKlass) elobj;
+                        buf.append(elkls.getElementTypeName());
+                    } else {
+                        if (Assert.ASSERTS_ENABLED) {
+                            Assert.that(false, "unknown scalar replaced object klass!");
+                        }
+                    }
+                    buf.append("[" + flen + "]");
+                    int ndim = (int) kls.getDimension();
+                    while (--ndim > 0) {
+                        buf.append("[]");
+                    }
+                } else {
+                    if (Assert.ASSERTS_ENABLED) {
+                        Assert.that(false, "unknown scalar replaced object klass!");
+                    }
+                }
+                buf.append("={");
+                for (int findex = 0; findex < flen; findex++) {
+                    ScopeValue svf = ov.getFieldAt(findex);
+                    String fstr = scopeValueAsString(sd, svf);
+                    buf.append(" [" + findex + "]=(#" + fstr + ")");
+                }
+                buf.append(" }");
+            }
+            buf.br();
+        }
     }
 
    protected String genHTMLForOopMap(OopMap map) {
@@ -1037,8 +1135,6 @@
             tmpBuf.beginTag("tr");
             tmpBuf.beginTag("td");
             tmpBuf.append(type);
-            tmpBuf.endTag("td");
-            tmpBuf.endTag("tr");
             for (; ! oms.isDone(); oms.next()) {
                OopMapValue omv = oms.getCurrent();
                if (omv == null) {
@@ -1048,7 +1144,7 @@
                VMReg vmReg = omv.getReg();
                int reg = vmReg.getValue();
                if (reg < stack0) {
-                  tmpBuf.append(VMRegImpl.getRegisterName(vmReg.getValue()));
+                  tmpBuf.append(VMRegImpl.getRegisterName(reg));
                } else {
                   tmpBuf.append('[');
                   tmpBuf.append(Integer.toString((reg - stack0) * 4));
@@ -1058,7 +1154,13 @@
                   tmpBuf.append(" = ");
                   VMReg vmContentReg = omv.getContentReg();
                   int contentReg = vmContentReg.getValue();
-                  tmpBuf.append(VMRegImpl.getRegisterName(vmContentReg.getValue()));
+                  if (contentReg < stack0) {
+                     tmpBuf.append(VMRegImpl.getRegisterName(contentReg));
+                  } else {
+                     tmpBuf.append('[');
+                     tmpBuf.append(Integer.toString((contentReg - stack0) * 4));
+                     tmpBuf.append(']');
+                  }
                }
                tmpBuf.append(spaces);
             }
@@ -1072,19 +1174,19 @@
 
       OopMapValueIterator omvIterator = new OopMapValueIterator();
       OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE);
-      buf.append(omvIterator.iterate(oms, "Oop:", false));
+      buf.append(omvIterator.iterate(oms, "Oops:", false));
+
+      oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
+      buf.append(omvIterator.iterate(oms, "narrowOops:", false));
 
       oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
-      buf.append(omvIterator.iterate(oms, "Value:", false));
-
-      oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
-      buf.append(omvIterator.iterate(oms, "Oop:", false));
+      buf.append(omvIterator.iterate(oms, "Values:", false));
 
       oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
       buf.append(omvIterator.iterate(oms, "Callee saved:",  true));
 
       oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE);
-      buf.append(omvIterator.iterate(oms, "Derived oop:", true));
+      buf.append(omvIterator.iterate(oms, "Derived oops:", true));
 
       buf.endTag("table");
       return buf.toString();
@@ -1093,6 +1195,8 @@
 
    protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) {
       OopMapSet mapSet = nmethod.getOopMaps();
+      if (mapSet == null || (mapSet.getSize() <= 0))
+        return "";
       int pcOffset = pcDesc.getPCOffset();
       OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging());
       if (map == null) {
@@ -1106,6 +1210,7 @@
      Formatter buf = new Formatter(genHTML);
      buf.beginTag("pre");
      buf.append("OopMap: ");
+     buf.br();
      buf.append(genHTMLForOopMap(map));
      buf.endTag("pre");
 
@@ -1154,7 +1259,7 @@
       return buf.toString();
    }
 
-   private String scopeValueAsString(ScopeValue sv) {
+   private String scopeValueAsString(ScopeDesc sd, ScopeValue sv) {
       Formatter buf = new Formatter(genHTML);
       if (sv.isConstantInt()) {
          buf.append("int ");
@@ -1187,6 +1292,11 @@
          } else {
             buf.append("null");
          }
+      } else if (sv.isObject()) {
+         ObjectValue ov = (ObjectValue)sv;
+         buf.append("#ScObj" + sd.getObjects().indexOf(ov));
+      } else {
+         buf.append("unknown scope value " + sv);
       }
       return buf.toString();
    }
@@ -1219,7 +1329,7 @@
          }
 
          buf.append(", ");
-         buf.append(scopeValueAsString(sv));
+         buf.append(scopeValueAsString(sd, sv));
          buf.append(") ");
       }
 
@@ -1246,7 +1356,7 @@
          buf.append("(owner = ");
          ScopeValue owner = mv.owner();
          if (owner != null) {
-            buf.append(scopeValueAsString(owner));
+            buf.append(scopeValueAsString(sd, owner));
          } else {
             buf.append("null");
          }
@@ -1324,11 +1434,11 @@
                   buf.append(instr.asString(currentPc, symFinder));
                }
 
+               buf.br();
                if (isSafepoint && !prevWasCall) {
-                  buf.append(genSafepointInfo(nmethod, pcDesc));
+                 buf.append(genSafepointInfo(nmethod, pcDesc));
                }
 
-               buf.br();
                prevWasCall = instr.isCall();
             }
 
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js	Sat Oct 17 19:51:05 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js	Wed Oct 21 09:15:33 2009 -0700
@@ -1047,7 +1047,7 @@
    } else {
       // some type names have ':'. replace to make it as a 
       // JavaScript identifier
-      tmp.name = tmp.name.replace(':', '_');
+      tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_');
       eval("function read" + tmp.name + "(addr) {" +
            "   return readVMType('" + tmp.name + "', addr);}"); 
       eval("function print" + tmp.name + "(addr) {" + 
--- a/src/share/vm/opto/callnode.cpp	Sat Oct 17 19:51:05 2009 -0700
+++ b/src/share/vm/opto/callnode.cpp	Wed Oct 21 09:15:33 2009 -0700
@@ -421,21 +421,23 @@
         iklass = cik->as_instance_klass();
       } else if (cik->is_type_array_klass()) {
         cik->as_array_klass()->base_element_type()->print_name_on(st);
-        st->print("[%d]=", spobj->n_fields());
+        st->print("[%d]", spobj->n_fields());
       } else if (cik->is_obj_array_klass()) {
-        ciType* cie = cik->as_array_klass()->base_element_type();
-        int ndim = 1;
-        while (cie->is_obj_array_klass()) {
-          ndim += 1;
-          cie = cie->as_array_klass()->base_element_type();
+        ciKlass* cie = cik->as_obj_array_klass()->base_element_klass();
+        if (cie->is_instance_klass()) {
+          cie->print_name_on(st);
+        } else if (cie->is_type_array_klass()) {
+          cie->as_array_klass()->base_element_type()->print_name_on(st);
+        } else {
+          ShouldNotReachHere();
         }
-        cie->print_name_on(st);
+        st->print("[%d]", spobj->n_fields());
+        int ndim = cik->as_array_klass()->dimension() - 1;
         while (ndim-- > 0) {
           st->print("[]");
         }
-        st->print("[%d]=", spobj->n_fields());
       }
-      st->print("{");
+      st->print("={");
       uint nf = spobj->n_fields();
       if (nf > 0) {
         uint first_ind = spobj->first_index();
--- a/src/share/vm/runtime/vmStructs.cpp	Sat Oct 17 19:51:05 2009 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Wed Oct 21 09:15:33 2009 -0700
@@ -594,6 +594,7 @@
                                                                                                                                      \
   nonstatic_field(PcDesc,                      _pc_offset,                                    int)                                   \
   nonstatic_field(PcDesc,                      _scope_decode_offset,                          int)                                   \
+  nonstatic_field(PcDesc,                      _obj_decode_offset,                            int)                                   \
   nonstatic_field(PcDesc,                      _flags,                        PcDesc::PcDescFlags)                                   \
                                                                                                                                      \
   /***************************************************/                                                                              \