Repository navigation
AOT: follow-up to #982: 48 fixes #983
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,876
−408
Merged
Changes from 20 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
599676b
AOT: the checks of slot types go by a plan for each layout
Jarred-Sumner e595187
AOT: the file of what the flow analysis hands on says why
Jarred-Sumner cce9fc8
AOT: a call of Math.random() is not removed or run twice
Jarred-Sumner 7719ee9
AOT: the refusal of a load by a dynamic path names the flag too
Jarred-Sumner 7a23cbf
AOT: native code that runs out of stack in an executable is reported
Jarred-Sumner e790324
AOT: seven mends in the run time's modules and mocks
Jarred-Sumner 8f2f86c
AOT: testaot can ask the laws of the algebra of types of every type o…
Jarred-Sumner 31e1efa
AOT: a step of the build counts who reads a field that assumes more t…
Jarred-Sumner 099e5b1
AOT: the build warns of a store under a name that native code locks o…
Jarred-Sumner 50fdcc3
AOT: the end of a mock gives back what the mock replaced
Jarred-Sumner 00b4078
AOT: a link that fails behind a computed name throws at the load, in …
Jarred-Sumner ee63417
AOT: the statistics tell the lines of packages, of declarations and o…
Jarred-Sumner 4265659
AOT: the detail of a stale type names an operand only where there is one
Jarred-Sumner 9b5490b
AOT: a store that is listed at its allocation goes by the proof of th…
Jarred-Sumner b798844
AOT: a test: a number stored into a new extension has the owner's bar…
Jarred-Sumner f14feaf
AOT: require() asks what the imports under a type have made of a data…
Jarred-Sumner 75c429d
AOT: a test pins the laws of the algebra of types over the types that…
Jarred-Sumner 3ff3203
AOT: a delete by key looks at the key, and an assignment asks for the…
Jarred-Sumner 2899c12
AOT: the file of what the flow analysis hands on has no blind spot
Jarred-Sumner 2ea1865
AOT: Bun read under a key that nobody knows keeps what code of the li…
Jarred-Sumner e5e3161
AOT: testaot asks for its process id the portable way
Jarred-Sumner 5aee766
AOT: a long text with accents is encoded by the library
Jarred-Sumner 82555ca
AOT: a call for a module of a graph under way settles behind the call…
Jarred-Sumner 3ca89f1
AOT: a refusal that the run time cannot decide decides no exact test
Jarred-Sumner 12aa5e1
AOT: what only an image of the library alone reached is deleted
Jarred-Sumner 9f816f4
AOT: a planted fault that drops the card of a variable
Jarred-Sumner 6f09bd3
AOT: a test run lists the compiled files that ran from source, and why
Jarred-Sumner 120a664
AOT: the stubs align with the same padding as the rest of the code
Jarred-Sumner eed8f13
AOT: an image that has noted no load has no moments
Jarred-Sumner c8fb4fe
AOT: the recheck of guards reads only what its functions reach
Jarred-Sumner ae95c46
AOT: the iterator of a map is told by its cell
Jarred-Sumner b812287
AOT: a guard that is not available names what may have ended it
Jarred-Sumner 59736f2
AOT: a cast may stand between the header's parameter and the step of …
Jarred-Sumner c6c92f5
AOT: the iterator of a set is told by its cell
Jarred-Sumner 030c7f1
AOT: an object held from ahead of the mock never reads the mock
Jarred-Sumner 11c292d
AOT: one forward walk builds a body anew in place of the compaction's…
Jarred-Sumner c4f5936
AOT: an import of a module that compiled code began settles when it h…
Jarred-Sumner 0e94bf3
AOT: the jobs behind a delivered text run ahead of the next file's body
Jarred-Sumner 03b2188
AOT: a call or a new in the place of what is constructed is quoted as…
Jarred-Sumner 8994ff7
AOT: a closure that a callee hands back keeps what it captured
Jarred-Sumner b77d9d4
AOT: the recheck of guards scans for borrowed parameters only what it…
Jarred-Sumner ab6866b
AOT: an import of a file of an image below walks its mocks once
Jarred-Sumner 76c88ac
AOT: a copy of a parameter that holds -2 is not taken for 0
Jarred-Sumner 9a5d507
AOT: what is asked of the objects of every escaped class is asked once
Jarred-Sumner 274e93a
AOT: a test that runs the frames pass alone gives the verifier the ta…
Jarred-Sumner bc7b292
AOT: two system calls at the start of an executable, and only its own…
Jarred-Sumner 35c6c14
AOT: the mocks of one handed-on namespace stand in a stack
Jarred-Sumner fc15cda
AOT: a declared iteration may step the iterator itself
Jarred-Sumner c448026
AOT: fix the macOS build
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
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
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
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
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
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
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
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
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
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
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
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
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,24 @@ | ||
| # Who names the heap of a field whose reading takes more for granted than a type says, and who calls a function that trusts its caller: <name> | <file> | <how often> | <why each is right>. | ||
| # aot/codegen/generator/reads-that-assume.ts holds the sources to these counts in every build. A declaration and a definition count as well. | ||
| JSString_value | builtins/AOTHashTableBuiltinEmitter.cpp | 5 | two test the rope bit next to the load, in front of any read through the word; three only compare the word with another one, which is right for a rope too | ||
| JSString_value | codegen/AOTInnerPointerValidation.cpp | 1 | a list of heaps, no load | ||
| JSString_value | codegen/AOTPrimitiveEmitter.h | 1 | isRopeString(): it is the test | ||
| JSString_value | codegen/AOTRuntimeValidationEmitter.cpp | 1 | tests the rope bit next to the load | ||
| JSString_value | codegen/AOTStringBuilderEmitter.cpp | 1 | tests the rope bit, reads nothing through the word | ||
| JSString_value | codegen/AOTStringBuiltinEmitter.cpp | 1 | tests the rope bit next to the load | ||
| JSString_value | codegen/AOTStringEmitter.cpp | 7 | implOfFlatString() takes a FlatStringCell; viewOfFlatString() is listed below; three test the rope bit next to the load; one reads behind the stub that has resolved the rope in place, or off the base of a substring, which is flat; one reads what FlattenString has just made | ||
| JSString_value | codegen/AOTStringEmitterComparisons.cpp | 4 | areBoth8Bit() is listed below; one only compares the word with the address of an atom; two test the rope bit next to the load | ||
| JSString_value | codegen/AOTStringSwitch.cpp | 1 | tests the rope bit next to the load | ||
| flatStringWrittenHere | builtins/AOTHashTableBuiltinEmitter.cpp | 1 | the cell is the key in its boxed form with the box taken off: a key without a number in its type is handed on as it came | ||
| flatStringWrittenHere | codegen/AOTStringEmitter.cpp | 2 | the definition; flatStringAssumedBy() hands it the cell that it has just made of the same value | ||
| flatStringWrittenHere | codegen/AOTStringEmitter.h | 1 | the declaration | ||
| flatStringAssumedBy | codegen/AOTStringEmitter.cpp | 2 | the definition; under a sabotage alone, which shows that it stops the build | ||
| flatStringAssumedBy | codegen/AOTStringEmitter.h | 1 | the declaration | ||
| viewOfFlatString | builtins/AOTMathBuiltinEmitterNumbers.cpp | 1 | behind isRopeString() of the same cell | ||
| viewOfFlatString | codegen/AOTStringBuiltinEmitter.cpp | 5 | each behind isRopeString() of the same cell | ||
| viewOfFlatString | codegen/AOTStringEmitter.cpp | 1 | the definition | ||
| viewOfFlatString | codegen/AOTStringEmitter.h | 1 | the declaration | ||
| viewOfFlatString | codegen/AOTStringEmitterComparisons.cpp | 1 | behind isRopeString() of the same cell | ||
| areBoth8Bit | codegen/AOTOperatorEmitterEquality.cpp | 1 | both operands are one character read off a string, which is flat; such a read inherits nothing, because the prototypes of built-ins are read-only in compiled code | ||
| areBoth8Bit | codegen/AOTStringEmitter.h | 1 | the declaration | ||
| areBoth8Bit | codegen/AOTStringEmitterComparisons.cpp | 1 | the definition |
125 changes: 125 additions & 0 deletions
125
Source/JavaScriptCore/aot/codegen/generator/reads-that-assume.ts
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,125 @@ | ||
| // To read some fields is to take more for granted than the type of a value says: the word in the cell of a string is a StringImpl only while the string is flat, | ||
| // and a type says what the characters are, not which object holds them. Such a field is read by few functions, which test first or take a type that only a proof can make. | ||
| // This step of the build counts, file by file, who names the heap of such a field and who calls a function that trusts its caller, and holds the counts to | ||
| // aot/codegen/AOTReadsThatAssume.txt. A place that the list lacks stops the build: go through one of the functions named in the message, or add the place with the reason why it is right. | ||
| import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; | ||
| import { join, resolve } from "node:path"; | ||
| import { parseArgs } from "node:util"; | ||
|
|
||
| const compilerDirectories = ["builtins", "codegen", "image", "object", "passes", "place", "represent", "select", "stubs"]; | ||
| const listFile = "aot/codegen/AOTReadsThatAssume.txt"; | ||
| const stampFile = "AOTReadsThatAssumeChecked.h"; | ||
|
|
||
| const watched: { name: string; pattern: RegExp; instead: string }[] = [ | ||
| { | ||
| name: "JSString_value", | ||
| pattern: /\b(?:m_)?heaps\.JSString_value\b/g, | ||
| instead: "StringEmitter::viewOf(), lengthOf(), viewOfString(), isRopeString(), or implOfFlatString() with a FlatStringCell", | ||
| }, | ||
| { | ||
| name: "flatStringWrittenHere", | ||
| pattern: /\bflatStringWrittenHere\(/g, | ||
| instead: "StringEmitter::flatStringByType(): this one trusts its caller that the cell is the value's", | ||
| }, | ||
| { | ||
| name: "flatStringAssumedBy", | ||
| pattern: /\bflatStringAssumedBy\(/g, | ||
| instead: "StringEmitter::flatStringByType(), and another road for what is not flat: this one stops the build of a user's program", | ||
| }, | ||
| { | ||
| name: "viewOfFlatString", | ||
| pattern: /\bviewOfFlatString\(/g, | ||
| instead: "StringEmitter::viewOf(): this one trusts its caller that isRopeString() of the same cell has just answered no", | ||
| }, | ||
| { | ||
| name: "areBoth8Bit", | ||
| pattern: /\bareBoth8Bit\(/g, | ||
| instead: "StringEmitter::areEqual(): this one trusts its caller that both strings are flat", | ||
| }, | ||
| ]; | ||
|
|
||
| type Counts = Map<string, number>; | ||
|
|
||
| function keyOf(name: string, file: string): string { | ||
| return `${name} | ${file}`; | ||
| } | ||
|
|
||
| function countPlaces(javascriptcore: string): Counts { | ||
| const counts: Counts = new Map(); | ||
| for (const directory of compilerDirectories) { | ||
| for (const entry of readdirSync(join(javascriptcore, "aot", directory), { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))) { | ||
| if (!entry.isFile() || !/\.(?:cpp|h)$/.test(entry.name)) continue; | ||
| const text = readFileSync(join(javascriptcore, "aot", directory, entry.name), "utf8"); | ||
| for (const { name, pattern } of watched) { | ||
| const found = text.match(pattern)?.length ?? 0; | ||
| if (found) counts.set(keyOf(name, `${directory}/${entry.name}`), found); | ||
| } | ||
| } | ||
| } | ||
| return counts; | ||
| } | ||
|
|
||
| function readList(text: string): { listed: Counts; problems: string[] } { | ||
| const listed: Counts = new Map(); | ||
| const problems: string[] = []; | ||
| for (const line of text.split("\n")) { | ||
| if (!line || line.startsWith("#")) continue; | ||
| const [name, file, count, reason] = line.split(" | "); | ||
| if (!name || !file || !/^\d+$/.test(count ?? "") || !reason?.trim()) problems.push(`${listFile}: not "<name> | <file> | <count> | <reason>": ${line}`); | ||
| else listed.set(keyOf(name, file), Number(count)); | ||
| } | ||
| return { listed, problems }; | ||
| } | ||
|
|
||
| function compare(found: Counts, listed: Counts): string[] { | ||
| const problems: string[] = []; | ||
| for (const [key, count] of found) { | ||
| const allowed = listed.get(key) ?? 0; | ||
| if (count === allowed) continue; | ||
| const [name, file] = key.split(" | "); | ||
| if (count > allowed) | ||
| problems.push( | ||
| `aot/${file} has ${count} of ${name}, the list has ${allowed}. It takes for granted what no type says. Use ${watched.find(entry => entry.name === name)!.instead}; or say in ${listFile} why the new place is right.`, | ||
| ); | ||
| else problems.push(`aot/${file} has ${count} of ${name}, the list has ${allowed}: lower the count in ${listFile}, or the next place passes unseen.`); | ||
| } | ||
| for (const [key, allowed] of listed) { | ||
| if (!found.has(key)) problems.push(`aot/${key.split(" | ")[1]} has none of ${key.split(" | ")[0]}, the list has ${allowed}: take the line out of ${listFile}.`); | ||
| } | ||
| return problems; | ||
| } | ||
|
|
||
| // A check that was never seen to fail proves nothing: every name must be found somewhere, and one place too many, one too few and one in a file of its own must each be noticed. | ||
| function hasTeeth(found: Counts): boolean { | ||
| if (!watched.every(({ name }) => [...found.keys()].some(key => key.startsWith(`${name} | `)))) return false; | ||
| const [key, count] = [...found][0] ?? []; | ||
| if (key === undefined || count === undefined) return false; | ||
| const more = new Map(found).set(key, count + 1); | ||
| const fewer = new Map(found).set(key, count - 1); | ||
| const elsewhere = new Map(found).set(keyOf(watched[0]!.name, "codegen/AOTNoSuchFile.cpp"), 1); | ||
| return !compare(found, found).length && [more, fewer, elsewhere].every(changed => compare(changed, found).length === 1 && compare(found, changed).length === 1); | ||
| } | ||
|
|
||
| const { values } = parseArgs({ | ||
| strict: true, | ||
| options: { "javascriptcore": { type: "string" }, "out": { type: "string" }, "print-counts": { type: "boolean" } }, | ||
| }); | ||
| if (values.javascriptcore === undefined || (values.out === undefined && !values["print-counts"])) { | ||
| console.error("usage: <bun or node> aot/codegen/generator/reads-that-assume.ts --javascriptcore <Source/JavaScriptCore> (--out <dir> | --print-counts)"); | ||
| process.exit(1); | ||
| } | ||
| const javascriptcore = resolve(values.javascriptcore); | ||
| const found = countPlaces(javascriptcore); | ||
| if (values["print-counts"]) { | ||
| for (const [key, count] of found) console.log(`${key} | ${count}`); | ||
| process.exit(0); | ||
| } | ||
| const { listed, problems } = readList(readFileSync(join(javascriptcore, listFile), "utf8")); | ||
| if (!hasTeeth(found)) problems.push("aot/codegen/generator/reads-that-assume.ts does not notice a place too many or too few: it checks nothing."); | ||
| problems.push(...compare(found, listed)); | ||
| if (problems.length) { | ||
| console.error(problems.join("\n")); | ||
| process.exit(1); | ||
| } | ||
| mkdirSync(values.out!, { recursive: true }); | ||
| writeFileSync(join(values.out!, stampFile), "// Written by aot/codegen/generator/reads-that-assume.ts when the sources of the compiler have passed it. Do not edit.\n"); | ||
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scan every compiler source that the build tracks.
If a compiler source under
aot/pipelineor a nested directory calls a watched function,countPlacesskips the file and can write a passing stamp without an inventory entry. The CMake dependency glob already tracks AOT sources recursively. Extend the scanner to the compiler sources covered by that build dependency. (raw.githubusercontent.com)