mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Docs, Chore] (docs, tools, MobileGL, scripts, CONTRIBUTING.md, .gitignore): translate the documentation and use US spelling
This commit is contained in:
@@ -24,7 +24,7 @@ A gate whose baker is a different program from the gate has the same failure one
|
||||
day the CLI's defaults and the library's diverge, the gate reds on a header nobody can
|
||||
regenerate, and the fix is to edit the words by hand.
|
||||
|
||||
FORMATTING IS PRESERVED PER HEADER, not normalised: the headers in the tree disagree about
|
||||
FORMATTING IS PRESERVED PER HEADER, not normalized: the headers in the tree disagree about
|
||||
words per line and about the `u` suffix, and reformatting one of them would bury a one-word
|
||||
change in a whole-file diff. The style is read back out of the array being replaced.
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ def repo_relative(path, cwd):
|
||||
"""normpath the -H spelling, then express it repo-relative with forward slashes.
|
||||
|
||||
Today's transcripts contain e.g. TextureState/../SamplerState/SamplerObject.h, which
|
||||
only matches a forbidden prefix after normalisation. Anything outside the repo (the
|
||||
only matches a forbidden prefix after normalization. Anything outside the repo (the
|
||||
toolchain's own headers, /usr/include) is not our business and returns None.
|
||||
"""
|
||||
absolute = os.path.normpath(os.path.join(cwd, path))
|
||||
@@ -498,7 +498,7 @@ Multiple include guards may be useful for:
|
||||
|
||||
|
||||
def self_test_parser():
|
||||
"""Check 4: the trailer paragraph is discarded and a `../` spelling normalises."""
|
||||
"""Check 4: the trailer paragraph is discarded and a `../` spelling normalizes."""
|
||||
problems = []
|
||||
entries = parse_h_output(PARSER_CANNED_GXX, REPO_ROOT)
|
||||
if len(entries) != 3:
|
||||
@@ -508,14 +508,14 @@ def self_test_parser():
|
||||
problems.append("depths misparsed: {}".format(depths))
|
||||
normalised = entries[-1][1] if entries else None
|
||||
if normalised != "MobileGL/MG_State/GLState/SamplerState/SamplerObject.h":
|
||||
problems.append("`../` spelling did not normalise: {}".format(normalised))
|
||||
problems.append("`../` spelling did not normalize: {}".format(normalised))
|
||||
elif not find_violations(entries, PROBES[0]["Forbidden"], []):
|
||||
problems.append("normalised path did not match the value-header forbidden list")
|
||||
problems.append("normalized path did not match the value-header forbidden list")
|
||||
if problems:
|
||||
for problem in problems:
|
||||
say(" self-test parser: " + problem)
|
||||
return False
|
||||
say(" self-test parser: trailer discarded, `../` normalised and matched")
|
||||
say(" self-test parser: trailer discarded, `../` normalized and matched")
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ exemptions; the first is gone from the tree, and the second is compiled into the
|
||||
embeds (the push monolith without MG_Remote), so it is shipped code and gets the same rule.
|
||||
The rule is now "no frontend-pointer KEY in any named memo family, in any build", and nothing
|
||||
else; the one allow-list entry below is a named, dated carve-out.
|
||||
It does not evaluate the preprocessor - it recognises the conditional spellings the
|
||||
It does not evaluate the preprocessor - it recognizes the conditional spellings the
|
||||
tree actually uses - and it does not look at DirectVulkan, whose own key inventory is
|
||||
P7 wave 2's.
|
||||
|
||||
@@ -107,7 +107,7 @@ def legacy_lines(code: str) -> set[int]:
|
||||
def _retired_legacy_lines(code: str) -> set[int]:
|
||||
"""The pre-W3b exemption, kept only for the self-test's record of what changed.
|
||||
|
||||
NOT a preprocessor. It recognises `#if MOBILEGL_PIPE_LEGACY_MEMOS`,
|
||||
NOT a preprocessor. It recognizes `#if MOBILEGL_PIPE_LEGACY_MEMOS`,
|
||||
`#if !MOBILEGL_BUILD_DISAGGREGATED`, and the `#else` of
|
||||
`#if MOBILEGL_BUILD_DISAGGREGATED` - which is every spelling these two files use -
|
||||
and treats every other conditional as transparent."""
|
||||
|
||||
@@ -41,7 +41,7 @@ and integration harnesses drive the library rather than being it.
|
||||
THE SITES OF THE WIDENED PERIMETER, TRIAGED. The widening found 83; the same package routed
|
||||
five of them through Session::Fail and added one funnel of its own, so the floor the baseline
|
||||
records is 79 over 20 files. The triage is the argument for why the gate can be green with
|
||||
seventy-nine deaths inside it. The ENFORCEABLE artefact is the baseline's per-file map - this
|
||||
seventy-nine deaths inside it. The ENFORCEABLE artifact is the baseline's per-file map - this
|
||||
prose is why that map reads the way it does.
|
||||
|
||||
(i) INSIDE A SANCTIONED FUNNEL - 5 sites, and the only ones allowed to carry no marker. The
|
||||
|
||||
@@ -73,7 +73,7 @@ def _list_property(test, name):
|
||||
|
||||
def tcp_lock_violations(document):
|
||||
"""Entries of a ctest --show-only=json-v1 document that reach the loopback TCP supervisor -
|
||||
FIXTURES_REQUIRED names mobilegl-tcp, or the entry is labelled exactly integration-tcp - and do
|
||||
FIXTURES_REQUIRED names mobilegl-tcp, or the entry is labeled exactly integration-tcp - and do
|
||||
not hold RESOURCE_LOCK mobilegl-tcp. Sorted names; empty when the registration is sound."""
|
||||
bad = []
|
||||
for test in document.get('tests', []):
|
||||
@@ -121,7 +121,7 @@ def require_entries_passed(path, names):
|
||||
|
||||
`TcpLane.SupervisorProtocolControls` is registered with SKIP_RETURN_CODE 77 because the
|
||||
script it runs needs flatc, which is deliberately not in the build graph. That is the right
|
||||
behaviour for a developer who has not built one; it is the wrong behaviour for CI, where the
|
||||
behavior for a developer who has not built one; it is the wrong behavior for CI, where the
|
||||
lane's whole job is to run the supervisor's protocol controls and "skipped" is
|
||||
indistinguishable from the three commits the entry did not exist. The workflow builds flatc
|
||||
and then names the entry here, so a CI run in which the tool went missing reds by name
|
||||
|
||||
@@ -53,7 +53,7 @@ FILES = {
|
||||
}
|
||||
|
||||
# (file, a substring of the site's line) -> why no peer byte reaches it. The site is converted
|
||||
# anyway - it is on the decode path and returns like its neighbours - and the reason names the
|
||||
# anyway - it is on the decode path and returns like its neighbors - and the reason names the
|
||||
# earlier check that refuses the same bytes first.
|
||||
UNREACHABLE = [
|
||||
("PipeWireCodec.cpp", '"segment-resolve"',
|
||||
|
||||
@@ -18,7 +18,7 @@ surface as a silently absent field - the exact failure the revision was added to
|
||||
|
||||
This script pins the two together. protocol_revision_pins.json beside it is a table
|
||||
{revision: sha256(protocol.fbs)} of the schema each revision was minted for. The check reads the
|
||||
header's current revision, hashes protocol.fbs (line endings normalised, so a CRLF checkout hashes
|
||||
header's current revision, hashes protocol.fbs (line endings normalized, so a CRLF checkout hashes
|
||||
the same bytes as an LF one) and refuses when the current revision has no row or its row is not
|
||||
the file's digest. Both directions are covered: a schema edit that forgot the bump is red (stale
|
||||
row), and a bump that forgot the table is red (no row), so the table cannot fall behind the header.
|
||||
|
||||
@@ -25,7 +25,7 @@ runs", not "runs inproc"), and that arm's scenario is monolith-only by construct
|
||||
have a spawn counterpart, so it is named as an exception rather than allowed to widen the
|
||||
tolerance for everything else.
|
||||
|
||||
P7 PACKAGE L ADDS THE SAME QUESTION FOR MAGMA, IN TWO TIERS, AND THE NORMALISATION IS
|
||||
P7 PACKAGE L ADDS THE SAME QUESTION FOR MAGMA, IN TWO TIERS, AND THE NORMALIZATION IS
|
||||
DIFFERENT ON PURPOSE. The Espryt half above strips the sub-lane tails `F1.` and `Ct.` because
|
||||
they name neither the case nor the arm. The Magma half must NOT: `RunAhead.Credit1.` and
|
||||
`RunAhead.Credit3.` are two entries of the same case, differing in the credit the lane pins, and
|
||||
|
||||
@@ -19,7 +19,7 @@ asked about - and nothing about a green split lane says so. This asserts, per ba
|
||||
after the arm and tail segments come off both sides: an entry name is `<Backend>.[<Arm>.][<tail>.]
|
||||
<Suite>.<Case>`, and only the last two segments (the gtest name) are compared. `Split.F1.`,
|
||||
`Spawn.ForcedDs.`, `Tcp.MultiDrawTierBaseVertex.` and the monolith's
|
||||
`ForcedDepthStencilEmulation.` all normalise away.
|
||||
`ForcedDepthStencilEmulation.` all normalize away.
|
||||
|
||||
WHAT COUNTS AS A SPLIT CASE differs by backend, on purpose:
|
||||
* DirectGLES - an entry with an arm segment (Split/Spawn/Tcp/TcpDevice) that carries a GATED
|
||||
@@ -33,7 +33,7 @@ WHAT COUNTS AS A SPLIT CASE differs by backend, on purpose:
|
||||
|
||||
WHAT COUNTS AS A MONOLITH CASE: an entry with no arm segment carrying `integration-gpu` - the label
|
||||
the monolith registrations and the monolith-control mechanism entries share. That puts
|
||||
`DirectGLES.PushMonolithArm.<case>` (labelled integration-split, but no arm) on the monolith side,
|
||||
`DirectGLES.PushMonolithArm.<case>` (labeled integration-split, but no arm) on the monolith side,
|
||||
where it belongs, and leaves build-verify's `DirectGLES.VerifySplit.<case>` (no integration-gpu)
|
||||
out of both sides.
|
||||
|
||||
@@ -254,7 +254,7 @@ def self_test():
|
||||
if got != rc or any(n not in text for n in needles) or any(n in text for n in absent):
|
||||
failures.append(f"{label}: rc {got} (want {rc}); output:\n{text}")
|
||||
|
||||
expect("tails normalise on both sides", _doc(*BASE), "", 0,
|
||||
expect("tails normalize on both sides", _doc(*BASE), "", 0,
|
||||
"DirectGLES: monolith 3, on a gated split arm 3", "missing 0")
|
||||
expect("a monolith case on no arm reds BY NAME",
|
||||
_doc(*BASE, _entry("DirectGLES.CScenario.Five", "integration-gpu")), "", 1,
|
||||
|
||||
@@ -189,7 +189,7 @@ class Accounting(unittest.TestCase):
|
||||
`ctest -L integration-gpu -j 4` that entry and another Tcp case killed each other.
|
||||
The stub mirrors the real json-v1 shapes: the fixture's own setup entry, a sound Tcp
|
||||
case, the violator as it was registered, a Magma tcp entry that reaches the fixture
|
||||
under another label, a labelled control with no fixture, and the device lane, whose
|
||||
under another label, a labeled control with no fixture, and the device lane, whose
|
||||
lock is its own."""
|
||||
tally = module('junit_tally')
|
||||
parity = module('spawn_lane_parity')
|
||||
|
||||
+19
-19
@@ -10,7 +10,7 @@
|
||||
|
||||
Reads the four hand-maintained sources of truth
|
||||
|
||||
MobileGL/MG_Pipe/PipeCalls.def the call catalogue
|
||||
MobileGL/MG_Pipe/PipeCalls.def the call catalog
|
||||
MobileGL/MG_Pipe/PipeFields.def per-payload field lists for the verify comparator
|
||||
MobileGL/MG_Pipe/Coverage.def accessor -> call mapping for the read inventory,
|
||||
and the sticky-field list
|
||||
@@ -23,13 +23,13 @@ plus the vendored copy of the backend read inventory
|
||||
|
||||
and writes MobileGL/MG_Pipe/generated/*.inc. The outputs are COMMITTED; CI regenerates
|
||||
them and fails on a diff, which is what keeps the seven generators from drifting apart
|
||||
from the catalogue (they all consume the same .def).
|
||||
from the catalog (they all consume the same .def).
|
||||
|
||||
python3 scripts/gen_pipe.py # write the generated files, print the summary
|
||||
python3 scripts/gen_pipe.py --check # fail if regenerating would change anything
|
||||
python3 scripts/gen_pipe.py --self-test # the negative controls: each gate below must trip
|
||||
|
||||
Both modes refuse a catalogue whose call payload has no field list in PipeFields.def: a
|
||||
Both modes refuse a catalog whose call payload has no field list in PipeFields.def: a
|
||||
payload the G4 comparator cannot see is a payload MOBILEGL_PIPE_VERIFY is blind to. Both
|
||||
also refuse a field list that does not name every data member of its struct (or names one
|
||||
that is not a member), and a backend accessor read through gPipeInputs-> / pGLContext-> that
|
||||
@@ -573,7 +573,7 @@ def parse_wait_classes():
|
||||
this list is what the generated kMGPipeWaitClasses[] table spells into C++, and a copy
|
||||
here would go stale in exactly the case that matters. kWaitClassCount is the terminator and
|
||||
is NOT a class a row may carry - a row that named it would generate a table entry the
|
||||
lookup uses to mean 'this opcode never came from the catalogue'."""
|
||||
lookup uses to mean 'this opcode never came from the catalog'."""
|
||||
text = read(os.path.join(PIPE_DIR, "MGPipe.h"))
|
||||
body = WAIT_ENUM_RE.search(text)
|
||||
if not body:
|
||||
@@ -597,7 +597,7 @@ def check_wait_classes_are_known(calls):
|
||||
compile error in one consumer.
|
||||
|
||||
1. The token must be an MGPipeWaitClass enumerator, and never the kWaitClassCount
|
||||
terminator, which the generated lookup uses for "not from this catalogue".
|
||||
terminator, which the generated lookup uses for "not from this catalog".
|
||||
2. kReplySlot and kWaitReply must agree, BOTH WAYS. A reply-slot row that did not wait
|
||||
would be a waiter that hangs - the client would run on and read a slot nobody had
|
||||
posted into yet; a waiting row with no slot would block on an answer nobody posts.
|
||||
@@ -690,7 +690,7 @@ def banner(name, title, sources):
|
||||
|
||||
def gen_wire_layout(calls, payloads):
|
||||
"""Compiler-evaluated wire layout, including same-width member reorders."""
|
||||
out = [banner("PipeWireLayout.inc", "P6.5: wire layout and ordered catalogue.",
|
||||
out = [banner("PipeWireLayout.inc", "P6.5: wire layout and ordered catalog.",
|
||||
"PipeFields.def and PipeCalls.def")]
|
||||
out += ["struct WireLayoutMember { const char* Name; Uint64 Offset; Uint64 Size; };",
|
||||
"inline constexpr WireLayoutMember kMGPipeWireLayoutMembers[] = {"]
|
||||
@@ -735,12 +735,12 @@ def gen_tables(calls):
|
||||
out.append("// A table that is not exactly its call count of function pointers has grown a")
|
||||
out.append("// member that no generator knows about.")
|
||||
out.append("static_assert(sizeof(MGPipeScreen) == kMGPipeScreenCallCount * sizeof(void (*)()),")
|
||||
out.append(" \"MGPipeScreen is not exactly its catalogue's function pointers\");")
|
||||
out.append(" \"MGPipeScreen is not exactly its catalog's function pointers\");")
|
||||
out.append("static_assert(sizeof(MGPipeContext) == kMGPipeContextCallCount * sizeof(void (*)()),")
|
||||
out.append(" \"MGPipeContext is not exactly its catalogue's function pointers\");")
|
||||
out.append(" \"MGPipeContext is not exactly its catalog's function pointers\");")
|
||||
out.append("static_assert(kMGPipeScreenCallCount + kMGPipeContextCallCount == kMGPipeCallCount);")
|
||||
out.append("static_assert(kMGPipeCallCount == MGP_CALL_LIST_DOCUMENTED_COUNT,")
|
||||
out.append(" \"the catalogue and its documented count disagree\");")
|
||||
out.append(" \"the catalog and its documented count disagree\");")
|
||||
return "\n".join(out) + "\n"
|
||||
|
||||
|
||||
@@ -833,8 +833,8 @@ enum class MGPWireOp : Uint16 {
|
||||
// GetCaps and CreateSamplerState came to carry an MGPBlobRef member with no kHasBlob on
|
||||
// their line at all - nothing compared the two, because nothing had both in one place.
|
||||
//
|
||||
// Index 0 is MGPWireOp::kInvalid and is kNone: the catalogue is 1-based, and an encoder
|
||||
// that reads flags for an opcode it never got from the catalogue must see the empty set
|
||||
// Index 0 is MGPWireOp::kInvalid and is kNone: the catalog is 1-based, and an encoder
|
||||
// that reads flags for an opcode it never got from the catalog must see the empty set
|
||||
// rather than another call's flags.
|
||||
//
|
||||
// kHasBlob here means EXACTLY "the payload owns an MGPBlobRef member". Three calls carry
|
||||
@@ -853,7 +853,7 @@ enum class MGPWireOp : Uint16 {
|
||||
out.append(" \"the flags table and the opcode space disagree\");")
|
||||
out.append("""
|
||||
// The only supported read of the table. Out-of-range is kNone rather than undefined
|
||||
// behaviour, because the one caller that can pass a bad opcode is a decoder holding bytes
|
||||
// behavior, because the one caller that can pass a bad opcode is a decoder holding bytes
|
||||
// off a stream, and it must reach its own Fatal{ProtocolCorruption} rather than read past
|
||||
// the array on the way there.
|
||||
inline constexpr Uint32 MGPipeCallFlagsFor(MGPWireOp op) {
|
||||
@@ -862,7 +862,7 @@ inline constexpr Uint32 MGPipeCallFlagsFor(MGPWireOp op) {
|
||||
: static_cast<Uint32>(kNone);
|
||||
}
|
||||
|
||||
// The catalogue class of every opcode, indexed the same way; index 0 is kCallClassCount,
|
||||
// The catalog class of every opcode, indexed the same way; index 0 is kCallClassCount,
|
||||
// never a real class, for the flags table's reason.
|
||||
inline constexpr Uint8 kMGPipeCallClasses[static_cast<SizeT>(MGPWireOp::kOpCount)] = {
|
||||
/* 0 */ static_cast<Uint8>(kCallClassCount),
|
||||
@@ -883,7 +883,7 @@ inline constexpr MGPipeCallClass MGPipeCallClassFor(MGPWireOp op) {
|
||||
|
||||
// P5e (2.2): THE WAIT CLASS OF EVERY OPCODE, indexed the same way.
|
||||
// Index 0 is kWaitClassCount - never a real class - for the flags table's reason: the one
|
||||
// caller that can pass an opcode this catalogue never produced is a decoder holding bytes off
|
||||
// caller that can pass an opcode this catalog never produced is a decoder holding bytes off
|
||||
// a stream, and it must reach its own Fatal{ProtocolCorruption} rather than a wait decision.
|
||||
//
|
||||
// This is the STATIC HALF of MGPipeBarriered(op, payload, applierState), the predicate the emit
|
||||
@@ -908,7 +908,7 @@ inline constexpr MGPipeWaitClass MGPipeWaitClassFor(MGPWireOp op) {
|
||||
}
|
||||
|
||||
// THE COLUMN'S OWN INVARIANT, stated in C++ as well as in the generator: a reply-slot row
|
||||
// waits for its reply and a waiting row owns a slot. gen_pipe.py refuses a catalogue where the
|
||||
// waits for its reply and a waiting row owns a slot. gen_pipe.py refuses a catalog where the
|
||||
// two disagree, and this is the same statement where a reader of the generated table will look
|
||||
// for it - a kReplySlot row that did not wait would run on and read a slot nobody had posted
|
||||
// into, and a kWaitReply row with no slot would block on an answer nobody posts.
|
||||
@@ -923,7 +923,7 @@ static_assert(MGPipeWaitClassFor(MGPWireOp::ApplierReset) == kWaitApplied,
|
||||
static_assert(MGPipeWaitClassFor(MGPWireOp::ReadPixels) == kWaitReply,
|
||||
"a readback's answer is not derivable (R-5)");
|
||||
|
||||
// Spot checks the generator states about its own output, so that a catalogue edit that
|
||||
// Spot checks the generator states about its own output, so that a catalog edit that
|
||||
// silently drops a flag is a build break here and not a wrong decode six packages away.
|
||||
static_assert(MGPipeCallFlagsFor(MGPWireOp::kInvalid) == static_cast<Uint32>(kNone),
|
||||
"opcode 0 is not a call and carries no flags");
|
||||
@@ -1011,9 +1011,9 @@ inline MGPipeWireRecordApplyFn gMGPipeWireRecordApply = nullptr;
|
||||
// record's own count fields and require it to EQUAL MGPWireRecHeader::Size - belongs to the
|
||||
// decoder, which has the payload (MG_Remote/Wire's MGPipeWireRecordLayout, P5 w1).
|
||||
//
|
||||
// The switch and the opcode enum come from the same list, so a call added to the catalogue
|
||||
// The switch and the opcode enum come from the same list, so a call added to the catalog
|
||||
// cannot be forgotten here; the default arm is for the opcode that never came from this
|
||||
// catalogue at all - a byte off a corrupt stream - and it is fatal for the same reason the
|
||||
// catalog at all - a byte off a corrupt stream - and it is fatal for the same reason the
|
||||
// bounds check is.
|
||||
//
|
||||
// With no decoder installed - every monolith build, and a split build before
|
||||
@@ -1661,7 +1661,7 @@ def self_test(accessors):
|
||||
# The positive control: the canned struct's exact list passes, and the parser sees the
|
||||
# padding member as padding and the function as not a member.
|
||||
check_field_lists_cover_struct_members({"Canned": ["A", "B", "C"]}, ["Canned"], [canned_struct])
|
||||
# ... and the real catalogue's real flags and wait classes pass the same gates.
|
||||
# ... and the real catalog's real flags and wait classes pass the same gates.
|
||||
check_call_flags_are_known(calls_for_control)
|
||||
check_wait_classes_are_known(calls_for_control)
|
||||
if trips == 0:
|
||||
|
||||
@@ -343,7 +343,7 @@ def render_state_publishers():
|
||||
# not read. What it models is written down here, and what it does not model taints the
|
||||
# function it is in, which turns every answer depending on that function into UNDECIDED:
|
||||
#
|
||||
# modelled ++m_x / m_x = / m_x op= (a whole-member write: MEM:m_x, FIELD:m_x.*); a write
|
||||
# modeled ++m_x / m_x = / m_x op= (a whole-member write: MEM:m_x, FIELD:m_x.*); a write
|
||||
# through a member-rooted lvalue (m_x.f, m_x[i].f, m_x->f, nested), which records
|
||||
# MEM:m_x and FIELD:m_x.f - the first field below the member, deeper paths
|
||||
# collapse to it, because that is the granularity the shutter reads at; a
|
||||
@@ -356,7 +356,7 @@ def render_state_publishers():
|
||||
# memcpy/memset/memmove/swap whose destination is one, all credited as a whole
|
||||
# write of that lvalue - a read-only call is over-credited, which only WIDENS the
|
||||
# writer side; a write to a value local, a by-value parameter or an aggregate
|
||||
# initialiser's `.f = v`, which touch no member; a write through a const alias
|
||||
# initializer's `.f = v`, which touch no member; a write through a const alias
|
||||
# with `.` or through a const raw pointer, which the language forbids - but `->`
|
||||
# through a const REFERENCE may be a smart pointer's and is NOT taken as
|
||||
# read-only; MGP_NOTE_AGGREGATE; a call to any function whose body is under the
|
||||
@@ -417,7 +417,7 @@ AGGREGATE_CASE_RE = re.compile(r"case\s+MGPipeAggregate::(\w+)\s*:\s*([^;]*);")
|
||||
# is then `!`, `<` or `>` and no alternative here begins with one except <<= / >>=.
|
||||
ASSIGN = r"(?:\+\+|--|\+=|-=|\*=|/=|%=|&=|\|=|\^=|<<=|>>=|=(?!=))"
|
||||
# A write to the member itself: ++m_x, m_x = v, m_x += v. Used by the OUTSIDE scan only; the
|
||||
# analysed bodies go through extract_writes below.
|
||||
# analyzed bodies go through extract_writes below.
|
||||
MEMBER_WRITE_RE = re.compile(r"\+\+\s*(m_\w+)|\b(m_\w+)\s*%s" % ASSIGN)
|
||||
# A write THROUGH a member: m_x.f = v, m_x[i].f = v, m_x->f = v, and nested. Outside scan only.
|
||||
MEMBER_ROOTED_WRITE_RE = re.compile(
|
||||
@@ -451,8 +451,8 @@ READ_ONLY_METHODS = frozenset(("size", "empty", "begin", "end", "cbegin", "cend"
|
||||
# memcpy(&dst, ...), memset(&dst, ...), memmove(&dst, ...), swap(a, b): whole writes.
|
||||
BULK_RE = re.compile(r"\b(?:std\s*::\s*)?(memcpy|memmove|memset|swap)\s*\(")
|
||||
# A local declaration: [qualifiers] Type[<...>][::More] [const] [& | && | *] name, then the
|
||||
# initialiser's opener. A `&`/`*` mark (or an initialiser that takes an address) makes the
|
||||
# local an ALIAS whose initialiser must resolve to a member-rooted lvalue; anything else is
|
||||
# initializer's opener. A `&`/`*` mark (or an initializer that takes an address) makes the
|
||||
# local an ALIAS whose initializer must resolve to a member-rooted lvalue; anything else is
|
||||
# a value local, which cannot alias a member - unless the body later writes through it with
|
||||
# `->` or `*`, in which case it is a pointer or an iterator and is treated as an alias. A
|
||||
# pointer alias is REBOUND by `p = expr;` (every binding counts); a reference alias is
|
||||
@@ -494,7 +494,7 @@ ASSIGN_OP_RE = re.compile(r"(\+\+|--|<<=|>>=|[-+*/%&|^]=|(?<![=!<>\[\-+*/%&|^])=
|
||||
# answered.
|
||||
MACRO_DIRECTIVE_RE = re.compile(
|
||||
r"^[ \t]*#[ \t]*(define|undef)[ \t]+(\w+)(\([^()\n]*\))?((?:\\\n|[^\n])*)", re.M)
|
||||
# MGP_NOTE_AGGREGATE is modelled directly (its hop is read out of MGPipeNoteAggregate's own
|
||||
# MGP_NOTE_AGGREGATE is modeled directly (its hop is read out of MGPipeNoteAggregate's own
|
||||
# switch), so expanding it would delete the very token AGGREGATE_RE looks for.
|
||||
NEVER_EXPAND = frozenset(("MGP_NOTE_AGGREGATE", "MGP_NOTE_MUTATION"))
|
||||
MACRO_BODY_LIMIT = 4000
|
||||
@@ -856,7 +856,7 @@ def extract_writes(body, params_text, site):
|
||||
% (site, what, root))
|
||||
|
||||
def designated(text, root_at):
|
||||
"""`{.f = v, .g = w}`: an aggregate initialiser, not a write to a field named f."""
|
||||
"""`{.f = v, .g = w}`: an aggregate initializer, not a write to a field named f."""
|
||||
before = text[:root_at].rstrip()
|
||||
if not before.endswith("."):
|
||||
return False
|
||||
@@ -934,7 +934,7 @@ def extract_writes(body, params_text, site):
|
||||
|
||||
def state_bodies():
|
||||
"""({function name: [body text]}, {function name: [parameter text]},
|
||||
{function name: {taint reason}}, [analysed paths]) over MG_State/GLState and
|
||||
{function name: {taint reason}}, [analyzed paths]) over MG_State/GLState and
|
||||
MG_Impl/Pipe, macros expanded first."""
|
||||
paths = []
|
||||
for root in STATE_ROOTS:
|
||||
@@ -962,15 +962,15 @@ def state_bodies():
|
||||
|
||||
|
||||
def writers_outside(analysed):
|
||||
"""{MEM token: a file OUTSIDE the analysed roots that writes it}.
|
||||
"""{MEM token: a file OUTSIDE the analyzed roots that writes it}.
|
||||
|
||||
The absence claim is only as good as the set of writers the analysis reads. Every .h/.cpp
|
||||
under MobileGL/ that is not one of the analysed files is scanned with the direct write
|
||||
under MobileGL/ that is not one of the analyzed files is scanned with the direct write
|
||||
patterns, and a shutter member that turns up here is undecided rather than answered.
|
||||
|
||||
A file that DECLARES a member of that name is writing its own, not the frontend's - the
|
||||
backend's PipeInputs mirrors half of GLState's member names - so its writes do not count.
|
||||
That is the one judgement here, and it is the conservative way round only for names the
|
||||
That is the one judgment here, and it is the conservative way round only for names the
|
||||
two sides share; a genuine outside writer of a frontend member does not declare it.
|
||||
|
||||
This scan is textual and file-wide: it sees a direct member write and a member-rooted
|
||||
@@ -1375,7 +1375,7 @@ def derive_bit_answers(mapping, bits, movers, moved, outside=None):
|
||||
unread = sorted(set(outside[token] for token in shutter if token in outside))
|
||||
if unread:
|
||||
out[(mutator, bit)] = (UNDECIDED, "that shutter's members are written outside "
|
||||
"the analysed roots too, e.g. %s, so 'it writes "
|
||||
"the analyzed roots too, e.g. %s, so 'it writes "
|
||||
"nothing that shutter reads' is not a fact this "
|
||||
"script has" % unread[0])
|
||||
continue
|
||||
@@ -1702,8 +1702,8 @@ def self_test(scanned, bits, publishers, movers, moved, outside=None, undecided_
|
||||
hidden[token] = "MobileGL/MG_Backend/a-file-this-analysis-never-reads.cpp"
|
||||
verdicts = derive_bit_answers(with_wrong_bit, bits, movers, moved, hidden)
|
||||
verdict, detail = verdicts.get(("SetCurrentVertexAttributeInt", "NEW_PIXEL_PACK"), ("", ""))
|
||||
tripped(verdict == UNDECIDED and "outside the analysed roots" in detail,
|
||||
"10 (a shutter member written outside the analysed roots)")
|
||||
tripped(verdict == UNDECIDED and "outside the analyzed roots" in detail,
|
||||
"10 (a shutter member written outside the analyzed roots)")
|
||||
|
||||
# 11-14. THE WRITE ANALYSIS ITSELF, on synthetic bodies through the real extractor. The
|
||||
# review's false verdict was "SetBlendEquation writes nothing NEW_PATCH_STATE's
|
||||
|
||||
@@ -197,7 +197,7 @@ def parse_ownership(text=None):
|
||||
|
||||
def parse_ops_and_verbs(calls_text=None, fill_points_text=None):
|
||||
"""The two name spaces the stamp map joins, read from the files that define them: the
|
||||
catalogue's calls (PipeCalls.def, which IS the MGPWireOp enum, with each call's KIND) and
|
||||
catalog's calls (PipeCalls.def, which IS the MGPWireOp enum, with each call's KIND) and
|
||||
the verb set (FillPoints.def, which IS MG_Backend::GLFunctionsTable's member list)."""
|
||||
calls_text = read(PIPE_CALLS) if calls_text is None else calls_text
|
||||
fill_points_text = read(FILL_POINTS) if fill_points_text is None else fill_points_text
|
||||
@@ -213,7 +213,7 @@ def parse_ops_and_verbs(calls_text=None, fill_points_text=None):
|
||||
|
||||
|
||||
def array_block(text, declaration):
|
||||
"""The braced initialiser of a generated `... <declaration> = {` table, comments KEPT.
|
||||
"""The braced initializer of a generated `... <declaration> = {` table, comments KEPT.
|
||||
|
||||
The generated tables carry the row's name in a trailing comment (`// DrawArrays`) and in a
|
||||
leading one (`/* 58 ReadPixels */`), and those comments are the only place the row's NAME
|
||||
@@ -236,7 +236,7 @@ def array_block(text, declaration):
|
||||
if depth == 0:
|
||||
return text[open_at + 1:i]
|
||||
i += 1
|
||||
sys.exit("gen_pipe_field_ownership: %r never closes its initialiser" % declaration)
|
||||
sys.exit("gen_pipe_field_ownership: %r never closes its initializer" % declaration)
|
||||
|
||||
|
||||
WAIT_ROW_RE = re.compile(r"/\*\s*\d+\s+(\w+)\s*\*/\s*static_cast<Uint8>\(\s*(k\w+)\s*\)")
|
||||
@@ -386,7 +386,7 @@ def build_admitted(accessors, ownership, phase, verbs, verb_ops, waits, verb_cla
|
||||
|
||||
def verb_shaped_calls(calls, verbs):
|
||||
"""The calls that MUST have a stamp row or an exemption, by two derived tests: the
|
||||
catalogue's own kind (kCtxVerb) and a name that is also a verb's. Neither can see a call
|
||||
catalog's own kind (kCtxVerb) and a name that is also a verb's. Neither can see a call
|
||||
that is a verb boundary, is not kCtxVerb and is renamed - FieldOwnership.def names the one
|
||||
such call in the tree and says the phase that emits it writes its row."""
|
||||
verbSet = set(verbs)
|
||||
@@ -946,7 +946,7 @@ def self_test():
|
||||
# alone and control 12 would pass for the wrong reason. Renaming the kind is the cheapest
|
||||
# way to prove the kind is actually being read.
|
||||
kindless = read(PIPE_CALLS).replace("kCtxVerb", "kCtxVerbb")
|
||||
controls.append(("the catalogue's kCtxVerb kind renamed away",
|
||||
controls.append(("the catalog's kCtxVerb kind renamed away",
|
||||
"is exempted from the stamp map but is not verb-shaped",
|
||||
lambda: run(calls_text=kindless)))
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
# End of Source File Header
|
||||
|
||||
# G5's gate: "pool 与延迟释放原样搬" is LITERAL - ELEVEN functions in
|
||||
# G5's gate: "the pool and the deferred release are moved as they are" is LITERAL - ELEVEN functions in
|
||||
# MobileGL/MG_Backend/DirectGLES/Managers.cpp are byte-identical after P3a.
|
||||
#
|
||||
# WHAT G5 CLAIMS, and why a diff of the file cannot say it. ARCHITECTURE.md §9.1 puts the three
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
# four static_asserts in MGPipeValueTypes.h's trip-wire block still hold, the field list in
|
||||
# PipeFields.def still names it and the generated comparator still compares it. What breaks is the
|
||||
# VALUE - the wire record now says "not BGRA" for a GL_BGRA attribute, which is the shape that made
|
||||
# a swizzled colour array read back with its channels in driver order. It is also the field with
|
||||
# a swizzled color array read back with its channels in driver order. It is also the field with
|
||||
# the least other coverage: `Size` keeps 4 for GL_BGRA (D-G2), so a dropped IsBgra does not even
|
||||
# change the attribute's size.
|
||||
#
|
||||
@@ -265,7 +265,7 @@ fi
|
||||
case "$VERDICT" in
|
||||
did-not-trip)
|
||||
say "NEGATIVE CONTROL DID NOT TRIP: $TEST_NAME was still green with ${FIELD} no longer copied"
|
||||
say "into MGPVertexAttribWire. A GL_BGRA attribute travelled as a non-BGRA one and the emission"
|
||||
say "into MGPVertexAttribWire. A GL_BGRA attribute traveled as a non-BGRA one and the emission"
|
||||
say "comparison did not notice, so G6 is not checking what it claims to check."
|
||||
say "The failing run's output is kept at $LOG_DIR/ctest-after.log"
|
||||
exit 1
|
||||
|
||||
@@ -40,11 +40,11 @@
|
||||
# rather than in the code because excluding the hash copy would mean hard-coding another
|
||||
# package's helper name into a regex that deliberately does not know one.
|
||||
# 2. SamplerParameters::borderColorForm stops being copied in MG_Impl/Pipe/SamplerEmit.h. All
|
||||
# four border-colour VALUES still cross; what is lost is which of the three forms
|
||||
# four border-color VALUES still cross; what is lost is which of the three forms
|
||||
# (float / int / uint) they are to be read as, and D-F4 is explicit that the form crosses and
|
||||
# that all four values are compared. The failure it models is IntegerBorderColorScenario's:
|
||||
# an integer border colour read as floats is not an error anywhere, it is just the wrong
|
||||
# colour at the clamped edge of every sampled texture.
|
||||
# an integer border color read as floats is not an error anywhere, it is just the wrong
|
||||
# color at the clamped edge of every sampled texture.
|
||||
#
|
||||
# Each patch is applied by REGEX rather than by an exact line, because both headers belong to OTHER
|
||||
# PACKAGES (C.7: FramebufferEmit.h is package B's, SamplerEmit.h is package C's) and their spelling
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
# StageBlocksIntoUnpackRing Managers.cpp: the unpack-PBO staging repack. It is what makes the
|
||||
# ring path issue NO glPixelStorei, and the +6 ms/frame Mali cliff
|
||||
# lives on the other side of it
|
||||
# UnpackRingAvailable Managers.cpp: honours Features.EsprytDisableUnpackRing and
|
||||
# UnpackRingAvailable Managers.cpp: honors Features.EsprytDisableUnpackRing and
|
||||
# self-heals a stale context generation
|
||||
# UnpackRingAllocate Managers.cpp: on the hot upload route
|
||||
# RecomputeBackendColorSlots Managers.cpp: the attachment permutation - three passes plus the
|
||||
@@ -503,7 +503,7 @@ write_spec() {
|
||||
done
|
||||
}
|
||||
|
||||
# Materialise every region source at a git ref into "$2".
|
||||
# Materialize every region source at a git ref into "$2".
|
||||
checkout_ref() {
|
||||
local ref=$1 dir=$2 source
|
||||
mkdir -p "$dir" || return 2
|
||||
|
||||
@@ -12,7 +12,7 @@ P0.5's acceptance gate says every `nm --defined-only -S` delta has to be explain
|
||||
symbol. The awkward part is that de-nesting a type renames every mangled
|
||||
name that mentions it - `ProgramObject::LinkArtifacts` -> `LinkArtifacts` shows up inside
|
||||
every `std::vector<...>` instantiation too - so a raw nm diff of a pure move looks
|
||||
catastrophic. `--strip-scope` folds those into a "renamed-only" bucket: same normalised
|
||||
catastrophic. `--strip-scope` folds those into a "renamed-only" bucket: same normalized
|
||||
demangled name, byte-identical size. What is left over is the report's real content.
|
||||
|
||||
python3 scripts/symbol_report.py --before old.so --after new.so
|
||||
@@ -195,7 +195,7 @@ def bucket(before, after, only_names, threshold):
|
||||
"before": b["size"], "after": a["size"]})
|
||||
continue
|
||||
if a["mangled"] != b["mangled"]:
|
||||
# same normalised name, byte-identical size: the pure-move signature
|
||||
# same normalized name, byte-identical size: the pure-move signature
|
||||
if wanted(name):
|
||||
renamed.append({"name": name, "delta": 0,
|
||||
"before": b["mangled"][0], "after": a["mangled"][0]})
|
||||
@@ -302,7 +302,7 @@ def self_test():
|
||||
if [(r["name"], r["delta"]) for r in resized] != [("MobileGL::Grew()", 0x10)]:
|
||||
problems.append("resized bucket: {}".format([(r["name"], r["delta"]) for r in resized]))
|
||||
# `ProgramObject::LinkArtifacts::Reset` -> `LinkArtifacts::Reset` folds to the same
|
||||
# normalised name at the same size: renamed-only, not added+removed.
|
||||
# normalized name at the same size: renamed-only, not added+removed.
|
||||
if [r["name"] for r in renamed] != ["MobileGL::MG_State::GLState::LinkArtifacts::Reset()"]:
|
||||
problems.append("renamed bucket: {}".format([r["name"] for r in renamed]))
|
||||
if unchanged != 2: # ProgramObject::Link() and NoSize()
|
||||
@@ -432,8 +432,8 @@ def main():
|
||||
say("{} -> {} defined symbols: {} added, {} removed, {} resized, {} renamed".format(
|
||||
before_count, after_count, len(added), len(removed), len(resized), len(renamed)))
|
||||
# The two counts differ by the folding: several mangled symbols can share one
|
||||
# normalised demangled name (local aliases, `.cold` parts, identical-COMDAT clones).
|
||||
say("{} -> {} normalised names, {} unchanged (name, size and mangling all identical)".format(
|
||||
# normalized demangled name (local aliases, `.cold` parts, identical-COMDAT clones).
|
||||
say("{} -> {} normalized names, {} unchanged (name, size and mangling all identical)".format(
|
||||
len(before), len(after), unchanged))
|
||||
if only_names:
|
||||
say("listing restricted to names containing: " + ", ".join(only_names))
|
||||
@@ -468,7 +468,7 @@ def main():
|
||||
["symbol", "before", "after", "delta"])
|
||||
lines += markdown_table("Renamed only (same size)",
|
||||
[(r["name"], r["before"], r["after"]) for r in renamed],
|
||||
["normalised symbol", "before mangling", "after mangling"])
|
||||
["normalized symbol", "before mangling", "after mangling"])
|
||||
report = "\n".join(lines) + "\n"
|
||||
|
||||
if args.markdown:
|
||||
|
||||
Reference in New Issue
Block a user