<html>
    <head>
      <base href="https://bugs.webkit.org/" />
    </head>
    <body><span class="vcard"><a class="email" href="mailto:sbarati&#64;apple.com" title="Saam Barati &lt;sbarati&#64;apple.com&gt;"> <span class="fn">Saam Barati</span></a>
</span> changed
              <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [ES6]. Implement Annex B.3.3 function hoisting rules for eval"
   href="https://bugs.webkit.org/show_bug.cgi?id=163208">bug 163208</a>
        <br>
             <table border="1" cellspacing="0" cellpadding="8">
          <tr>
            <th>What</th>
            <th>Removed</th>
            <th>Added</th>
          </tr>

         <tr>
           <td style="text-align:right;">Attachment #294533 Flags</td>
           <td>review?
           </td>
           <td>review-
           </td>
         </tr></table>
      <p>
        <div>
            <b><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [ES6]. Implement Annex B.3.3 function hoisting rules for eval"
   href="https://bugs.webkit.org/show_bug.cgi?id=163208#c9">Comment # 9</a>
              on <a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - [ES6]. Implement Annex B.3.3 function hoisting rules for eval"
   href="https://bugs.webkit.org/show_bug.cgi?id=163208">bug 163208</a>
              from <span class="vcard"><a class="email" href="mailto:sbarati&#64;apple.com" title="Saam Barati &lt;sbarati&#64;apple.com&gt;"> <span class="fn">Saam Barati</span></a>
</span></b>
        <pre>Comment on <span class=""><a href="attachment.cgi?id=294533&amp;action=diff" name="attach_294533" title="Patch">attachment 294533</a> <a href="attachment.cgi?id=294533&amp;action=edit" title="Patch">[details]</a></span>
Patch

View in context: <a href="https://bugs.webkit.org/attachment.cgi?id=294533&amp;action=review">https://bugs.webkit.org/attachment.cgi?id=294533&amp;action=review</a>

I think the main approach is OK, but there are a lot of little things I think might be wrong or could be better/simpler. Comments below.

<span class="quote">&gt; Source/JavaScriptCore/ChangeLog:13
&gt; +        Current patch implement Annex B.3.3 that is related to hoisting of function
&gt; +        declaration in eval. <a href="https://tc39.github.io/ecma262/#sec-web-compat-evaldeclarationinstantiation">https://tc39.github.io/ecma262/#sec-web-compat-evaldeclarationinstantiation</a>
&gt; +        Function declaration in eval should create variable with function name in function scope 
&gt; +        where eval is invoked or bind to variable if it declared outside of the eval. If variable is created 
&gt; +        it can be removed by delete a; command. If eval is invoke in block scope that 
&gt; +        contains let/const variable with the same name as function declaration  we do not binding</span >

It's worth also talking about your implementation in the changelog.

<span class="quote">&gt; Source/JavaScriptCore/bytecode/CodeBlock.cpp:2851
&gt; +        // Fixme: we do not have llint optimization for those op_codes</span >

Please file a bug for this or implement the optimization.
Also, should be FIXME not Fixme.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:754
&gt; +    auto varKind = [&amp;] (UniquedStringImpl* uid) -&gt; VarKind {
&gt; +        return evalNode-&gt;captures(uid) ? VarKind::Scope : VarKind::Stack;
&gt; +    };
&gt; +
&gt; +    for (FunctionMetadataNode* function : evalNode-&gt;functionStack()) {
&gt; +        VarKind kind = varKind(function-&gt;ident().impl());
&gt; +        if (kind == VarKind::Scope)
&gt; +            m_codeBlock-&gt;addFunctionDecl(makeFunction(function));
&gt; +        else
&gt; +            m_functionsToInitialize.append(std::make_pair(function, GlobalFunctionVariable));
&gt; +    }</span >

Why is this change needed?

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2193
&gt; +RegisterID* BytecodeGenerator::emitResolveOuterScopeType(RegisterID* dst, RegisterID* scope)</span >

This function name is incorrect.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2196
&gt; +    m_codeBlock-&gt;addPropertyAccessInstruction(instructions().size());</span >

