Skip to content

Commit

Permalink
[MERGE #5914 @boingoing] Class members which capture super via dot (s…
Browse files Browse the repository at this point in the history
…uper.constructor) end up getting the wrong value

Merge pull request #5914 from boingoing:super_capture_ts

Class members which capture super via dot (super.constructor) end up getting the wrong value

    We were using the wrong bytecode register when emitting LdHomeObjProto in the case of a lambda capturing super via a dot reference. Consider this Javascript:

    ```javascript
    class A { }
    class B extends A {
        foo() {
            const _s = () => super.constructor;
            console.log(_s().name);
        }
    }
    ```
    The member function foo correctly stashes this and super but the lambda needs to load them from the environment and it was loading them into the same register. Here's the incorrect bytecode:
    ```
    Function _s ( (#1.5), #6) (In0) (size: 8 [8])
          5 locals (2 temps from R3), 1 inline cache
        Constant Table:
        ======== =====
         R1 LdRoot

      Line  13: super.constructor
      Col   26: ^
        0000   ProfiledLdEnvSlot    R3 = [1][2]  <0>
        0006   ProfiledLdEnvSlot    R3 = [1][3]  <1>
        000c   LdHomeObjProto       R4  R3
        0011   ProfiledLdSuperFld   R0 = R4(this=R3). #0 <0>
        0019   Br                   x:001e (   2)
        001c   LdUndef              R0
    ```
    With the fix in this PR, here's the bytecode we get for _s:
    ```
    Function _s ( (#1.5), #6) (In0) (size: 8 [8])
          6 locals (3 temps from R3), 1 inline cache
        Constant Table:
        ======== =====
         R1 LdRoot

      Line  56: super.constructor
      Col   26: ^
        0000   ProfiledLdEnvSlot    R3 = [1][2]  <0>
        0006   ProfiledLdEnvSlot    R4 = [1][3]  <1>
        000c   LdHomeObjProto       R5  R3
        0011   ProfiledLdSuperFld   R0 = R5(this=R4). #0 <0>
        0019   Br                   x:001e (   2)
        001c   LdUndef              R0
    ```
  • Loading branch information
boingoing committed Feb 8, 2019
2 parents 9c289b8 + 9b24ee4 commit 87249a1
Show file tree
Hide file tree
Showing 3 changed files with 1,613 additions and 1,532 deletions.
41 changes: 17 additions & 24 deletions lib/Runtime/ByteCode/ByteCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10833,44 +10833,37 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
case knopDot:
{
Emit(pnode->AsParseNodeBin()->pnode1, byteCodeGenerator, funcInfo, false);
funcInfo->ReleaseLoc(pnode->AsParseNodeBin()->pnode1);
funcInfo->AcquireLoc(pnode);
Js::PropertyId propertyId = pnode->AsParseNodeBin()->pnode2->AsParseNodeName()->PropertyIdFromNameNode();

Js::RegSlot callObjLocation = pnode->AsParseNodeBin()->pnode1->location;
Js::RegSlot protoLocation = callObjLocation;

if (ByteCodeGenerator::IsSuper(pnode->AsParseNodeBin()->pnode1))
{
Emit(pnode->AsParseNodeSuperReference()->pnodeThis, byteCodeGenerator, funcInfo, false);
protoLocation = byteCodeGenerator->EmitLdObjProto(Js::OpCode::LdHomeObjProto, callObjLocation, funcInfo);
funcInfo->ReleaseLoc(pnode->AsParseNodeSuperReference()->pnodeThis);
}

funcInfo->ReleaseLoc(pnode->AsParseNodeBin()->pnode1);
funcInfo->AcquireLoc(pnode);
Js::PropertyId propertyId = pnode->AsParseNodeBin()->pnode2->AsParseNodeName()->PropertyIdFromNameNode();
uint cacheId = funcInfo->FindOrAddInlineCacheId(protoLocation, propertyId, false, false);

if (propertyId == Js::PropertyIds::length)
{
uint cacheId = funcInfo->FindOrAddInlineCacheId(protoLocation, propertyId, false, false);
byteCodeGenerator->Writer()->PatchableProperty(Js::OpCode::LdLen_A, pnode->location, protoLocation, cacheId);
}
else if (pnode->IsCallApplyTargetLoad())
{
if (ByteCodeGenerator::IsSuper(pnode->AsParseNodeBin()->pnode1))
{
Emit(pnode->AsParseNodeSuperReference()->pnodeThis, byteCodeGenerator, funcInfo, false);
protoLocation = byteCodeGenerator->EmitLdObjProto(Js::OpCode::LdHomeObjProto, callObjLocation, funcInfo);
funcInfo->ReleaseLoc(pnode->AsParseNodeSuperReference()->pnodeThis);
}
uint cacheId = funcInfo->FindOrAddInlineCacheId(protoLocation, propertyId, false, false);
byteCodeGenerator->Writer()->PatchableProperty(Js::OpCode::LdFldForCallApplyTarget, pnode->location, protoLocation, cacheId);
}
else if (ByteCodeGenerator::IsSuper(pnode->AsParseNodeBin()->pnode1))
{
byteCodeGenerator->Writer()->PatchablePropertyWithThisPtr(Js::OpCode::LdSuperFld, pnode->location, protoLocation, pnode->AsParseNodeSuperReference()->pnodeThis->location, cacheId, isConstructorCall);
}
else
{
if (ByteCodeGenerator::IsSuper(pnode->AsParseNodeBin()->pnode1))
{
Emit(pnode->AsParseNodeSuperReference()->pnodeThis, byteCodeGenerator, funcInfo, false);
protoLocation = byteCodeGenerator->EmitLdObjProto(Js::OpCode::LdHomeObjProto, callObjLocation, funcInfo);
funcInfo->ReleaseLoc(pnode->AsParseNodeSuperReference()->pnodeThis);
uint cacheId = funcInfo->FindOrAddInlineCacheId(protoLocation, propertyId, false, false);
byteCodeGenerator->Writer()->PatchablePropertyWithThisPtr(Js::OpCode::LdSuperFld, pnode->location, protoLocation, pnode->AsParseNodeSuperReference()->pnodeThis->location, cacheId, isConstructorCall);
}
else
{
uint cacheId = funcInfo->FindOrAddInlineCacheId(callObjLocation, propertyId, false, false);
byteCodeGenerator->Writer()->PatchableProperty(Js::OpCode::LdFld, pnode->location, callObjLocation, cacheId, isConstructorCall);
}
byteCodeGenerator->Writer()->PatchableProperty(Js::OpCode::LdFld, pnode->location, callObjLocation, cacheId, isConstructorCall);
}

break;
Expand Down
Loading

0 comments on commit 87249a1

Please sign in to comment.