Skip to content

Commit

Permalink
Add tests that exercise GetClosureScope
Browse files Browse the repository at this point in the history
Summary:
We currently have no tests that emit GetClosureScope, since we can
almost always determine the environment of a function being inlined.

Add a simple test that produces it.

Reviewed By: avp

Differential Revision: D66236885

fbshipit-source-id: b0e62e8ea1a394fb0f2c676fc51fbf33b0b0a04f
  • Loading branch information
neildhar authored and facebook-github-bot committed Dec 7, 2024
1 parent fcda87c commit 696f1f0
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
82 changes: 82 additions & 0 deletions test/Optimizer/inline-unavailable-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// RUN: %hermesc -dump-ir %s | %FileCheckOrRegen --match-full-lines %s

// Test our ability to inline functions where their enclosing environment is not
// available at the call site.

function foo(sink){
let x;
let numBar = 0;
function bar() {
let y = ++numBar;
// Assign x in bar, so the parent environment of the function is unavailable
// when we call x, and we are forced to get the environment from the
// closure.
x = function () { "inline"; return ++y; };
}
sink(bar);
return x();
}

// Auto-generated content below. Please do not modify manually.

// CHECK:scope %VS0 []

// CHECK:function global(): undefined
// CHECK-NEXT:%BB0:
// CHECK-NEXT: %0 = CreateScopeInst (:environment) %VS0: any, empty: any
// CHECK-NEXT: DeclareGlobalVarInst "foo": string
// CHECK-NEXT: %2 = CreateFunctionInst (:object) %0: environment, %foo(): functionCode
// CHECK-NEXT: StorePropertyLooseInst %2: object, globalObject: object, "foo": string
// CHECK-NEXT: ReturnInst undefined: undefined
// CHECK-NEXT:function_end

// CHECK:scope %VS1 [x: undefined|object, numBar: number]

// CHECK:scope %VS2 [y: number]

// CHECK:function foo(sink: any): number
// CHECK-NEXT:%BB0:
// CHECK-NEXT: %0 = GetParentScopeInst (:environment) %VS0: any, %parentScope: environment
// CHECK-NEXT: %1 = CreateScopeInst (:environment) %VS1: any, %0: environment
// CHECK-NEXT: %2 = LoadParamInst (:any) %sink: any
// CHECK-NEXT: %3 = CreateFunctionInst (:object) %1: environment, %bar(): functionCode
// CHECK-NEXT: StoreFrameInst %1: environment, undefined: undefined, [%VS1.x]: undefined|object
// CHECK-NEXT: StoreFrameInst %1: environment, 0: number, [%VS1.numBar]: number
// CHECK-NEXT: %6 = CallInst (:any) %2: any, empty: any, false: boolean, empty: any, undefined: undefined, undefined: undefined, %3: object
// CHECK-NEXT: %7 = LoadFrameInst (:undefined|object) %1: environment, [%VS1.x]: undefined|object
// CHECK-NEXT: %8 = TypeOfIsInst (:boolean) %7: undefined|object, typeOfIs(Function)
// CHECK-NEXT: CondBranchInst %8: boolean, %BB2, %BB1
// CHECK-NEXT:%BB1:
// CHECK-NEXT: ThrowTypeErrorInst "Trying to call a non-function": string
// CHECK-NEXT:%BB2:
// CHECK-NEXT: %11 = GetClosureScopeInst (:environment) %VS2: any, %7: undefined|object
// CHECK-NEXT: %12 = LoadFrameInst (:number) %11: environment, [%VS2.y]: number
// CHECK-NEXT: %13 = FAddInst (:number) %12: number, 1: number
// CHECK-NEXT: StoreFrameInst %11: environment, %13: number, [%VS2.y]: number
// CHECK-NEXT: ReturnInst %13: number
// CHECK-NEXT:function_end

// CHECK:function bar(): undefined
// CHECK-NEXT:%BB0:
// CHECK-NEXT: %0 = GetParentScopeInst (:environment) %VS1: any, %parentScope: environment
// CHECK-NEXT: %1 = CreateScopeInst (:environment) %VS2: any, %0: environment
// CHECK-NEXT: %2 = LoadFrameInst (:number) %0: environment, [%VS1.numBar]: number
// CHECK-NEXT: %3 = FAddInst (:number) %2: number, 1: number
// CHECK-NEXT: StoreFrameInst %0: environment, %3: number, [%VS1.numBar]: number
// CHECK-NEXT: StoreFrameInst %1: environment, %3: number, [%VS2.y]: number
// CHECK-NEXT: %6 = CreateFunctionInst (:object) %1: environment, %x(): functionCode
// CHECK-NEXT: StoreFrameInst %0: environment, %6: object, [%VS1.x]: undefined|object
// CHECK-NEXT: ReturnInst undefined: undefined
// CHECK-NEXT:function_end

// CHECK:function x(): number [allCallsitesKnownInStrictMode,unreachable]
// CHECK-NEXT:%BB0:
// CHECK-NEXT: UnreachableInst
// CHECK-NEXT:function_end
30 changes: 30 additions & 0 deletions test/hermes/inline-unavailable-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// RUN: %hermes %s | %FileCheck --match-full-lines %s
// RUN: %shermes -exec %s | %FileCheck --match-full-lines %s

// Test our ability to inline functions where their enclosing environment is not
// available at the call site.

function foo(sink){
let x;
let numBar = 0;
function bar() {
let y = ++numBar;
// Assign x in bar, so the parent environment of the function is unavailable
// when we call x, and we are forced to get the environment from the
// closure.
x = function () { "inline"; return ++y; };
}
sink(bar);
return x();
}

// Call bar when it is passed in, and then print the result.
print(foo((cb) => { cb(); cb(); cb(); }));
// CHECK: 4

0 comments on commit 696f1f0

Please sign in to comment.