This looks wrong.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2201
&gt; +    dst = tempDestination(dst);
&gt; +    emitOpcode(op_is_scope_var_type);
&gt; +    instructions().append(kill(dst));</span >

Why not just make dst the result w/out all the tempDestination stuff? This seems like it could be wrong.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2209
&gt; +    m_codeBlock-&gt;addPropertyAccessInstruction(instructions().size());</span >

This looks wrong.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2215
&gt; +    </span >

remove newline.

<span class="quote">&gt; Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp:2217
&gt; +    instructions().append(localScopeDepth());</span >

Why not just make the access off the base-most scope of the eval instead of having a local scope depth? We should already have the scope on the symbol table stack, right?

<span class="quote">&gt; Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:1100
&gt; +                        JSScope* scope = jsCast&lt;JSScope*&gt;(child.value());</span >

Doesn't LexicalEnvironmentType guarantee that it's a JSSymbolTableObject?

<span class="quote">&gt; Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h:1103
&gt; +                        if (scope-&gt;symbolTable() != nullptr)
&gt; +                            result = scope-&gt;symbolTable()-&gt;scopeType() == SymbolTable::ScopeType::VarScope;</span >

How we normally do this is:
if (SymbolTable* symbolTable = scope-&gt;symbolTable())
     ....

<span class="quote">&gt; Source/JavaScriptCore/dfg/DFGNode.h:983
&gt; +    int32_t getOpInfo2()</span >

Please give this a name for your usage of it.

<span class="quote">&gt; Source/JavaScriptCore/dfg/DFGOperations.h:193
&gt; +JSCell* JIT_OPERATION operationResolveClosestVarScope(ExecState*, JSScope*, UniquedStringImpl*, int32_t);</span >

should be uint32_t

<span class="quote">&gt; Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp:8777
&gt; +    callOperation(operationResolveClosestVarScope, resultGPR, scopeGPR, identifierUID(node-&gt;identifierNumber()), node-&gt;getOpInfo2());</span >

We usually give names to the opInfo methods so we know what it's for.

<span class="quote">&gt; Source/JavaScriptCore/jit/JITPropertyAccess.cpp:821
&gt; +    linkSlowCase(iter);
&gt; +    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_is_scope_var_type);
&gt; +    slowPathCall.call();</span >

This should not have a slow path. The fast path should do the function call.

<span class="quote">&gt; Source/JavaScriptCore/jit/JITPropertyAccess.cpp:828
&gt; +    linkSlowCase(iter);
&gt; +    JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_resolve_closest_var_scope);
&gt; +    slowPathCall.call();</span >

ditto

<span class="quote">&gt; Source/JavaScriptCore/parser/Parser.h:1182
&gt; +            // We allways try to hoist function to top scope inside of eval</span >

I don't think this comment adds anything.

<span class="quote">&gt; Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:826
&gt; +    CHECK_EXCEPTION();</span >

An exception could not be thrown by the previous statement.

<span class="quote">&gt; Source/JavaScriptCore/runtime/CommonSlowPaths.cpp:832
&gt; +    else if (scope-&gt;symbolTable() != nullptr)
&gt; +        result = scope-&gt;symbolTable()-&gt;scopeType() == SymbolTable::ScopeType::VarScope;</span >

We usually do:
else if (SymbolTable* symbolTable = scope-&gt;symbolTable())

<span class="quote">&gt; Source/JavaScriptCore/runtime/JSScope.cpp:218
&gt; +JSObject* JSScope::resolveClosestVar(ExecState* exec, JSScope* scope, const Identifier&amp; ident, int skipScope)</span >

should be unsigned instead of int

<span class="quote">&gt; Source/JavaScriptCore/runtime/JSScope.cpp:224
&gt; +    int skipedScopes = 0;</span >

typo, should be: &quot;skippedScopes&quot;
also, should be unsigned.

<span class="quote">&gt; Source/JavaScriptCore/runtime/JSScope.cpp:245
&gt; +        if (skipedScopes &lt; skipScope) {
&gt; +            ++skipedScopes;
&gt; +            continue;
&gt; +        }</span >

Why not just have the bytecode emit starting from the base-most scope of the function and you can remove the skipScope parameter entirely?</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are the assignee for the bug.</li>
      </ul>
    </body>
</html>