-
Notifications
You must be signed in to change notification settings - Fork 651
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: We currently create `BoundFunction` as lazy if the target is lazy, and populate its properties from the target when they are accessed. However, this doesn't account for the possibility that the target is modified after the `BoundFunction` is created. If that happens, looking up the property on the `BoundFunction` will retrieve the new value instead of the value that was present when the function was bound. To address this, make `BoundFunction` always non-lazy. This should have very little effect in practice, since looking up `target.bind` will itself make `target` non-lazy, so most `BoundFunction`s should already be non-lazy. Reviewed By: avp Differential Revision: D68638177 fbshipit-source-id: 50726e819544efe2590f0ff7c79df9484b77c0b8
- Loading branch information
1 parent
608c5ba
commit ee1ac30
Showing
2 changed files
with
52 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* 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 | ||
|
||
// We previously implemented BoundFunction as a lazy object if the target was | ||
// lazy. This resulted in incorrect behaviour if the target was updated after | ||
// the BoundFunction was created. | ||
|
||
function a(){} | ||
// Looking up `a.bind` would make `a` non-lazy, so this should always work. | ||
var boundA = a.bind(); | ||
Object.defineProperty(a, "length", {value: 5}); | ||
print(boundA.length); | ||
// CHECK: 0 | ||
|
||
function b(arg1, arg2){} | ||
// `b` remains lazy here because we didn't look up anything on it. | ||
// Previously, this would have created a lazy `boundB`. | ||
var boundB = Function.prototype.bind.call(b, undefined, 1); | ||
// Modify the length property, making `b` non-lazy. | ||
Object.defineProperty(b, "length", {value: 5}); | ||
// Check that `boundB` preserves the original length minus the bound arg. | ||
print(boundB.length); | ||
// CHECK-NEXT: 1 | ||
|
||
function c(arg1, arg2, arg3){} | ||
// Modify the length property, making it a getter. | ||
Object.defineProperty(c, "length", {get: function(){print("c.length called"); return 3;}}); | ||
// Check that binding the function calls the getter. | ||
var boundC = c.bind(undefined, 1); | ||
// CHECK-NEXT: c.length called | ||
|
||
// Check that the new length is the returned length minus the bound arg. | ||
print(boundC.length); | ||
// CHECK-NEXT: 2 | ||
|
||
function d(arg1, arg2, arg3){} | ||
// As with `b` above, `d` remains lazy here. | ||
var boundD = Function.prototype.bind.call(d, undefined, 1); | ||
// Modify the length property, making it a throwing getter. | ||
Object.defineProperty(d, "length", {get: function(){throw new Error("d.length called"); }}); | ||
// Check that the getter is not called. | ||
print(boundD.length); | ||
// CHECK-NEXT: 2 |