<div class="gmail_quote">2011/6/19 David Bruant <span dir="ltr"><<a href="mailto:david.bruant@labri.fr">david.bruant@labri.fr</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<u></u>

  
    
  
  <div text="#000000" bgcolor="#ffffff">
    Le 19/06/2011 17:43, Tom Van Cutsem a écrit :
    <div class="im"><blockquote type="cite">
      <div class="gmail_quote">2011/6/17 David Bruant <span dir="ltr"><<a href="mailto:david.bruant@labri.fr" target="_blank">david.bruant@labri.fr</a>></span><br>
        <blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">
          <div text="#000000" bgcolor="#ffffff">Symetrically to the
            forwarding of defineProperty, maybe that
            getOwnPropertyDescriptor could be forwarded too (requires to
            call the getOwnPropertyDescriptor trap for non-configurable
            properties) and the return value could be used to redefine
            writable on the proxy fixed property if necessary.<br>
          </div>
        </blockquote>
        <div><br>
        </div>
        <div>
          <div>Yep, trapping getOwnPropertyDescriptor on fixed
            properties seems to close the loop.</div>
        </div>
        <div><br>
        </div>
        <div>However, I find it strange that the return value of
          getOwnPropertyDescriptor would actually implicitly side-effect
          the fixed property of the proxy. I naturally think of
          defineProperty as a side-effecting trap, not so for
          getOwnPropertyDescriptor. Perhaps it should only check the
          return value for consistency with the fixed descriptor,
          without side-effects.</div>
      </div>
    </blockquote></div>
    It won't be enough to ensure invariants.<br>
    ----<br>
    var ep = EvilProxy();<br>
    Object.defineProperty(ep, 'a', {value:1, configurable:false,
    writable:true}); // works as expected<br>
    Object.getOwnPropertyDescriptor(ep, 'a'); // {value:1,
    configurable:false, writable:true}<br>
    // This is the stored fixed property descriptor<br>
    Object.getOwnPropertyDescriptor(ep, 'a'); // {value:1,
    configurable:false, writable:false} is legitimate<br>
    // because it doesn't break any invariant. No side effect-here,
    stored descriptor remains the same<br>
    Object.getOwnPropertyDescriptor(ep, 'a'); // {value:1,
    configurable:false, writable:true}<br>
    // This is coherent with what is stored in the fixed property record<br>
    ----<br>
    My point is that the second Object.getOwnPropertyDescriptor call is
    legitimate, but if we do not store that writable changed from "true"
    to "false", then it can be later observed as "true" which violates
    the ES5.1 invariant:<br>
    "If the [[Writable]] attribute may change from false to true, then
    the [[Configurable]] attribute must be true."<br>
    Consequently, for this very case (changing writable from false to
    true for non-configurable properties), getOwnPropertyDescriptor
    needs to have a side-effect. That's probably the only one.<br>
    <br>
    To sum up, we need to trap getOwnPropertyDescriptor for writable
    consistency in the forwarding use case. However, if we trap and do
    not have a side effect, an EvilProxy could break an invariant.<br>
    <br>
    <br>
    Also, as it turns out, there is actually no need to store the entire
    property descriptor for fixed properties to enforce invariants.
    There is a need to store:<br>
    1) Whether the property has been observed as non-configurable and if
    it's the case:<br>
    1.1) Whether writable has been observed to false and if it's the
    case<br>
    1.1.1) latest observed/provided value (no need to keep the value
    until configurable and writable or both false since it can be
    changed anytime. First universal property invariant)<br>
    1.2) latest observed/provided get/set<br>
    1.3) latest observed/provided enumerable (there are no invariants on
    this one, so I'm not sure)<br>
    <br>
    I think that the notion of "latest observed" is the one requiring
    getOwnPropertyDescriptor to have side-effects (even though it may
    sound counter intuitive).<br></div></blockquote><div><br></div><div>Yes, you're right. Thanks for the clarifying example. I gave a first shot at trying to define the semantics of [[GetOwnProperty]] for Proxies with support for fixed properties:</div>
<div><br></div><div><div>[[GetOwnProperty]] (P)</div><div>1. Let handler be the value of the [[Handler]] internal property of O.</div><div>2. Let getOwnProperty be the result of calling the [[Get]] internal method of handler with argument “getOwnPropertyDescriptor”.</div>
<div>3. If getOwnProperty is undefined, throw a TypeError exception.</div><div>4. If IsCallable(getOwnProperty) is false, throw a TypeError exception.</div><div>5. Let trapResult be the result of calling the [[Call]] internal method of getOwnProperty providing handler as the this value and P as the first argument.</div>
<div>6. Let fixedProperty be the result of calling Object.[[GetOwnProperty]]( P )</div><div>7. If trapResult is undefined</div><div>  a. If fixedProperty is undefined, return undefined</div><div>  b. Otherwise, fixedProperty is defined, so throw a TypeError</div>
<div>8. Let desc be ToCompletePropertyDescriptor(trapResult)</div><div>9. If fixedProperty is not undefined, or desc.[[Configurable]] is false</div><div>  a. call Object.[[DefineOwnProperty]](P, desc, true)</div><div>10. Return desc</div>
</div><div><br></div><div><div>Here, Object.[[GetOwnProperty]] and Object.[[DefineOwnProperty]] refer to the algorithms for Object values</div><div>from ES5 sections 8.12.1 and 8.12.9 respectively.</div><div>Line 7.b. is necessary to guard against a handler reporting a previously fixed property as undefined.</div>
</div><div><br></div><div>It's true that the proxy does not necessarily need to store the entire fixed property descriptor. However, in terms of specifying the semantics, reusing the existing built-in semantics for Objects seems easier to grasp.</div>
<div><br></div><div>Cheers,</div><div>Tom</div></div>