Repository navigation
[JSC] Add live module exports for module mocks, plus fifteen smaller changes for bun test #781
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+2,959
−98
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
6e5dc1a
[JSC] Add live exports to module records
Jarred-Sumner 16c9b13
[JSC] Allow a Proxy in the global object's prototype chain
Jarred-Sumner 6a9159f
[JSC] Make the CodeCache entry limit configurable
Jarred-Sumner 4e9ab72
[JSC] Resolve a static import once while it is loading
Jarred-Sumner 5821913
[JSC] Compile /(?:X)+/ as /(?:X)*/ when X can always match the empty …
Jarred-Sumner df3fccd
[JSC] Function.prototype.call should not need an array for a few argu…
Jarred-Sumner 93890b6
[JSC] Make the checks for live module exports cheaper
Jarred-Sumner 1b38d15
[JSC] YarrJIT should save only the frame slots of the alternative tha…
Jarred-Sumner 52cfbe9
[JSC] A WebAssembly import of a re-exported live export follows the r…
Jarred-Sumner 2fecf94
[JSC] YarrJIT: a greedy group in tail position needs no state from ea…
Jarred-Sumner 150a846
[JSC] Yarr: neighbouring alternatives of one character are one charac…
Jarred-Sumner ecb1cca
[JSC] Yarr: a tail loop matches a run of characters without going aro…
Jarred-Sumner ce8cd0f
[JSC] Yarr: the limit on a pattern's length does not count what is in…
Jarred-Sumner 97bebb5
[JSC] YarrJIT should free the ParenContexts of a failed attempt befor…
Jarred-Sumner 1dcfd63
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 464364e
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 0a1dc02
[JSC] Yarr: a character class with a property escape counts in full t…
Jarred-Sumner 44bcc6a
[JSC] Yarr: only a class of characters and ranges is left out of the …
Jarred-Sumner eae4fc2
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner cb2e3b1
[JSC] mergeSingleCharacterAlternatives() should restore m_isLastAlter…
Jarred-Sumner bb19c72
[JSC] function-prototype-call-not-called-as-a-method.js should tell u…
Jarred-Sumner 0bf60dd
[JSC] Reword the comments about the Yarr pattern length limit and tai…
Jarred-Sumner 2a1191f
[JSC] resolveExport() should treat an AOT module's `export *` targets…
Jarred-Sumner 03984bd
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 559f519
[JSC] Four RegExp stress tests should run in under 200 ms
Jarred-Sumner 35c0e0c
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner f2b7fc8
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 482602d
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 1840866
[JSC] A RegExp nested too deep should throw the same error as before
Jarred-Sumner 1fb1904
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 483c671
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner e28a3c0
[JSC] BUN-TEST-DIFFERENCES.md should list the nine stress tests this …
Jarred-Sumner 78b0b83
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner 2957847
[JSC] CallData::Type should be word-sized
Jarred-Sumner 52117f4
[JSC] Interpreter::executeCall should not reserve stack for bound fun…
Jarred-Sumner e3728e9
Merge branch 'main' into claude/module-live-exports
Jarred-Sumner File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
129 changes: 129 additions & 0 deletions
129
JSTests/stress/function-prototype-call-not-called-as-a-method.js
This file contains hidden or 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,129 @@ | ||
| // f.call(...) is compiled to a call of f. These are the ways to reach Function.prototype.call itself. | ||
| function describe(value) | ||
| { | ||
| // By default JSON.stringify() prints these as null. | ||
| return JSON.stringify(value, (key, value) => value === undefined || (typeof value === "number" && !isFinite(value)) ? `<${value}>` : value); | ||
| } | ||
|
|
||
| function shouldBe(actual, expected, what) | ||
| { | ||
| actual = describe(actual); | ||
| expected = describe(expected); | ||
| if (actual !== expected) | ||
| throw new Error(what + ": expected " + expected + " but got " + actual); | ||
| } | ||
|
|
||
| function shouldThrow(func, errorType, what) | ||
| { | ||
| let error; | ||
| try { | ||
| func(); | ||
| } catch (e) { | ||
| error = e; | ||
| } | ||
| if (!(error instanceof errorType)) | ||
| throw new Error(what + ": expected a " + errorType.name + " but got " + error); | ||
| } | ||
|
|
||
| const call = Function.prototype.call; | ||
| shouldBe([call.length, call.name], [1, "call"], "length and name"); | ||
|
|
||
| function strict() { "use strict"; return [this === undefined ? "undefined" : this, arguments.length, ...arguments]; } | ||
| const sloppy = new Function(`return [this === globalThis ? "global" : typeof this, arguments.length, ...arguments];`); | ||
| function target() { return new.target === undefined; } | ||
| function thrower(value) { throw new RangeError(value); } | ||
| class Base { constructor() { } } | ||
|
|
||
| const uncurried = call.bind(strict); | ||
| const uncurriedSloppy = call.bind(sloppy); | ||
| const callCall = call.bind(call); | ||
| const withThis = call.bind(strict, "bound this"); | ||
| const withArguments = call.bind(strict, "bound this", 1, 2); | ||
| const hasOwn = call.bind(Object.prototype.hasOwnProperty); | ||
| const slice = call.bind(Array.prototype.slice); | ||
| const includes = call.bind(String.prototype.includes); | ||
| const push = call.bind(Array.prototype.push); | ||
| const max = call.bind(Math.max); | ||
| const symbol = Symbol(); | ||
| const objects = [{ a: 1, [symbol]: 1 }, { b: 1 }, Object.create({ [symbol]: 1 }), [1], function () { }]; | ||
|
|
||
| function test() | ||
| { | ||
| shouldBe(uncurried(), ["undefined", 0], "no arguments"); | ||
| for (let count = 0; count <= 8; ++count) { | ||
| const rest = Array.from({ length: count }, (_, i) => i + 1); | ||
| shouldBe(uncurried("t", ...rest), ["t", count, ...rest], "spread, " + count); | ||
| shouldBe(Reflect.apply(call, strict, ["t", ...rest]), ["t", count, ...rest], "Reflect.apply, " + count); | ||
| shouldBe(callCall(strict, "t", ...rest), ["t", count, ...rest], "call.bind(call), " + count); | ||
| shouldBe(call.call(strict, "t", ...rest), ["t", count, ...rest], "call.call, " + count); | ||
| shouldBe(call.apply(strict, ["t", ...rest]), ["t", count, ...rest], "call.apply, " + count); | ||
| shouldBe(withThis(...rest), ["bound this", count, ...rest], "bound this, " + count); | ||
| shouldBe(withArguments(...rest), ["bound this", count + 2, 1, 2, ...rest], "bound arguments, " + count); | ||
| } | ||
| shouldBe(uncurried("t"), ["t", 0], "1"); | ||
| shouldBe(uncurried("t", 1), ["t", 1, 1], "2"); | ||
| shouldBe(uncurried("t", 1, 2), ["t", 2, 1, 2], "3"); | ||
| shouldBe(uncurried("t", 1, 2, 3), ["t", 3, 1, 2, 3], "4"); | ||
| shouldBe(uncurried("t", 1, 2, 3, 4), ["t", 4, 1, 2, 3, 4], "5"); | ||
| shouldBe(uncurried("t", undefined), ["t", 1, undefined], "an undefined argument counts"); | ||
| shouldBe(uncurried(undefined, undefined, undefined), ["undefined", 2, undefined, undefined], "undefined arguments count"); | ||
| shouldBe(uncurried(null), [null, 0], "null this, strict"); | ||
| shouldBe(uncurriedSloppy(), ["global", 0], "no this, sloppy"); | ||
| shouldBe(uncurriedSloppy(null, 1), ["global", 1, 1], "null this, sloppy"); | ||
| shouldBe(uncurriedSloppy(1, 1), ["object", 1, 1], "primitive this, sloppy"); | ||
| shouldBe(call.bind(target)(), true, "new.target"); | ||
| shouldBe(callCall(callCall, callCall, strict, "t", 1), ["t", 1, 1], "nested"); | ||
|
|
||
| shouldBe(objects.map(object => hasOwn(object, symbol)), [true, false, false, false, false], "hasOwnProperty, symbol"); | ||
| shouldBe(objects.map(object => hasOwn(object, "a")), [true, false, false, false, false], "hasOwnProperty, string"); | ||
| shouldBe(objects.map(object => hasOwn(object, 0)), [false, false, false, true, false], "hasOwnProperty, index"); | ||
| shouldBe(objects.map(object => hasOwn(object)), [false, false, false, false, false], "hasOwnProperty, nothing"); | ||
| shouldBe([slice([1, 2, 3]), slice([1, 2, 3], 1), slice([1, 2, 3], 1, 2), slice("abc", 1)], [[1, 2, 3], [2, 3], [2], ["b", "c"]], "slice"); | ||
| shouldBe([includes("abc", "b"), includes("abc", "b", 2), includes("abc")], [true, false, false], "includes"); | ||
| const array = []; | ||
| shouldBe([push(array), push(array, 1), push(array, 2, 3), push(array, 4, 5, 6), push(array, 7, 8, 9, 10, 11), array], [0, 1, 3, 6, 11, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], "push"); | ||
| shouldBe([max(null, 1, 3, 2), max(null, 1, 3, 2, 5, 4), max()], [3, 5, -Infinity], "Math.max"); | ||
|
|
||
| shouldThrow(() => hasOwn(undefined, "a"), TypeError, "hasOwnProperty of undefined"); | ||
| shouldThrow(() => hasOwn(null, "a"), TypeError, "hasOwnProperty of null"); | ||
| shouldThrow(() => call.bind(thrower)(null, "x"), RangeError, "the callee throws"); | ||
| shouldThrow(() => call.bind(Base)(), TypeError, "a class constructor"); | ||
| for (const notCallable of [undefined, null, 1, "s", symbol, {}, []]) { | ||
| for (let count = 0; count <= 6; ++count) | ||
| shouldThrow(() => Reflect.apply(call, notCallable, Array(count).fill(1)), TypeError, "not callable, " + count); | ||
| shouldThrow(() => callCall(notCallable, 1, 2), TypeError, "not callable, call.bind(call)"); | ||
| } | ||
| shouldThrow(() => new call(), TypeError, "new"); | ||
| } | ||
| noInline(test); | ||
|
|
||
| for (let i = 0; i < testLoopCount / 200; ++i) | ||
| test(); | ||
|
|
||
| // Hot enough for the DFG and the FTL to inline the bound function, Function.prototype.call and the callee. | ||
| function hot(object, i) | ||
| { | ||
| return [hasOwn(object, symbol), hasOwn(object, "a"), uncurried(object, i)[2], callCall(strict, object, i, 1)[1], includes("abc", "b"), max(null, i, 1, 2, 3, 4)]; | ||
| } | ||
| noInline(hot); | ||
| for (let i = 5; i < testLoopCount; ++i) | ||
| shouldBe(hot(objects[i % 2], i), [!(i % 2), !(i % 2), i, 2, true, i], "hot"); | ||
|
|
||
| // A callee that changes, and an argument count that changes, at one call site. | ||
| function callIt(f, ...rest) { return callCall(f, ...rest); } | ||
| noInline(callIt); | ||
| for (let i = 0; i < testLoopCount / 2; ++i) { | ||
| shouldBe(callIt(strict, "t", i), ["t", 1, i], "same callee"); | ||
| if (!(i % 100)) { | ||
| shouldBe(callIt(sloppy, 1, i, 2, 3, 4, 5), ["object", 5, i, 2, 3, 4, 5], "another callee"); | ||
| shouldBe(callIt(Math.max, null, i, -1), i, "a native callee"); | ||
| } | ||
| } | ||
|
|
||
| // Many arguments. | ||
| shouldBe(uncurried("t", ...Array(10000).fill(0))[1], 10000, "10000 arguments"); | ||
| shouldThrow(() => uncurried("t", ...Array(0x100001).fill(0)), RangeError, "too many arguments"); | ||
|
|
||
| // The arguments are read when the call is made. | ||
| function reassigns(a, b) { "use strict"; a = 10; b = 20; return [arguments[0], arguments[1], a, b]; } | ||
| shouldBe(call.bind(reassigns)(null, 1, 2), [1, 2, 10, 20], "the callee's parameters"); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.