<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Hi Nicolas,<div><br></div><div>It looks great. But this is scary:</div><div><br></div><div><span class="Apple-style-span" style="font-family: -webkit-monospace; font-size: 11px; ">+  // Allocate a new LibgccObject to represent this frame. Deallocation of this<br>+  // object may be impossible: libgcc does not seem to deallocate it, even with<br>+  // __deregister_frame. Deallocating it manually may also cause libgcc to<br>+  // crash.<br>+  struct LibgccObject* ob = (struct LibgccObject*)<br>+    malloc(sizeof(struct LibgccObject));</span></div><div><font class="Apple-style-span" face="-webkit-monospace" size="3"><span class="Apple-style-span" style="font-size: 11px;"><br></span></font></div><div><font class="Apple-style-span" face="-webkit-monospace" size="3"><span class="Apple-style-span" style="font-size: 11px;">Are you sure you can't deallocate it when the JIT is teared down?</span></font></div><div><font class="Apple-style-span" face="-webkit-monospace" size="3"><span class="Apple-style-span" style="font-size: 11px;"><br></span></font></div><div><font class="Apple-style-span" face="-webkit-monospace" size="3"><span class="Apple-style-span" style="font-size: 11px;">Evan</span></font></div><div><br></div><div><br><div><div>On Aug 21, 2008, at 1:20 AM, Nicolas Geoffray wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div>Hi Evan,<br><br>New patch with new un-gcc documentation :)<br><br>Thanks for reviewing!<br><br>Nicolas<br><br>Evan Cheng wrote:<br><blockquote type="cite">Hi Nicolas,<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Comments in line.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">On Aug 19, 2008, at 8:04 AM, Nicolas Geoffray wrote:<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">Dear all,<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Here's a patch that enables exception handling on Darwin with the  JIT. It's really ugly, it's a workaround to work with libgcc which  is doing crazy stuff when unwinding the stack. The __register_frame  function was sufficient enough for Linux, but unfortunately, the  code for darwin erases by default the registered frames. In a  perfect world, I think libgcc should be modified....<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">I'd be totally OK if you don't want this patch in, as it's an ugly  workaround. I can move the patch to vmkit, and that would be fine by  me. However, this makes lli work out of the box with exceptions and  darwin, so it's still an improvement.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Nicolas<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">Index: lib/ExecutionEngine/JIT/JIT.cpp<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">===================================================================<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">--- lib/ExecutionEngine/JIT/JIT.cpp<span class="Apple-tab-span" style="white-space:pre">   </span>(revision 54920)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+++ lib/ExecutionEngine/JIT/JIT.cpp<span class="Apple-tab-span" style="white-space:pre"> </span>(working copy)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">@@ -64,10 +64,73 @@<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">  }<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">}<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">#if defined (__GNUC__)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">extern "C" void __register_frame(void*);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">-#endif<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#if defined (__APPLE__)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+struct object {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  void *pc_begin;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  void *tbase;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  void *dbase;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  void* real_begin;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    union {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    struct {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+      unsigned long sorted : 1;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+      unsigned long from_array : 1;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+      unsigned long mixed_encoding : 1;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+      unsigned long encoding : 8;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+      unsigned long count : 21;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    } b;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    size_t i;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  } s;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Please pick more descriptive names than object, etc. Also, please try  to match the naming convention used in the file. Some documentation is  definitely welcome. :-)<br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  // Be pessimistic, include this field even if GCC<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  // may not have it.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  char *fde_end;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct object *next;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+};<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+extern "C" void _keymgr_set_and_unlock_processwide_ptr (int, void *);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+extern "C" void *_keymgr_get_and_lock_processwide_ptr (int);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#define KEYMGR_GCC3_DW2_OBJ_LIST        302     /* Dwarf2 object  list  */<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+struct km_object_info {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct object* seen_objects;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct object* unseen_objects;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  unsigned spare[2];<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+};<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+extern "C" void darwin_register_frame(void* begin) {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct km_object_info* the_obj_info = (struct km_object_info*)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct object* ob = (struct object*)malloc(sizeof(struct object));<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Who frees this?<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->pc_begin = (void *)-1;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->tbase = 0;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->dbase = 0;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->real_begin = begin;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->s.i = 0;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  //ob->s.b.encoding = DW_EH_PE_omit;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Why is this commented out?<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->s.b.encoding = 0xff;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  // Put the info on both places, as libgcc uses the first or the<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  // the second field.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->fde_end = (char*)the_obj_info->unseen_objects;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  ob->next = (struct object*)the_obj_info->unseen_objects;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Are the casting necessary? Why not just define the types correctly.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  the_obj_info->unseen_objects = ob;<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST,<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+                                          the_obj_info);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+}<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Function level documentation please.<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Thanks!<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">Evan<br></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">  <br></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#endif // __APPLE__<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#endif // __GNUC__<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">/// createJIT - This is the factory method for creating a JIT for  the current<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">/// machine, it does not fall back to the interpreter.  This takes  ownership<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">/// of the module provider.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">@@ -108,8 +171,20 @@<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">  // Register routine for informing unwinding runtime about new EH  frames<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">#if defined(__GNUC__)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#if defined(__APPLE__)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  struct km_object_info* the_obj_info = (struct km_object_info*)<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    _keymgr_get_and_lock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  if (!the_obj_info) {<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    the_obj_info = (km_object_info*)malloc(sizeof(struct  km_object_info));<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+    _keymgr_set_and_unlock_processwide_ptr (KEYMGR_GCC3_DW2_OBJ_LIST,<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+                                            the_obj_info);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  }<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+  InstallExceptionTableRegister(darwin_register_frame);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#else<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">  InstallExceptionTableRegister(__register_frame);<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">-#endif<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#endif // __APPLE__<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">+#endif // __GNUC__<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">  // Initialize passes.<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">  PM.doInitialization();<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">_______________________________________________<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">llvm-commits mailing list<br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite"><a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br></blockquote></blockquote><blockquote type="cite"><blockquote type="cite">    <br></blockquote></blockquote><blockquote type="cite"><br></blockquote><blockquote type="cite">_______________________________________________<br></blockquote><blockquote type="cite">llvm-commits mailing list<br></blockquote><blockquote type="cite"><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br></blockquote><blockquote type="cite"><a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br></blockquote><blockquote type="cite">  <br></blockquote><br>Index: lib/ExecutionEngine/JIT/JIT.cpp<br>===================================================================<br>--- lib/ExecutionEngine/JIT/JIT.cpp<span class="Apple-tab-span" style="white-space:pre">        </span>(revision 54988)<br>+++ lib/ExecutionEngine/JIT/JIT.cpp<span class="Apple-tab-span" style="white-space:pre">       </span>(working copy)<br>@@ -64,10 +64,128 @@<br>   }<br> }<br><br>+<br> #if defined (__GNUC__)<br>+ <br>+// libgcc defines the __register_frame function to dynamically register new<br>+// dwarf frames for exception handling. This functionality is not portable<br>+// across compilers and is only provided by GCC. We use the __register_frame<br>+// function here so that code generated by the JIT cooperates with the unwinding<br>+// runtime of libgcc. When JITting with exception handling enable, LLVM<br>+// generates dwarf frames and registers it to libgcc with __register_frame.<br>+//<br>+// The __register_frame function works with Linux.<br>+//<br>+// Unfortunately, this functionality seems to be in libgcc after the unwinding<br>+// library of libgcc for darwin was written. The code for darwin overwrites the<br>+// value updated by __register_frame with a value fetched with "keymgr".<br>+// "keymgr" is an obsolete functionality, which should be rewritten some day.<br>+// In the meantime, since "keymgr" is on all libgccs shipped with apple-gcc, we<br>+// need a workaround in LLVM which uses the "keymgr" to dynamically modify the<br>+// values of an opaque key, used by libgcc to find dwarf tables.<br>+<br> extern "C" void __register_frame(void*);<br>-#endif<br><br>+#if defined (__APPLE__)<br>+<br>+namespace {<br>+<br>+// LibgccObject - This is the structure defined in libgcc. There is no #include<br>+// provided for this structure, so we also define it here. libgcc calls it<br>+// "struct object". The structure is undocumented in libgcc.<br>+struct LibgccObject {<br>+  void *unused1;<br>+  void *unused2;<br>+  void *unused3;<br>+  <br>+  /// frame - Pointer to the exception table.<br>+  void *frame;<br>+  <br>+  /// encoding -  The encoding of the object?<br>+  union {<br>+    struct {<br>+      unsigned long sorted : 1;<br>+      unsigned long from_array : 1;<br>+      unsigned long mixed_encoding : 1;<br>+      unsigned long encoding : 8;<br>+      unsigned long count : 21; <br>+    } b;<br>+    size_t i;<br>+  } encoding;<br>+  <br>+  /// fde_end - libgcc defines this field only if some macro is defined. We<br>+  /// include this field even if it may not there, to make libgcc happy.<br>+  char *fde_end;<br>+  <br>+  /// next - At least we know it's a chained list!<br>+  struct LibgccObject *next;<br>+};<br>+<br>+// "kemgr" stuff. Apparently, all frame tables are stored there.<br>+extern "C" void _keymgr_set_and_unlock_processwide_ptr(int, void *);<br>+extern "C" void *_keymgr_get_and_lock_processwide_ptr(int);<br>+#define KEYMGR_GCC3_DW2_OBJ_LIST        302     /* Dwarf2 object list  */<br>+<br>+/// LibgccObjectInfo - libgcc defines this struct as km_object_info. It<br>+/// probably contains all dwarf tables that are loaded.<br>+struct LibgccObjectInfo {<br>+<br>+  /// seenObjects - LibgccObjects already parsed by the unwinding runtime.<br>+  ///<br>+  struct LibgccObject* seenObjects;<br>+<br>+  /// unseenObjects - LibgccObjects not parsed yet by the unwinding runtime.<br>+  ///<br>+  struct LibgccObject* unseenObjects;<br>+  <br>+  unsigned unused[2];<br>+};<br>+<br>+// for DW_EH_PE_omit<br>+#include "llvm/Support/Dwarf.h"<br>+<br>+/// darwin_register_frame - Since __register_frame does not work with darwin's<br>+/// libgcc,we provide our own function, which "tricks" libgcc by modifying the<br>+/// "Dwarf2 object list" key.<br>+void DarwinRegisterFrame(void* FrameBegin) {<br>+  // Get the key.<br>+  struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*)<br>+    _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);<br>+  <br>+  // Allocate a new LibgccObject to represent this frame. Deallocation of this<br>+  // object may be impossible: libgcc does not seem to deallocate it, even with<br>+  // __deregister_frame. Deallocating it manually may also cause libgcc to<br>+  // crash.<br>+  struct LibgccObject* ob = (struct LibgccObject*)<br>+    malloc(sizeof(struct LibgccObject));<br>+  <br>+  // Do like libgcc for the values of the field.<br>+  ob->unused1 = (void *)-1;<br>+  ob->unused2 = 0;<br>+  ob->unused3 = 0;<br>+  ob->frame = FrameBegin;<br>+  ob->encoding.i = 0; <br>+  ob->encoding.b.encoding = llvm::dwarf::DW_EH_PE_omit;<br>+  <br>+  // Put the info on both places, as libgcc uses the first or the the second<br>+  // field. Note that we rely on having two pointers here. If fde_end was a<br>+  // char, things would get complicated.<br>+  ob->fde_end = (char*)LOI->unseenObjects;<br>+  ob->next = LOI->unseenObjects;<br>+  <br>+  // Update the key's unseenObjects list.<br>+  LOI->unseenObjects = ob;<br>+  <br>+  // Finally update the "key". Apparently, libgcc requires it. <br>+  _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,<br>+                                         LOI);<br>+<br>+}<br>+<br>+}<br>+#endif // __APPLE__<br>+#endif // __GNUC__<br>+<br> /// createJIT - This is the factory method for creating a JIT for the current<br> /// machine, it does not fall back to the interpreter.  This takes ownership<br> /// of the module provider.<br>@@ -108,8 +226,23 @@<br><br>   // Register routine for informing unwinding runtime about new EH frames<br> #if defined(__GNUC__)<br>+#if defined(__APPLE__)<br>+  struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*)<br>+    _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);<br>+  <br>+  // The key is created on demand, and libgcc creates it the first time an<br>+  // exception occurs. Since we need the key to register frames, we create<br>+  // it now.<br>+  if (!LOI) {<br>+    LOI = (LibgccObjectInfo*)malloc(sizeof(struct LibgccObjectInfo)); <br>+    _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,<br>+                                           LOI);<br>+  }<br>+  InstallExceptionTableRegister(DarwinRegisterFrame);<br>+#else<br>   InstallExceptionTableRegister(__register_frame);<br>-#endif<br>+#endif // __APPLE__<br>+#endif // __GNUC__<br><br>   // Initialize passes.<br>   PM.doInitialization();<br>_______________________________________________<br>llvm-commits mailing list<br><a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br><a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br></div></blockquote></div><br></div></body></html>