<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[160340] branches/jsCStack/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/160340">160340</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2013-12-09 15:50:26 -0800 (Mon, 09 Dec 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>CStack Branch: Fix baseline JIT for basic operation
https://bugs.webkit.org/show_bug.cgi?id=125470

Not yet reviewed.

Fixed compileOpCall and it's slow case to properly adjust the stack pointer before
and after a call.

Cleaned up the calling convention in the various thunks.  Adjusted the stack
pointer at the end of the arity fixup thunk to account for the frame moving.

Added ctiNativeCallFallback() thunk generator for when another thunk that can't
perform its operation inline needs to make a native call.  This thunk generator
differes from ctiNativeCall() in that it doesn't emit a funciton prologue, thus
allowing the original thunk to jump to the &quot;fallback&quot; thunk.  I'm open to another
name beside &quot;fallback&quot;.  Maybe &quot;ctiNativeTailCall()&quot;.

Fixed the OSR entry handling in the LLInt prologue macro to properly account
for the callee saving the caller frame pointer.

Added stack alignement check function for use in debug builds to find and break
if the stack pointer is not appropriately aligned.

* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::checkStackPointerAlignment):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
* jit/JIT.h:
(JSC::JIT::frameRegisterCountFor):
* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_ret):
(JSC::JIT::emit_op_enter):
* jit/JITThunks.cpp:
(JSC::JITThunks::ctiNativeCallFallback):
* jit/JITThunks.h:
* jit/ThunkGenerators.cpp:
(JSC::slowPathFor):
(JSC::nativeForGenerator):
(JSC::nativeCallFallbackGenerator):
(JSC::arityFixup):
(JSC::charCodeAtThunkGenerator):
(JSC::charAtThunkGenerator):
(JSC::fromCharCodeThunkGenerator):
(JSC::sqrtThunkGenerator):
(JSC::floorThunkGenerator):
(JSC::ceilThunkGenerator):
(JSC::roundThunkGenerator):
(JSC::expThunkGenerator):
(JSC::logThunkGenerator):
(JSC::absThunkGenerator):
(JSC::powThunkGenerator):
(JSC::imulThunkGenerator):
(JSC::arrayIteratorNextThunkGenerator):
* jit/ThunkGenerators.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter64.asm:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesjsCStackSourceJavaScriptCoreChangeLog">branches/jsCStack/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitAssemblyHelpersh">branches/jsCStack/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITcpp">branches/jsCStack/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITh">branches/jsCStack/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITCallcpp">branches/jsCStack/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITOpcodescpp">branches/jsCStack/Source/JavaScriptCore/jit/JITOpcodes.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITThunkscpp">branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITThunksh">branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitThunkGeneratorscpp">branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitThunkGeneratorsh">branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorellintLowLevelInterpreterasm">branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorellintLowLevelInterpreter64asm">branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesjsCStackSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ChangeLog (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ChangeLog        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/ChangeLog        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -1,3 +1,65 @@
</span><ins>+2013-12-09  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        CStack Branch: Fix baseline JIT for basic operation
+        https://bugs.webkit.org/show_bug.cgi?id=125470
+
+        Not yet reviewed.
+
+        Fixed compileOpCall and it's slow case to properly adjust the stack pointer before
+        and after a call.
+
+        Cleaned up the calling convention in the various thunks.  Adjusted the stack
+        pointer at the end of the arity fixup thunk to account for the frame moving.
+
+        Added ctiNativeCallFallback() thunk generator for when another thunk that can't
+        perform its operation inline needs to make a native call.  This thunk generator
+        differes from ctiNativeCall() in that it doesn't emit a funciton prologue, thus 
+        allowing the original thunk to jump to the &quot;fallback&quot; thunk.  I'm open to another
+        name beside &quot;fallback&quot;.  Maybe &quot;ctiNativeTailCall()&quot;.
+
+        Fixed the OSR entry handling in the LLInt prologue macro to properly account
+        for the callee saving the caller frame pointer.
+
+        Added stack alignement check function for use in debug builds to find and break
+        if the stack pointer is not appropriately aligned.
+
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::checkStackPointerAlignment):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompile):
+        * jit/JIT.h:
+        (JSC::JIT::frameRegisterCountFor):
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileOpCall):
+        (JSC::JIT::compileOpCallSlowCase):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_ret):
+        (JSC::JIT::emit_op_enter):
+        * jit/JITThunks.cpp:
+        (JSC::JITThunks::ctiNativeCallFallback):
+        * jit/JITThunks.h:
+        * jit/ThunkGenerators.cpp:
+        (JSC::slowPathFor):
+        (JSC::nativeForGenerator):
+        (JSC::nativeCallFallbackGenerator):
+        (JSC::arityFixup):
+        (JSC::charCodeAtThunkGenerator):
+        (JSC::charAtThunkGenerator):
+        (JSC::fromCharCodeThunkGenerator):
+        (JSC::sqrtThunkGenerator):
+        (JSC::floorThunkGenerator):
+        (JSC::ceilThunkGenerator):
+        (JSC::roundThunkGenerator):
+        (JSC::expThunkGenerator):
+        (JSC::logThunkGenerator):
+        (JSC::absThunkGenerator):
+        (JSC::powThunkGenerator):
+        (JSC::imulThunkGenerator):
+        (JSC::arrayIteratorNextThunkGenerator):
+        * jit/ThunkGenerators.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter64.asm:
+
</ins><span class="cx"> 2013-12-06  Michael Saboff  &lt;msaboff@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         CStack Branch: Fix Specialized Thunks to use function prologues and epilogues
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/AssemblyHelpers.h (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/AssemblyHelpers.h        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/AssemblyHelpers.h        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -60,6 +60,15 @@
</span><span class="cx">     AssemblerType_T&amp; assembler() { return m_assembler; }
</span><span class="cx">     
</span><span class="cx"> #if CPU(X86_64) || CPU(X86)
</span><ins>+    void checkStackPointerAlignment()
+    {
+#ifndef NDEBUG
+        Jump stackPointerAligned = branchTestPtr(Zero, stackPointerRegister, TrustedImm32(0xf));
+        breakpoint();
+        stackPointerAligned.link(this);
+#endif
+    }
+
</ins><span class="cx">     void emitFunctionPrologue()
</span><span class="cx">     {
</span><span class="cx">         push(framePointerRegister);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JIT.cpp (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JIT.cpp        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JIT.cpp        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -543,7 +543,11 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Label functionBody = label();
</span><del>-    
</del><ins>+
+    checkStackPointerAlignment();
+    addPtr(TrustedImm32(-frameRegisterCountFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
+    checkStackPointerAlignment();
+
</ins><span class="cx">     privateCompileMainPass();
</span><span class="cx">     privateCompileLinkPass();
</span><span class="cx">     privateCompileSlowCases();
</span><span class="lines">@@ -555,6 +559,7 @@
</span><span class="cx">     if (m_codeBlock-&gt;codeType() == FunctionCode) {
</span><span class="cx">         stackCheck.link(this);
</span><span class="cx">         m_bytecodeOffset = 0;
</span><ins>+        // &amp;&amp;&amp;&amp; This may need to have some stack space allocated to make the call
</ins><span class="cx">         callOperationWithCallFrameRollbackOnException(operationStackCheck, m_codeBlock);
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">         m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs.
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JIT.h (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JIT.h        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JIT.h        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -246,6 +246,7 @@
</span><span class="cx">         
</span><span class="cx">         static unsigned frameRegisterCountFor(CodeBlock* codeBlock)
</span><span class="cx">         {
</span><ins>+            ASSERT(!(codeBlock-&gt;m_numCalleeRegisters &amp; 1));
</ins><span class="cx">             return codeBlock-&gt;m_numCalleeRegisters;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITCall.cpp (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITCall.cpp        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITCall.cpp        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -179,9 +179,7 @@
</span><span class="cx">     store32(TrustedImm32(locationBits), Address(callFrameRegister, JSStack::ArgumentCount * static_cast&lt;int&gt;(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
</span><span class="cx">     emitGetVirtualRegister(callee, regT0); // regT0 holds callee.
</span><span class="cx"> 
</span><del>-    store64(callFrameRegister, Address(regT1, CallFrame::callerFrameOffset()));
</del><span class="cx">     store64(regT0, Address(regT1, JSStack::Callee * static_cast&lt;int&gt;(sizeof(Register))));
</span><del>-    move(regT1, callFrameRegister);
</del><span class="cx"> 
</span><span class="cx">     if (opcodeID == op_call_eval) {
</span><span class="cx">         compileCallEval(instruction);
</span><span class="lines">@@ -198,10 +196,15 @@
</span><span class="cx">     m_callStructureStubCompilationInfo[callLinkInfoIndex].callType = CallLinkInfo::callTypeFor(opcodeID);
</span><span class="cx">     m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeOffset;
</span><span class="cx"> 
</span><del>-    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT1);
-    emitPutToCallFrameHeader(regT1, JSStack::ScopeChain);
</del><ins>+    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT2);
+    store64(regT2, Address(regT1, JSStack::ScopeChain * sizeof(Register)));
+    addPtr(TrustedImm32(16), regT1, stackPointerRegister);
+
</ins><span class="cx">     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
</span><span class="cx"> 
</span><ins>+    addPtr(TrustedImm32(-frameRegisterCountFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
+    checkStackPointerAlignment();
+
</ins><span class="cx">     sampleCodeBlock(m_codeBlock);
</span><span class="cx">     
</span><span class="cx">     emitPutCallResult(instruction);
</span><span class="lines">@@ -216,8 +219,13 @@
</span><span class="cx"> 
</span><span class="cx">     linkSlowCase(iter);
</span><span class="cx"> 
</span><ins>+    addPtr(TrustedImm32(16), regT1, stackPointerRegister);
+
</ins><span class="cx">     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_vm-&gt;getCTIStub(linkConstructThunkGenerator).code() : m_vm-&gt;getCTIStub(linkCallThunkGenerator).code());
</span><span class="cx"> 
</span><ins>+    addPtr(TrustedImm32(-frameRegisterCountFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
+    checkStackPointerAlignment();
+
</ins><span class="cx">     sampleCodeBlock(m_codeBlock);
</span><span class="cx">     
</span><span class="cx">     emitPutCallResult(instruction);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITOpcodescpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITOpcodes.cpp (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITOpcodes.cpp        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITOpcodes.cpp        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -262,6 +262,7 @@
</span><span class="cx">     // Return the result in %eax.
</span><span class="cx">     emitGetVirtualRegister(currentInstruction[1].u.operand, returnValueGPR);
</span><span class="cx"> 
</span><ins>+    checkStackPointerAlignment(); // &amp;&amp;&amp;&amp;
</ins><span class="cx">     emitFunctionEpilogue();
</span><span class="cx">     ret();
</span><span class="cx"> }
</span><span class="lines">@@ -777,6 +778,7 @@
</span><span class="cx"> 
</span><span class="cx"> void JIT::emit_op_enter(Instruction*)
</span><span class="cx"> {
</span><ins>+    checkStackPointerAlignment(); // &amp;&amp;&amp;&amp;
</ins><span class="cx">     emitEnterOptimizationCheck();
</span><span class="cx">     
</span><span class="cx">     // Even though CTI doesn't use them, we initialize our constant
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITThunkscpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.cpp (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.cpp        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.cpp        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     return ctiStub(vm, nativeCallGenerator).code();
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> MacroAssemblerCodePtr JITThunks::ctiNativeConstruct(VM* vm)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(LLINT)
</span><span class="lines">@@ -61,6 +62,12 @@
</span><span class="cx">     return ctiStub(vm, nativeConstructGenerator).code();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodePtr JITThunks::ctiNativeCallFallback(VM* vm)
+{
+    ASSERT(vm-&gt;canUseJIT());
+    return ctiStub(vm, nativeCallFallbackGenerator).code();
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef JITThunks::ctiStub(VM* vm, ThunkGenerator generator)
</span><span class="cx"> {
</span><span class="cx">     Locker locker(m_lock);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITThunksh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.h (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.h        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITThunks.h        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> 
</span><span class="cx">     MacroAssemblerCodePtr ctiNativeCall(VM*);
</span><span class="cx">     MacroAssemblerCodePtr ctiNativeConstruct(VM*);
</span><ins>+    MacroAssemblerCodePtr ctiNativeCallFallback(VM*);    
</ins><span class="cx"> 
</span><span class="cx">     MacroAssemblerCodeRef ctiStub(VM*, ThunkGenerator);
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.cpp (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -82,8 +82,6 @@
</span><span class="cx"> static void slowPathFor(
</span><span class="cx">     CCallHelpers&amp; jit, VM* vm, P_JITOperation_E slowPathFunction)
</span><span class="cx"> {
</span><del>-    // &amp;&amp;&amp;&amp;  FIXME: Need to cleanup frame below like emitFunctionEpilogue()
-    jit.breakpoint();
</del><span class="cx">     jit.emitFunctionPrologue();
</span><span class="cx">     jit.storePtr(GPRInfo::callFrameRegister, &amp;vm-&gt;topCallFrame);
</span><span class="cx">     jit.setupArgumentsExecState();
</span><span class="lines">@@ -95,11 +93,8 @@
</span><span class="cx">     // 1) Exception throwing thunk.
</span><span class="cx">     // 2) Host call return value returner thingy.
</span><span class="cx">     // 3) The function to call.
</span><del>-    jit.emitGetReturnPCFromCallFrameHeaderPtr(GPRInfo::nonPreservedNonReturnGPR);
-    jit.emitPutReturnPCToCallFrameHeader(CCallHelpers::TrustedImmPtr(0));
-    emitPointerValidation(jit, GPRInfo::nonPreservedNonReturnGPR);
-    jit.restoreReturnAddressBeforeReturn(GPRInfo::nonPreservedNonReturnGPR);
</del><span class="cx">     emitPointerValidation(jit, GPRInfo::returnValueGPR);
</span><ins>+    jit.emitFunctionEpilogue();
</ins><span class="cx">     jit.jump(GPRInfo::returnValueGPR);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -245,13 +240,15 @@
</span><span class="cx">     return virtualForThunkGenerator(vm, CodeForConstruct);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind kind)
</del><ins>+static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind kind, bool fallBack = false)
</ins><span class="cx"> {
</span><span class="cx">     int executableOffsetToFunction = NativeExecutable::offsetOfNativeFunctionFor(kind);
</span><span class="cx">     
</span><span class="cx">     JSInterfaceJIT jit(vm);
</span><span class="cx"> 
</span><del>-    jit.emitFunctionPrologue();
</del><ins>+    if (!fallBack)
+        jit.emitFunctionPrologue();
+
</ins><span class="cx">     jit.emitPutImmediateToCallFrameHeader(0, JSStack::CodeBlock);
</span><span class="cx">     jit.storePtr(JSInterfaceJIT::callFrameRegister, &amp;vm-&gt;topCallFrame);
</span><span class="cx"> 
</span><span class="lines">@@ -282,23 +279,15 @@
</span><span class="cx">     jit.emitGetCallerFrameFromCallFrameHeaderPtr(JSInterfaceJIT::regT0);
</span><span class="cx">     jit.emitGetFromCallFrameHeaderPtr(JSStack::ScopeChain, JSInterfaceJIT::regT1, JSInterfaceJIT::regT0);
</span><span class="cx">     jit.emitPutCellToCallFrameHeader(JSInterfaceJIT::regT1, JSStack::ScopeChain);
</span><del>-
-    jit.peek(JSInterfaceJIT::regT1);
-    jit.emitPutReturnPCToCallFrameHeader(JSInterfaceJIT::regT1);
-
</del><span class="cx"> #if !OS(WINDOWS)
</span><span class="cx">     // Calling convention:      f(edi, esi, edx, ecx, ...);
</span><span class="cx">     // Host function signature: f(ExecState*);
</span><span class="cx">     jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::edi);
</span><span class="cx"> 
</span><del>-    jit.subPtr(JSInterfaceJIT::TrustedImm32(16 - sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister); // Align stack after call.
-
</del><span class="cx">     jit.emitGetFromCallFrameHeaderPtr(JSStack::Callee, X86Registers::esi);
</span><span class="cx">     jit.loadPtr(JSInterfaceJIT::Address(X86Registers::esi, JSFunction::offsetOfExecutable()), X86Registers::r9);
</span><del>-    jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
</del><span class="cx">     jit.call(JSInterfaceJIT::Address(X86Registers::r9, executableOffsetToFunction));
</span><span class="cx"> 
</span><del>-    jit.addPtr(JSInterfaceJIT::TrustedImm32(16 - sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
</del><span class="cx"> #else
</span><span class="cx">     // Calling convention:      f(ecx, edx, r8, r9, ...);
</span><span class="cx">     // Host function signature: f(ExecState*);
</span><span class="lines">@@ -417,7 +406,7 @@
</span><span class="cx">     jit.jumpToExceptionHandler();
</span><span class="cx"> 
</span><span class="cx">     LinkBuffer patchBuffer(*vm, &amp;jit, GLOBAL_THUNK_ID);
</span><del>-    return FINALIZE_CODE(patchBuffer, (&quot;native %s trampoline&quot;, toCString(kind).data()));
</del><ins>+    return FINALIZE_CODE(patchBuffer, (&quot;native %s %strampoline&quot;, toCString(kind).data(), fallBack ? &quot;fallback &quot; : &quot;&quot;));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef nativeCallGenerator(VM* vm)
</span><span class="lines">@@ -425,6 +414,11 @@
</span><span class="cx">     return nativeForGenerator(vm, CodeForCall);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef nativeCallFallbackGenerator(VM* vm)
+{
+    return nativeForGenerator(vm, CodeForCall, true);
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef nativeConstructGenerator(VM* vm)
</span><span class="cx"> {
</span><span class="cx">     return nativeForGenerator(vm, CodeForConstruct);
</span><span class="lines">@@ -459,9 +453,10 @@
</span><span class="cx">     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
</span><span class="cx">     jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::regT2).linkTo(fillUndefinedLoop, &amp;jit);
</span><span class="cx"> 
</span><del>-    // Adjust call frame register to account for missing args
</del><ins>+    // Adjust call frame register and stack pointer to account for missing args
</ins><span class="cx">     jit.lshift64(JSInterfaceJIT::TrustedImm32(3), JSInterfaceJIT::regT0);
</span><span class="cx">     jit.addPtr(JSInterfaceJIT::regT0, JSInterfaceJIT::callFrameRegister);
</span><ins>+    jit.addPtr(JSInterfaceJIT::regT0, JSInterfaceJIT::stackPointerRegister);
</ins><span class="cx"> 
</span><span class="cx"> #  if CPU(X86_64)
</span><span class="cx">     jit.push(JSInterfaceJIT::regT4);
</span><span class="lines">@@ -553,7 +548,7 @@
</span><span class="cx">     SpecializedThunkJIT jit(vm, 1);
</span><span class="cx">     stringCharLoad(jit, vm);
</span><span class="cx">     jit.returnInt32(SpecializedThunkJIT::regT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;charCodeAt&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;charCodeAt&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef charAtThunkGenerator(VM* vm)
</span><span class="lines">@@ -562,7 +557,7 @@
</span><span class="cx">     stringCharLoad(jit, vm);
</span><span class="cx">     charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
</span><span class="cx">     jit.returnJSCell(SpecializedThunkJIT::regT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;charAt&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;charAt&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM* vm)
</span><span class="lines">@@ -572,7 +567,7 @@
</span><span class="cx">     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0);
</span><span class="cx">     charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
</span><span class="cx">     jit.returnJSCell(SpecializedThunkJIT::regT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;fromCharCode&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;fromCharCode&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef sqrtThunkGenerator(VM* vm)
</span><span class="lines">@@ -584,7 +579,7 @@
</span><span class="cx">     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx">     jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;sqrt&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;sqrt&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -732,7 +727,7 @@
</span><span class="cx">     doubleResult.link(&amp;jit);
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><span class="cx"> #endif // CPU(ARM64)
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;floor&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;floor&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef ceilThunkGenerator(VM* vm)
</span><span class="lines">@@ -755,7 +750,7 @@
</span><span class="cx">     jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="cx">     doubleResult.link(&amp;jit);
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;ceil&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;ceil&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef roundThunkGenerator(VM* vm)
</span><span class="lines">@@ -789,7 +784,7 @@
</span><span class="cx">     jit.returnInt32(SpecializedThunkJIT::regT0);
</span><span class="cx">     doubleResult.link(&amp;jit);
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;round&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;round&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef expThunkGenerator(VM* vm)
</span><span class="lines">@@ -802,7 +797,7 @@
</span><span class="cx">     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx">     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(exp));
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;exp&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;exp&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef logThunkGenerator(VM* vm)
</span><span class="lines">@@ -815,7 +810,7 @@
</span><span class="cx">     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx">     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(log));
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;log&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;log&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef absThunkGenerator(VM* vm)
</span><span class="lines">@@ -835,7 +830,7 @@
</span><span class="cx">     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
</span><span class="cx">     jit.absDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT1);
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;abs&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;abs&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef powThunkGenerator(VM* vm)
</span><span class="lines">@@ -887,7 +882,7 @@
</span><span class="cx">     } else
</span><span class="cx">         jit.appendFailure(nonIntExponent);
</span><span class="cx"> 
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;pow&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;pow&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
</span><span class="lines">@@ -920,7 +915,7 @@
</span><span class="cx">     } else
</span><span class="cx">         jit.appendFailure(nonIntArg1Jump);
</span><span class="cx"> 
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;imul&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;imul&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static MacroAssemblerCodeRef arrayIteratorNextThunkGenerator(VM* vm, ArrayIterationKind kind)
</span><span class="lines">@@ -960,7 +955,7 @@
</span><span class="cx">     if (kind == ArrayIterateKey) {
</span><span class="cx">         jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
</span><span class="cx">         jit.returnInt32(SpecializedThunkJIT::regT1);
</span><del>-        return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;array-iterator-next-key&quot;);
</del><ins>+        return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;array-iterator-next-key&quot;);
</ins><span class="cx">         
</span><span class="cx">     }
</span><span class="cx">     ASSERT(kind == ArrayIterateValue);
</span><span class="lines">@@ -1011,7 +1006,7 @@
</span><span class="cx">     jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
</span><span class="cx">     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
</span><span class="cx">     
</span><del>-    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCall(vm), &quot;array-iterator-next-value&quot;);
</del><ins>+    return jit.finalize(vm-&gt;jitStubs-&gt;ctiNativeCallFallback(vm), &quot;array-iterator-next-value&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef arrayIteratorNextKeyThunkGenerator(VM* vm)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitThunkGeneratorsh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.h (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.h        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/jit/ThunkGenerators.h        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef nativeCallGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeConstructGenerator(VM*);
</span><ins>+MacroAssemblerCodeRef nativeCallFallbackGenerator(VM*);
</ins><span class="cx"> MacroAssemblerCodeRef arityFixup(VM*);
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef charCodeAtThunkGenerator(VM*);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -219,6 +219,7 @@
</span><span class="cx">     end
</span><span class="cx"> end
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> macro restoreCallerPCAndCFR()
</span><span class="cx">     if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS or SH4
</span><span class="cx">         # In C_LOOP case, we're only preserving the bytecode vPC.
</span><span class="lines">@@ -229,6 +230,8 @@
</span><span class="cx">         pop cfr
</span><span class="cx">     end
</span><span class="cx"> end
</span><ins>+
+
</ins><span class="cx"> macro preserveReturnAddressAfterCall(destinationRegister)
</span><span class="cx">     if C_LOOP or ARM or ARMv7 or ARMv7_TRADITIONAL or ARM64 or MIPS or SH4
</span><span class="cx">         # In C_LOOP case, we're only preserving the bytecode vPC.
</span><span class="lines">@@ -350,12 +353,8 @@
</span><span class="cx">     if JIT_ENABLED
</span><span class="cx">         baddis 5, CodeBlock::m_llintExecuteCounter + ExecutionCounter::m_counter[t1], .continue
</span><span class="cx">         cCall2(osrSlowPath, cfr, PC)
</span><del>-        move t1, cfr
</del><span class="cx">         btpz t0, .recover
</span><del>-        # &amp;&amp;&amp;&amp; FIXME: Not sure this is right
-        break
-        # loadp ReturnPC[cfr], t2
-        # restoreReturnAddressBeforeReturn(t2)
</del><ins>+        pop cfr # pop the callerFrame since we will jump to a function that wants to save it
</ins><span class="cx">         jmp t0
</span><span class="cx">     .recover:
</span><span class="cx">         codeBlockGetter(t1)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (160339 => 160340)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2013-12-09 23:48:59 UTC (rev 160339)
+++ branches/jsCStack/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2013-12-09 23:50:26 UTC (rev 160340)
</span><span class="lines">@@ -470,6 +470,7 @@
</span><span class="cx"> 
</span><span class="cx"> _llint_op_enter:
</span><span class="cx">     traceExecution()
</span><ins>+    checkStackPointerAlignment(t2, 0xdead00e1)
</ins><span class="cx">     loadp CodeBlock[cfr], t2                // t2&lt;CodeBlock&gt; = cfr.CodeBlock
</span><span class="cx">     loadi CodeBlock::m_numVars[t2], t2      // t2&lt;size_t&gt; = t2&lt;CodeBlock&gt;.m_numVars
</span><span class="cx">     btiz t2, .opEnterDone
</span></span></pre>
</div>
</div>

</body>
</html>