<!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>[166908] trunk/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/166908">166908</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-04-07 20:55:12 -0700 (Mon, 07 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Setters are just getters that take an extra argument and don't return a value
https://bugs.webkit.org/show_bug.cgi?id=131336

Reviewed by Geoffrey Garen.
        
Other than that, they're totally the same thing.
        
This isn't as dumb as it sounds.        

Most of the work in calling an accessor has to do with emitting the necessary checks for
figuring out whether we're calling the accessor we expected, followed by the boilerplate
needed for setting up a call inside of a stub. It makes sense for the code to be totally
common.

* jit/AssemblyHelpers.h:
(JSC::AssemblyHelpers::storeValue):
(JSC::AssemblyHelpers::moveTrustedValue):
* jit/CCallHelpers.h:
(JSC::CCallHelpers::setupResults):
* jit/Repatch.cpp:
(JSC::kindFor):
(JSC::customFor):
(JSC::generateByIdStub):
(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):
(JSC::tryCachePutByID):
(JSC::tryBuildPutByIdList):
(JSC::generateGetByIdStub): Deleted.
(JSC::emitCustomSetterStub): Deleted.
* runtime/JSCJSValue.h:
(JSC::JSValue::asValue):
* runtime/PutPropertySlot.h:
(JSC::PutPropertySlot::cachedOffset):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelpersh">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCCallHelpersh">trunk/Source/JavaScriptCore/jit/CCallHelpers.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRepatchcpp">trunk/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueh">trunk/Source/JavaScriptCore/runtime/JSCJSValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePutPropertySloth">trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -1,3 +1,39 @@
</span><ins>+2014-04-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Setters are just getters that take an extra argument and don't return a value
+        https://bugs.webkit.org/show_bug.cgi?id=131336
+
+        Reviewed by Geoffrey Garen.
+        
+        Other than that, they're totally the same thing.
+        
+        This isn't as dumb as it sounds.        
+
+        Most of the work in calling an accessor has to do with emitting the necessary checks for
+        figuring out whether we're calling the accessor we expected, followed by the boilerplate
+        needed for setting up a call inside of a stub. It makes sense for the code to be totally
+        common.
+
+        * jit/AssemblyHelpers.h:
+        (JSC::AssemblyHelpers::storeValue):
+        (JSC::AssemblyHelpers::moveTrustedValue):
+        * jit/CCallHelpers.h:
+        (JSC::CCallHelpers::setupResults):
+        * jit/Repatch.cpp:
+        (JSC::kindFor):
+        (JSC::customFor):
+        (JSC::generateByIdStub):
+        (JSC::tryCacheGetByID):
+        (JSC::tryBuildGetByIDList):
+        (JSC::tryCachePutByID):
+        (JSC::tryBuildPutByIdList):
+        (JSC::generateGetByIdStub): Deleted.
+        (JSC::emitCustomSetterStub): Deleted.
+        * runtime/JSCJSValue.h:
+        (JSC::JSValue::asValue):
+        * runtime/PutPropertySlot.h:
+        (JSC::PutPropertySlot::cachedOffset):
+
</ins><span class="cx"> 2014-04-07  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Hang in debuggable application after receiving WIRPermissionDenied
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.h        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -77,6 +77,26 @@
</span><span class="cx">         store32(TrustedImm32(JSValue::CellTag), address.withOffset(TagOffset));
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><ins>+    
+    void storeValue(JSValueRegs regs, Address address)
+    {
+#if USE(JSVALUE64)
+        store64(regs.gpr(), address);
+#else
+        store32(regs.payloadGPR(), address.withOffset(PayloadOffset));
+        store32(regs.tagGPR(), address.withOffset(TagOffset));
+#endif
+    }
+    
+    void moveTrustedValue(JSValue value, JSValueRegs regs)
+    {
+#if USE(JSVALUE64)
+        move(TrustedImm64(JSValue::encode(value)), regs.gpr());
+#else
+        move(TrustedImm32(value.tag()), regs.tagGPR());
+        move(TrustedImm32(value.payload()), regs.payloadGPR());
+#endif
+    }
</ins><span class="cx"> 
</span><span class="cx"> #if CPU(X86_64) || CPU(X86)
</span><span class="cx">     static size_t prologueStackPointerDelta()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCCallHelpersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CCallHelpers.h (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/jit/CCallHelpers.h        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -1667,6 +1667,15 @@
</span><span class="cx">             swap(destA, destB);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void setupResults(JSValueRegs regs)
+    {
+#if USE(JSVALUE64)
+        move(GPRInfo::returnValueGPR, regs.gpr());
+#else
+        setupResults(regs.payloadGPR(), regs.tagGPR());
+#endif
+    }
+    
</ins><span class="cx">     void jumpToExceptionHandler()
</span><span class="cx">     {
</span><span class="cx">         // genericUnwind() leaves the handler CallFrame* in vm-&gt;callFrameForThrow,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Repatch.cpp (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Repatch.cpp        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/jit/Repatch.cpp        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -222,29 +222,66 @@
</span><span class="cx">     linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone), stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void generateGetByIdStub(
-    ExecState* exec, const PropertySlot&amp; slot, const Identifier&amp; propertyName,
-    StructureStubInfo&amp; stubInfo, StructureChain* chain, size_t count, PropertyOffset offset,
-    Structure* structure, CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel,
-    RefPtr&lt;JITStubRoutine&gt;&amp; stubRoutine)
</del><ins>+enum ByIdStubKind {
+    GetValue,
+    CallGetter,
+    CallCustomGetter,
+    CallSetter,
+    CallCustomSetter
+};
+
+static ByIdStubKind kindFor(const PropertySlot&amp; slot)
</ins><span class="cx"> {
</span><ins>+    if (slot.isCacheableValue())
+        return GetValue;
+    if (slot.isCacheableCustom())
+        return CallCustomGetter;
+    RELEASE_ASSERT(slot.isCacheableGetter());
+    return CallGetter;
+}
+
+static FunctionPtr customFor(const PropertySlot&amp; slot)
+{
+    if (!slot.isCacheableCustom())
+        return FunctionPtr();
+    return FunctionPtr(slot.customGetter());
+}
+
+static ByIdStubKind kindFor(const PutPropertySlot&amp; slot)
+{
+    RELEASE_ASSERT(!slot.isCacheablePut());
+    RELEASE_ASSERT(slot.isCacheableCustomProperty());
+    return CallCustomSetter;
+}
+
+static FunctionPtr customFor(const PutPropertySlot&amp; slot)
+{
+    if (!slot.isCacheableCustomProperty())
+        return FunctionPtr();
+    return FunctionPtr(slot.customSetter());
+}
+
+static void generateByIdStub(
+    ExecState* exec, ByIdStubKind kind, const Identifier&amp; propertyName,
+    FunctionPtr custom, StructureStubInfo&amp; stubInfo, StructureChain* chain, size_t count,
+    PropertyOffset offset, Structure* structure, CodeLocationLabel successLabel,
+    CodeLocationLabel slowCaseLabel, RefPtr&lt;JITStubRoutine&gt;&amp; stubRoutine)
+{
</ins><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><span class="cx">     GPRReg baseGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.baseGPR);
</span><ins>+    JSValueRegs valueRegs = JSValueRegs(
</ins><span class="cx"> #if USE(JSVALUE32_64)
</span><del>-    GPRReg resultTagGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.valueTagGPR);
</del><ins>+        static_cast&lt;GPRReg&gt;(stubInfo.patch.valueTagGPR),
</ins><span class="cx"> #endif
</span><del>-    GPRReg resultGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.valueGPR);
</del><ins>+        static_cast&lt;GPRReg&gt;(stubInfo.patch.valueGPR));
</ins><span class="cx">     GPRReg scratchGPR = TempRegisterSet(stubInfo.patch.usedRegisters).getFreeGPR();
</span><span class="cx">     bool needToRestoreScratch = scratchGPR == InvalidGPRReg;
</span><del>-    RELEASE_ASSERT(!needToRestoreScratch || slot.isCacheableValue());
</del><ins>+    RELEASE_ASSERT(!needToRestoreScratch || kind == GetValue);
</ins><span class="cx">     
</span><span class="cx">     CCallHelpers stubJit(&amp;exec-&gt;vm(), exec-&gt;codeBlock());
</span><span class="cx">     if (needToRestoreScratch) {
</span><del>-#if USE(JSVALUE64)
-        scratchGPR = AssemblyHelpers::selectScratchGPR(baseGPR, resultGPR);
-#else
-        scratchGPR = AssemblyHelpers::selectScratchGPR(baseGPR, resultGPR, resultTagGPR);
-#endif
</del><ins>+        scratchGPR = AssemblyHelpers::selectScratchGPR(
+            baseGPR, valueRegs.tagGPR(), valueRegs.payloadGPR());
</ins><span class="cx">         stubJit.pushToSave(scratchGPR);
</span><span class="cx">         needToRestoreScratch = true;
</span><span class="cx">     }
</span><span class="lines">@@ -276,8 +313,6 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isAccessor = slot.isCacheableGetter() || slot.isCacheableCustom();
-    
</del><span class="cx">     GPRReg baseForAccessGPR;
</span><span class="cx">     if (chain) {
</span><span class="cx">         stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR);
</span><span class="lines">@@ -286,9 +321,9 @@
</span><span class="cx">         baseForAccessGPR = baseGPR;
</span><span class="cx">     
</span><span class="cx">     GPRReg loadedValueGPR = InvalidGPRReg;
</span><del>-    if (!slot.isCacheableCustom()) {
-        if (slot.isCacheableValue())
-            loadedValueGPR = resultGPR;
</del><ins>+    if (kind != CallCustomGetter &amp;&amp; kind != CallCustomSetter) {
+        if (kind == GetValue)
+            loadedValueGPR = valueRegs.payloadGPR();
</ins><span class="cx">         else
</span><span class="cx">             loadedValueGPR = scratchGPR;
</span><span class="cx">         
</span><span class="lines">@@ -303,8 +338,8 @@
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">         stubJit.load64(MacroAssembler::Address(storageGPR, offsetRelativeToBase(offset)), loadedValueGPR);
</span><span class="cx"> #else
</span><del>-        if (slot.isCacheableValue())
-            stubJit.load32(MacroAssembler::Address(storageGPR, offsetRelativeToBase(offset) + TagOffset), resultTagGPR);
</del><ins>+        if (kind == GetValue)
+            stubJit.load32(MacroAssembler::Address(storageGPR, offsetRelativeToBase(offset) + TagOffset), valueRegs.tagGPR());
</ins><span class="cx">         stubJit.load32(MacroAssembler::Address(storageGPR, offsetRelativeToBase(offset) + PayloadOffset), loadedValueGPR);
</span><span class="cx"> #endif
</span><span class="cx">     }
</span><span class="lines">@@ -312,7 +347,6 @@
</span><span class="cx">     // Stuff for custom getters.
</span><span class="cx">     MacroAssembler::Call operationCall;
</span><span class="cx">     MacroAssembler::Call handlerCall;
</span><del>-    FunctionPtr operationFunction;
</del><span class="cx"> 
</span><span class="cx">     // Stuff for JS getters.
</span><span class="cx">     MacroAssembler::DataLabelPtr addressOfLinkFunctionCheck;
</span><span class="lines">@@ -321,14 +355,14 @@
</span><span class="cx">     std::unique_ptr&lt;CallLinkInfo&gt; callLinkInfo;
</span><span class="cx"> 
</span><span class="cx">     MacroAssembler::Jump success, fail;
</span><del>-    if (isAccessor) {
</del><ins>+    if (kind != GetValue) {
</ins><span class="cx">         // Need to make sure that whenever this call is made in the future, we remember the
</span><span class="cx">         // place that we made it from. It just so happens to be the place that we are at
</span><span class="cx">         // right now!
</span><span class="cx">         stubJit.store32(MacroAssembler::TrustedImm32(exec-&gt;locationAsRawBits()),
</span><span class="cx">             CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
</span><span class="cx"> 
</span><del>-        if (slot.isCacheableGetter()) {
</del><ins>+        if (kind == CallGetter || kind == CallSetter) {
</ins><span class="cx">             // Create a JS call using a JS call inline cache. Assume that:
</span><span class="cx">             //
</span><span class="cx">             // - SP is aligned and represents the extent of the calling compiler's stack usage.
</span><span class="lines">@@ -352,11 +386,20 @@
</span><span class="cx">             
</span><span class="cx">             // There is a 'this' argument but nothing else.
</span><span class="cx">             unsigned numberOfParameters = 1;
</span><ins>+            // ... unless we're calling a setter.
+            if (kind == CallSetter)
+                numberOfParameters++;
</ins><span class="cx">             
</span><del>-            // Get the getter; if there ain't one then the result is jsUndefined().
-            stubJit.loadPtr(
-                MacroAssembler::Address(loadedValueGPR, GetterSetter::offsetOfGetter()),
-                loadedValueGPR);
</del><ins>+            // Get the accessor; if there ain't one then the result is jsUndefined().
+            if (kind == CallSetter) {
+                stubJit.loadPtr(
+                    MacroAssembler::Address(loadedValueGPR, GetterSetter::offsetOfSetter()),
+                    loadedValueGPR);
+            } else {
+                stubJit.loadPtr(
+                    MacroAssembler::Address(loadedValueGPR, GetterSetter::offsetOfGetter()),
+                    loadedValueGPR);
+            }
</ins><span class="cx">             MacroAssembler::Jump returnUndefined = stubJit.branchTestPtr(
</span><span class="cx">                 MacroAssembler::Zero, loadedValueGPR);
</span><span class="cx">             
</span><span class="lines">@@ -384,11 +427,19 @@
</span><span class="cx">             
</span><span class="cx">             stubJit.storeCell(
</span><span class="cx">                 loadedValueGPR, calleeFrame.withOffset(JSStack::Callee * sizeof(Register)));
</span><ins>+
</ins><span class="cx">             stubJit.storeCell(
</span><span class="cx">                 baseGPR,
</span><span class="cx">                 calleeFrame.withOffset(
</span><span class="cx">                     virtualRegisterForArgument(0).offset() * sizeof(Register)));
</span><span class="cx">             
</span><ins>+            if (kind == CallSetter) {
+                stubJit.storeValue(
+                    valueRegs,
+                    calleeFrame.withOffset(
+                        virtualRegisterForArgument(1).offset() * sizeof(Register)));
+            }
+            
</ins><span class="cx">             MacroAssembler::Jump slowCase = stubJit.branchPtrWithPatch(
</span><span class="cx">                 MacroAssembler::NotEqual, loadedValueGPR, addressOfLinkFunctionCheck,
</span><span class="cx">                 MacroAssembler::TrustedImmPtr(0));
</span><span class="lines">@@ -405,6 +456,8 @@
</span><span class="cx">             stubJit.addPtr(
</span><span class="cx">                 MacroAssembler::TrustedImm32(alignedNumberOfBytesForCall),
</span><span class="cx">                 MacroAssembler::stackPointerRegister);
</span><ins>+            if (kind == CallGetter)
+                stubJit.setupResults(valueRegs);
</ins><span class="cx">             
</span><span class="cx">             done.append(stubJit.jump());
</span><span class="cx">             slowCase.link(&amp;stubJit);
</span><span class="lines">@@ -419,36 +472,35 @@
</span><span class="cx">             stubJit.addPtr(
</span><span class="cx">                 MacroAssembler::TrustedImm32(alignedNumberOfBytesForCall),
</span><span class="cx">                 MacroAssembler::stackPointerRegister);
</span><ins>+            if (kind == CallGetter)
+                stubJit.setupResults(valueRegs);
</ins><span class="cx">             
</span><span class="cx">             done.append(stubJit.jump());
</span><span class="cx">             returnUndefined.link(&amp;stubJit);
</span><span class="cx">             
</span><del>-#if USE(JSVALUE64)
-            stubJit.move(
-                MacroAssembler::TrustedImm64(JSValue::encode(jsUndefined())), resultGPR);
-#else
-            stubJit.move(MacroAssembler::TrustedImm32(JSValue::UndefinedTag), resultTagGPR);
-            stubJit.move(MacroAssembler::TrustedImm32(0), resultGPR);
-#endif
</del><ins>+            if (kind == CallGetter)
+                stubJit.moveTrustedValue(jsUndefined(), valueRegs);
</ins><span class="cx">             
</span><span class="cx">             done.link(&amp;stubJit);
</span><span class="cx">         } else {
</span><del>-            // EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
</del><ins>+            // getter: EncodedJSValue (*GetValueFunc)(ExecState*, JSObject* slotBase, EncodedJSValue thisValue, PropertyName);
+            // setter: void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
</ins><span class="cx"> #if USE(JSVALUE64)
</span><del>-            stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, MacroAssembler::TrustedImmPtr(propertyName.impl()));
</del><ins>+            if (kind == CallCustomGetter)
+                stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, MacroAssembler::TrustedImmPtr(propertyName.impl()));
+            else
+                stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, valueRegs.gpr());
</ins><span class="cx"> #else
</span><del>-            stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::TrustedImmPtr(propertyName.impl()));
</del><ins>+            if (kind == CallCustomGetter)
+                stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::TrustedImmPtr(propertyName.impl()));
+            else
+                stubJit.setupArgumentsWithExecState(baseForAccessGPR, baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), valueRegs.payloadGPR(), valueRegs.tagGPR());
</ins><span class="cx"> #endif
</span><span class="cx">             stubJit.storePtr(GPRInfo::callFrameRegister, &amp;vm-&gt;topCallFrame);
</span><span class="cx"> 
</span><del>-            operationFunction = FunctionPtr(slot.customGetter());
-
</del><span class="cx">             operationCall = stubJit.call();
</span><del>-#if USE(JSVALUE64)
-            stubJit.move(GPRInfo::returnValueGPR, resultGPR);
-#else
-            stubJit.setupResults(resultGPR, resultTagGPR);
-#endif
</del><ins>+            if (kind == CallCustomGetter)
+                stubJit.setupResults(valueRegs);
</ins><span class="cx">             MacroAssembler::Jump noException = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
</span><span class="cx">             
</span><span class="cx">             stubJit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister);
</span><span class="lines">@@ -463,10 +515,10 @@
</span><span class="cx">     LinkBuffer patchBuffer(*vm, &amp;stubJit, exec-&gt;codeBlock());
</span><span class="cx">     
</span><span class="cx">     linkRestoreScratch(patchBuffer, needToRestoreScratch, success, fail, failureCases, successLabel, slowCaseLabel);
</span><del>-    if (slot.isCacheableCustom()) {
-        patchBuffer.link(operationCall, operationFunction);
</del><ins>+    if (kind == CallCustomGetter || kind == CallCustomSetter) {
+        patchBuffer.link(operationCall, custom);
</ins><span class="cx">         patchBuffer.link(handlerCall, lookupExceptionHandler);
</span><del>-    } else if (slot.isCacheableGetter()) {
</del><ins>+    } else if (kind == CallGetter || kind == CallSetter) {
</ins><span class="cx">         callLinkInfo-&gt;hotPathOther = patchBuffer.locationOfNearCall(fastPathCall);
</span><span class="cx">         callLinkInfo-&gt;hotPathBegin = patchBuffer.locationOf(addressOfLinkFunctionCheck);
</span><span class="cx">         callLinkInfo-&gt;callReturnLocation = patchBuffer.locationOfNearCall(slowPathCall);
</span><span class="lines">@@ -482,7 +534,7 @@
</span><span class="cx">         (&quot;Get access stub for %s, return point %p&quot;,
</span><span class="cx">             toCString(*exec-&gt;codeBlock()).data(), successLabel.executableAddress()));
</span><span class="cx">     
</span><del>-    if (slot.isCacheableGetter())
</del><ins>+    if (kind == CallGetter || kind == CallSetter)
</ins><span class="cx">         stubRoutine = adoptRef(new AccessorCallJITStubRoutine(code, *vm, std::move(callLinkInfo)));
</span><span class="cx">     else
</span><span class="cx">         stubRoutine = createJITStubRoutine(code, *vm, codeBlock-&gt;ownerExecutable(), true);
</span><span class="lines">@@ -631,8 +683,9 @@
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     StructureChain* prototypeChain = structure-&gt;prototypeChain(exec);
</span><del>-    generateGetByIdStub(
-        exec, slot, propertyName, stubInfo, prototypeChain, count, offset, structure,
</del><ins>+    generateByIdStub(
+        exec, kindFor(slot), propertyName, customFor(slot), stubInfo, prototypeChain, count,
+        offset, structure,
</ins><span class="cx">         stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
</span><span class="cx">         stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase),
</span><span class="cx">         stubInfo.stubRoutine);
</span><span class="lines">@@ -712,9 +765,9 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RefPtr&lt;JITStubRoutine&gt; stubRoutine;
</span><del>-    generateGetByIdStub(
-        exec, slot, ident, stubInfo, prototypeChain, count, offset, structure,
-        stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
</del><ins>+    generateByIdStub(
+        exec, kindFor(slot), ident, customFor(slot), stubInfo, prototypeChain, count, offset,
+        structure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
</ins><span class="cx">         CodeLocationLabel(list-&gt;currentSlowPathTarget(stubInfo)), stubRoutine);
</span><span class="cx">     
</span><span class="cx">     GetByIdAccess::AccessType accessType;
</span><span class="lines">@@ -1044,73 +1097,6 @@
</span><span class="cx">             structure);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void emitCustomSetterStub(ExecState* exec, const PutPropertySlot&amp; slot,
-    StructureStubInfo&amp; stubInfo, Structure* structure, StructureChain* prototypeChain,
-    CodeLocationLabel failureLabel, RefPtr&lt;JITStubRoutine&gt;&amp; stubRoutine)
-{
-    VM* vm = &amp;exec-&gt;vm();
-    ASSERT(stubInfo.patch.spillMode == DontSpill);
-    GPRReg baseGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.baseGPR);
-#if USE(JSVALUE32_64)
-    GPRReg valueTagGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.valueTagGPR);
-#endif
-    GPRReg valueGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.valueGPR);
-    TempRegisterSet tempRegisters(stubInfo.patch.usedRegisters);
-
-    CCallHelpers stubJit(vm);
-    GPRReg scratchGPR = tempRegisters.getFreeGPR();
-    RELEASE_ASSERT(scratchGPR != InvalidGPRReg);
-    RELEASE_ASSERT(scratchGPR != baseGPR);
-    RELEASE_ASSERT(scratchGPR != valueGPR);
-    MacroAssembler::JumpList failureCases;
-    failureCases.append(branchStructure(stubJit,
-        MacroAssembler::NotEqual,
-        MacroAssembler::Address(baseGPR, JSCell::structureIDOffset()),
-        structure));
-    
-    if (prototypeChain) {
-        for (WriteBarrier&lt;Structure&gt;* it = prototypeChain-&gt;head(); *it; ++it)
-            addStructureTransitionCheck((*it)-&gt;storedPrototype(), exec-&gt;codeBlock(), stubInfo, stubJit, failureCases, scratchGPR);
-    }
-
-    // typedef void (*PutValueFunc)(ExecState*, JSObject* base, EncodedJSValue thisObject, EncodedJSValue value);
-#if USE(JSVALUE64)
-    stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, valueGPR);
-#else
-    stubJit.setupArgumentsWithExecState(MacroAssembler::TrustedImmPtr(slot.base()), baseGPR, MacroAssembler::TrustedImm32(JSValue::CellTag), valueGPR, valueTagGPR);
-#endif
-
-    // Need to make sure that whenever this call is made in the future, we remember the
-    // place that we made it from. It just so happens to be the place that we are at
-    // right now!
-    stubJit.store32(MacroAssembler::TrustedImm32(exec-&gt;locationAsRawBits()),
-        CCallHelpers::tagFor(static_cast&lt;VirtualRegister&gt;(JSStack::ArgumentCount)));
-    stubJit.storePtr(GPRInfo::callFrameRegister, &amp;vm-&gt;topCallFrame);
-
-    MacroAssembler::Call setterCall = stubJit.call();
-    
-    MacroAssembler::Jump success = stubJit.emitExceptionCheck(CCallHelpers::InvertedExceptionCheck);
-
-    stubJit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister);
-
-    MacroAssembler::Call handlerCall = stubJit.call();
-
-    stubJit.jumpToExceptionHandler();
-    LinkBuffer patchBuffer(*vm, &amp;stubJit, exec-&gt;codeBlock());
-
-    patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone));
-    patchBuffer.link(failureCases, failureLabel);
-    patchBuffer.link(setterCall, FunctionPtr(slot.customSetter()));
-    patchBuffer.link(handlerCall, lookupExceptionHandler);
-
-    stubRoutine = FINALIZE_CODE_FOR_GC_AWARE_STUB(
-        exec-&gt;codeBlock(), patchBuffer, true, nullptr,
-        (&quot;PutById custom setter stub for %s, return point %p&quot;,
-            toCString(*exec-&gt;codeBlock()).data(),
-            stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone).executableAddress()));
-}
-
-
</del><span class="cx"> static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier&amp; ident, const PutPropertySlot&amp; slot, StructureStubInfo&amp; stubInfo, PutKind putKind)
</span><span class="cx"> {
</span><span class="cx">     if (Options::forceICFailure())
</span><span class="lines">@@ -1184,9 +1170,11 @@
</span><span class="cx">         RefPtr&lt;JITStubRoutine&gt; stubRoutine;
</span><span class="cx"> 
</span><span class="cx">         StructureChain* prototypeChain = 0;
</span><ins>+        PropertyOffset offset = slot.cachedOffset();
+        size_t count = 0;
</ins><span class="cx">         if (baseValue != slot.base()) {
</span><del>-            PropertyOffset offsetIgnored;
-            if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offsetIgnored) == InvalidPrototypeChain)
</del><ins>+            count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offset);
+            if (count == InvalidPrototypeChain)
</ins><span class="cx">                 return false;
</span><span class="cx"> 
</span><span class="cx">             prototypeChain = structure-&gt;prototypeChain(exec);
</span><span class="lines">@@ -1194,8 +1182,10 @@
</span><span class="cx">         PolymorphicPutByIdList* list;
</span><span class="cx">         list = PolymorphicPutByIdList::from(putKind, stubInfo);
</span><span class="cx"> 
</span><del>-        emitCustomSetterStub(exec, slot, stubInfo,
-            structure, prototypeChain,
</del><ins>+        generateByIdStub(
+            exec, kindFor(slot), ident, customFor(slot), stubInfo, prototypeChain, count,
+            offset, structure,
+            stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
</ins><span class="cx">             stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase),
</span><span class="cx">             stubRoutine);
</span><span class="cx"> 
</span><span class="lines">@@ -1308,9 +1298,11 @@
</span><span class="cx">     if (slot.isCacheableCustomProperty() &amp;&amp; stubInfo.patch.spillMode == DontSpill) {
</span><span class="cx">         RefPtr&lt;JITStubRoutine&gt; stubRoutine;
</span><span class="cx">         StructureChain* prototypeChain = 0;
</span><ins>+        PropertyOffset offset = slot.cachedOffset();
+        size_t count = 0;
</ins><span class="cx">         if (baseValue != slot.base()) {
</span><del>-            PropertyOffset offsetIgnored;
-            if (normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offsetIgnored) == InvalidPrototypeChain)
</del><ins>+            count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offset);
+            if (count == InvalidPrototypeChain)
</ins><span class="cx">                 return false;
</span><span class="cx"> 
</span><span class="cx">             prototypeChain = structure-&gt;prototypeChain(exec);
</span><span class="lines">@@ -1318,8 +1310,10 @@
</span><span class="cx">         PolymorphicPutByIdList* list;
</span><span class="cx">         list = PolymorphicPutByIdList::from(putKind, stubInfo);
</span><span class="cx"> 
</span><del>-        emitCustomSetterStub(exec, slot, stubInfo,
-            structure, prototypeChain,
</del><ins>+        generateByIdStub(
+            exec, kindFor(slot), propertyName, customFor(slot), stubInfo, prototypeChain, count,
+            offset, structure,
+            stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToDone),
</ins><span class="cx">             CodeLocationLabel(list-&gt;currentSlowPathTarget()),
</span><span class="cx">             stubRoutine);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.h (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -291,19 +291,6 @@
</span><span class="cx">     static ptrdiff_t offsetOfPayload() { return OBJECT_OFFSETOF(JSValue, u.asBits.payload); }
</span><span class="cx">     static ptrdiff_t offsetOfTag() { return OBJECT_OFFSETOF(JSValue, u.asBits.tag); }
</span><span class="cx"> 
</span><del>-private:
-    template &lt;class T&gt; JSValue(WriteBarrierBase&lt;T&gt;);
-
-    enum HashTableDeletedValueTag { HashTableDeletedValue };
-    JSValue(HashTableDeletedValueTag);
-
-    inline const JSValue asValue() const { return *this; }
-    JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
-    JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const;
-    JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const;
-    JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
-    JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const;
-
</del><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx">     /*
</span><span class="cx">      * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
</span><span class="lines">@@ -416,6 +403,19 @@
</span><span class="cx">     #define ValueDeleted 0x4ll
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+private:
+    template &lt;class T&gt; JSValue(WriteBarrierBase&lt;T&gt;);
+
+    enum HashTableDeletedValueTag { HashTableDeletedValue };
+    JSValue(HashTableDeletedValueTag);
+
+    inline const JSValue asValue() const { return *this; }
+    JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
+    JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const;
+    JS_EXPORT_PRIVATE WTF::String toWTFStringSlowCase(ExecState*) const;
+    JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
+    JS_EXPORT_PRIVATE JSValue toThisSlowCase(ExecState*, ECMAMode) const;
+
</ins><span class="cx">     EncodedValueDescriptor u;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePutPropertySloth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h (166907 => 166908)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h        2014-04-08 03:49:37 UTC (rev 166907)
+++ trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h        2014-04-08 03:55:12 UTC (rev 166908)
</span><span class="lines">@@ -93,7 +93,6 @@
</span><span class="cx"> 
</span><span class="cx">         PropertyOffset cachedOffset() const
</span><span class="cx">         {
</span><del>-            ASSERT(isCacheablePut());
</del><span class="cx">             return m_offset;
</span><span class="cx">         }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>