jsilnet 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +25 -6
  2. package/REFERENCE.md +4 -0
  3. package/dist/browser/index.js +345 -0
  4. package/dist/browser/worker.js +42480 -0
  5. package/package.json +23 -4
  6. package/src/assembly/instruction-editing.js +165 -0
  7. package/src/assembly/method-removal.js +789 -0
  8. package/src/assembly/pointer-table-editing.js +506 -0
  9. package/src/assembly/portable-pdb-editing.js +441 -0
  10. package/src/browser/index.d.ts +123 -0
  11. package/src/browser/index.js +373 -0
  12. package/src/browser/worker-runtime.js +287 -0
  13. package/src/browser/worker.js +47 -0
  14. package/src/index.d.ts +267 -0
  15. package/src/index.js +107 -1574
  16. package/src/metadata/portable-pdb.js +2 -2
  17. package/src/metadata/strong-name.js +84 -83
  18. package/src/pe/headers.js +1 -1
  19. package/src/platform/bytes.js +21 -0
  20. package/src/platform/compression.js +24 -0
  21. package/src/platform/crypto.js +17 -0
  22. package/src/types/assembly/instruction-editing.d.ts +33 -0
  23. package/src/types/assembly/method-removal.d.ts +3 -0
  24. package/src/types/assembly/pointer-table-editing.d.ts +3 -0
  25. package/src/types/assembly/portable-pdb-editing.d.ts +23 -0
  26. package/src/types/binary/errors.d.ts +7 -0
  27. package/src/types/binary/reader.d.ts +30 -0
  28. package/src/types/il/body.d.ts +51 -0
  29. package/src/types/il/instructions.d.ts +33 -0
  30. package/src/types/il/opcodes.d.ts +2 -0
  31. package/src/types/il/rewrite.d.ts +38 -0
  32. package/src/types/index.d.ts +864 -0
  33. package/src/types/metadata/classic-pdb.d.ts +688 -0
  34. package/src/types/metadata/custom-attributes.d.ts +28 -0
  35. package/src/types/metadata/portable-pdb.d.ts +296 -0
  36. package/src/types/metadata/resources.d.ts +1 -0
  37. package/src/types/metadata/root-writer.d.ts +1 -0
  38. package/src/types/metadata/signatures.d.ts +5 -0
  39. package/src/types/metadata/streams.d.ts +26 -0
  40. package/src/types/metadata/strong-name.d.ts +11 -0
  41. package/src/types/metadata/tables.d.ts +25 -0
  42. package/src/types/metadata/writer.d.ts +16 -0
  43. package/src/types/pe/headers.d.ts +160 -0
  44. package/src/types/platform/bytes.d.ts +3 -0
  45. package/src/types/platform/compression.d.ts +2 -0
  46. package/src/types/platform/crypto.d.ts +4 -0
  47. package/src/types/resolution/module.d.ts +12 -0
  48. package/src/types/writer/patch.d.ts +4 -0
  49. package/src/types/writer/pe.d.ts +9 -0
  50. package/src/types/writer/structural.d.ts +4 -0
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { createHash } from "node:crypto";
1
+ import { createHash } from "./platform/crypto.js";
2
+ import { equalBytes } from "./platform/bytes.js";
2
3
  import { FormatError, UnsupportedFormatError } from "./binary/errors.js";
3
4
  import {
4
5
  parseEmbeddedPortablePdbData,
@@ -31,17 +32,14 @@ import {
31
32
  } from "./metadata/classic-pdb.js";
32
33
  import { parseMethodBody } from "./il/body.js";
33
34
  import { encodeInstruction, encodeOpcode, formatInstruction, getInstructionSize } from "./il/instructions.js";
34
- import { listOpcodes } from "./il/opcodes.js";
35
- import {
36
- createStructuralState,
37
- insertInstruction as insertStructuralInstruction,
38
- layoutStructuralState,
39
- removeInstruction as removeStructuralInstruction,
40
- updateStructuralOperand
41
- } from "./il/rewrite.js";
35
+ import { createStructuralState } from "./il/rewrite.js";
42
36
  import { resolveMethodParameters, resolveTypes } from "./resolution/module.js";
43
37
  import { applyPatches, createOperandPatches } from "./writer/patch.js";
44
38
  import { serializeStructural } from "./writer/structural.js";
39
+ import { createInstructionEditor } from "./assembly/instruction-editing.js";
40
+ import { createPointerTableEditor } from "./assembly/pointer-table-editing.js";
41
+ import { createPortablePdbEditor } from "./assembly/portable-pdb-editing.js";
42
+ import { createMethodRemovalEditor } from "./assembly/method-removal.js";
45
43
  import { appendBlobHeap, appendStringHeap, appendUserStringHeap } from "./metadata/writer.js";
46
44
  import { parseManifestResources } from "./metadata/resources.js";
47
45
  import {
@@ -53,28 +51,7 @@ import {
53
51
  remapEmbeddedPortablePdbTypeDefinitions as remapPortablePdbTypeDefinitions,
54
52
  removeEmbeddedPortablePdbMethod as removePortablePdbMethod,
55
53
  refreshEmbeddedPortablePdbId,
56
- addEmbeddedPortablePdbSourceLink as addPortablePdbSourceLink,
57
- addEmbeddedPortablePdbSource as addPortablePdbSource,
58
- removeEmbeddedPortablePdbSourceLink as removePortablePdbSourceLink,
59
- removeEmbeddedPortablePdbSource as removePortablePdbSource,
60
- removeEmbeddedPortablePdbCustomDebugInformation as removePortablePdbCustomDebugInformation,
61
- replaceEmbeddedPortablePdbMethodOffsets as replacePortablePdbMethodOffsets,
62
- addEmbeddedPortablePdbDocument as addPortablePdbDocument,
63
- insertEmbeddedPortablePdbDocument as insertPortablePdbDocument,
64
- addEmbeddedPortablePdbTypeDefinitionDocuments as addPortablePdbTypeDefinitionDocuments,
65
- removeEmbeddedPortablePdbDocument as removePortablePdbDocument,
66
- replaceEmbeddedPortablePdbDocumentMetadata as replacePortablePdbDocumentMetadata,
67
- replaceEmbeddedPortablePdbTypeDefinitionDocuments as replacePortablePdbTypeDefinitionDocuments,
68
- replaceEmbeddedPortablePdbDocumentName as replacePortablePdbDocumentName,
69
- replaceEmbeddedPortablePdbLocalScope as replacePortablePdbLocalScope,
70
- replaceEmbeddedPortablePdbLocalVariable as replacePortablePdbLocalVariable,
71
- replaceEmbeddedPortablePdbLocalConstant as replacePortablePdbLocalConstant,
72
- replaceEmbeddedPortablePdbCustomDebugInformation as replacePortablePdbCustomDebugInformation,
73
- replaceEmbeddedPortablePdbMethodDocument as replacePortablePdbMethodDocument,
74
- replaceEmbeddedPortablePdbImportScope as replacePortablePdbImportScope,
75
- replaceEmbeddedPortablePdbSequencePoints as replacePortablePdbSequencePoints,
76
- replaceEmbeddedPortablePdbSource as replacePortablePdbSource,
77
- replaceEmbeddedPortablePdbSourceLink as replacePortablePdbSourceLink
54
+ replaceEmbeddedPortablePdbMethodOffsets as replacePortablePdbMethodOffsets
78
55
  } from "./metadata/portable-pdb.js";
79
56
  import {
80
57
  assertStrongNamePEProfile,
@@ -1999,6 +1976,33 @@ export class Assembly {
1999
1976
  #strongNameSignatureSize = 0;
2000
1977
  #hasAuthenticodeCertificate;
2001
1978
  #hasDebugDirectory;
1979
+ #instructionEditor = createInstructionEditor(this, {
1980
+ ensureEditable: () => this.#ensureEditable(),
1981
+ validateBranchTarget: (body, target) => this.#validateBranchTarget(body, target),
1982
+ createStructuralState: (methodRid) => this.#createStructuralState(methodRid),
1983
+ commitStructuralState: (methodRid, state) => this.#commitStructuralState(methodRid, state),
1984
+ allowedTokenTables,
1985
+ validateInstructionGenericContext
1986
+ });
1987
+ #pointerTableEditor = createPointerTableEditor({
1988
+ ensureEditable: () => this.#ensureEditable(),
1989
+ getBijectivePointerRows,
1990
+ validateGenericVariableReferences,
1991
+ getGenericParameterArity,
1992
+ validateTypeSpecDefinitions,
1993
+ validateTypeSpecGenericContext
1994
+ });
1995
+ #portablePdbEditor = createPortablePdbEditor({
1996
+ ensureEditable: () => this.#ensureEditable(),
1997
+ getPortablePdbForEdit: (...args) => this.#getPortablePdbForEdit(...args)
1998
+ });
1999
+ #methodRemovalEditor = createMethodRemovalEditor({
2000
+ ensureEditable: () => this.#ensureEditable(),
2001
+ ensureTokenRemappingSafe: (...args) => this.#ensureTokenRemappingSafe(...args),
2002
+ getPortablePdbForEdit: (...args) => this.#getPortablePdbForEdit(...args),
2003
+ replaceEmbeddedPortablePdb: (...args) => this.#replaceEmbeddedPortablePdb(...args),
2004
+ getBijectivePointerRows
2005
+ });
2002
2006
 
2003
2007
  constructor(input) {
2004
2008
  this.#bytes = input instanceof Uint8Array ? Uint8Array.from(input) : new Uint8Array(input);
@@ -4038,416 +4042,88 @@ export class Assembly {
4038
4042
  );
4039
4043
  }
4040
4044
 
4041
- addEmbeddedPortablePdbDocument(debugEntryIndex, name, options) {
4042
- this.#ensureEditable();
4043
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4044
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4045
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4046
- }
4047
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4048
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4049
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4050
- }
4051
- const data = addPortablePdbDocument(
4052
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4053
- name,
4054
- options
4055
- );
4056
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4045
+ addEmbeddedPortablePdbDocument(debugEntryIndex, name, options) {
4046
+ return this.#portablePdbEditor.addEmbeddedPortablePdbDocument.call(this, debugEntryIndex, name, options);
4057
4047
  }
4058
4048
 
4059
- insertEmbeddedPortablePdbDocument(debugEntryIndex, options) {
4060
- this.#ensureEditable();
4061
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4062
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4063
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4064
- }
4065
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4066
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4067
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4068
- }
4069
- const data = insertPortablePdbDocument(
4070
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4071
- options
4072
- );
4073
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4049
+ insertEmbeddedPortablePdbDocument(debugEntryIndex, options) {
4050
+ return this.#portablePdbEditor.insertEmbeddedPortablePdbDocument.call(this, debugEntryIndex, options);
4074
4051
  }
4075
4052
 
4076
- addEmbeddedPortablePdbTypeDefinitionDocuments(
4077
- debugEntryIndex,
4078
- typeRid,
4079
- documentRids
4080
- ) {
4081
- this.#ensureEditable();
4082
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4083
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4084
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4085
- }
4086
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4087
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4088
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4089
- }
4090
- const data = addPortablePdbTypeDefinitionDocuments(
4091
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4092
- typeRid,
4093
- documentRids
4094
- );
4095
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4053
+ addEmbeddedPortablePdbTypeDefinitionDocuments(debugEntryIndex, typeRid, documentRids) {
4054
+ return this.#portablePdbEditor.addEmbeddedPortablePdbTypeDefinitionDocuments.call(this, debugEntryIndex, typeRid, documentRids);
4096
4055
  }
4097
4056
 
4098
- removeEmbeddedPortablePdbDocument(debugEntryIndex, documentRid) {
4099
- this.#ensureEditable();
4100
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4101
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4102
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4103
- }
4104
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4105
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4106
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4107
- }
4108
- const data = removePortablePdbDocument(
4109
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4110
- documentRid
4111
- );
4112
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4057
+ removeEmbeddedPortablePdbDocument(debugEntryIndex, documentRid) {
4058
+ return this.#portablePdbEditor.removeEmbeddedPortablePdbDocument.call(this, debugEntryIndex, documentRid);
4113
4059
  }
4114
4060
 
4115
- replaceEmbeddedPortablePdbTypeDefinitionDocuments(
4116
- debugEntryIndex,
4117
- typeRid,
4118
- documentRids
4119
- ) {
4120
- this.#ensureEditable();
4121
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4122
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4123
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4124
- }
4125
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4126
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4127
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4128
- }
4129
- const data = replacePortablePdbTypeDefinitionDocuments(
4130
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4131
- typeRid,
4132
- documentRids
4133
- );
4134
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4061
+ replaceEmbeddedPortablePdbTypeDefinitionDocuments(debugEntryIndex, typeRid, documentRids) {
4062
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbTypeDefinitionDocuments.call(this, debugEntryIndex, typeRid, documentRids);
4135
4063
  }
4136
4064
 
4137
- replaceEmbeddedPortablePdbDocumentMetadata(debugEntryIndex, documentRid, options) {
4138
- this.#ensureEditable();
4139
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4140
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4141
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4142
- }
4143
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4144
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4145
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4146
- }
4147
- const data = replacePortablePdbDocumentMetadata(
4148
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4149
- documentRid,
4150
- options
4151
- );
4152
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4065
+ replaceEmbeddedPortablePdbDocumentMetadata(debugEntryIndex, documentRid, options) {
4066
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbDocumentMetadata.call(this, debugEntryIndex, documentRid, options);
4153
4067
  }
4154
4068
 
4155
- replaceEmbeddedPortablePdbDocumentName(debugEntryIndex, documentRid, name, separator) {
4156
- this.#ensureEditable();
4157
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4158
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4159
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4160
- }
4161
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4162
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4163
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4164
- }
4165
- const data = replacePortablePdbDocumentName(
4166
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4167
- documentRid,
4168
- name,
4169
- separator
4170
- );
4171
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4069
+ replaceEmbeddedPortablePdbDocumentName(debugEntryIndex, documentRid, name, separator) {
4070
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbDocumentName.call(this, debugEntryIndex, documentRid, name, separator);
4172
4071
  }
4173
4072
 
4174
- replaceEmbeddedPortablePdbSequencePoints(debugEntryIndex, methodRid, sequencePoints) {
4175
- this.#ensureEditable();
4176
- if (this._portablePdbOffsetBaselines.has(methodRid)) {
4177
- throw new UnsupportedFormatError(
4178
- "Portable PDB sequence points cannot be replaced after IL offset remapping has been staged"
4179
- );
4180
- }
4181
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4182
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4183
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4184
- }
4185
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4186
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4187
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4188
- }
4189
- const data = replacePortablePdbSequencePoints(
4190
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4191
- methodRid,
4192
- sequencePoints
4193
- );
4194
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4073
+ replaceEmbeddedPortablePdbSequencePoints(debugEntryIndex, methodRid, sequencePoints) {
4074
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbSequencePoints.call(this, debugEntryIndex, methodRid, sequencePoints);
4195
4075
  }
4196
4076
 
4197
- replaceEmbeddedPortablePdbMethodDocument(debugEntryIndex, methodRid, documentRid) {
4198
- this.#ensureEditable();
4199
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4200
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4201
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4202
- }
4203
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4204
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4205
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4206
- }
4207
- const data = replacePortablePdbMethodDocument(
4208
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4209
- methodRid,
4210
- documentRid
4211
- );
4212
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4077
+ replaceEmbeddedPortablePdbMethodDocument(debugEntryIndex, methodRid, documentRid) {
4078
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbMethodDocument.call(this, debugEntryIndex, methodRid, documentRid);
4213
4079
  }
4214
4080
 
4215
- replaceEmbeddedPortablePdbImportScope(debugEntryIndex, importScopeRid, options) {
4216
- this.#ensureEditable();
4217
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4218
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4219
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4220
- }
4221
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4222
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4223
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4224
- }
4225
- const data = replacePortablePdbImportScope(
4226
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4227
- importScopeRid,
4228
- options
4229
- );
4230
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4081
+ replaceEmbeddedPortablePdbImportScope(debugEntryIndex, importScopeRid, options) {
4082
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbImportScope.call(this, debugEntryIndex, importScopeRid, options);
4231
4083
  }
4232
4084
 
4233
- replaceEmbeddedPortablePdbLocalScope(debugEntryIndex, localScopeRid, options) {
4234
- this.#ensureEditable();
4235
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4236
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4237
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4238
- }
4239
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4240
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4241
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4242
- }
4243
- const pdb = this.#getPortablePdbForEdit(debugEntryIndex, entry);
4244
- const localScope = pdb.tables.rows.get(50)?.[localScopeRid - 1];
4245
- if (!localScope || localScope.rid !== localScopeRid) {
4246
- throw new RangeError(`Invalid Portable PDB LocalScope row ID ${localScopeRid}`);
4247
- }
4248
- if (this._portablePdbOffsetBaselines.has(localScope.Method.rid)) {
4249
- throw new UnsupportedFormatError(
4250
- "Portable PDB LocalScope offsets cannot be replaced after IL offset remapping has been staged"
4251
- );
4252
- }
4253
- const data = replacePortablePdbLocalScope(pdb, localScopeRid, options);
4254
- const updatedPdb = parseEmbeddedPortablePdbData(data, 0, data.length);
4255
- const updatedScope = updatedPdb.tables.rows.get(50)?.[localScopeRid - 1];
4256
- const body = this.getMethodBody(localScope.Method.rid);
4257
- if (!updatedScope || !body) {
4258
- throw new FormatError(
4259
- `Portable PDB LocalScope row ${localScopeRid} does not resolve to a method body`
4260
- );
4261
- }
4262
- const isBoundary = (offset) => offset === body.codeSize ||
4263
- body.instructions.some((instruction) => instruction.offset === offset);
4264
- const endOffset = updatedScope.StartOffset + updatedScope.Length;
4265
- if (!isBoundary(updatedScope.StartOffset) || !isBoundary(endOffset)) {
4266
- throw new FormatError(
4267
- `Portable PDB LocalScope row ${localScopeRid} does not align with MethodDef ${localScope.Method.rid} instruction boundaries`
4268
- );
4269
- }
4270
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4085
+ replaceEmbeddedPortablePdbLocalScope(debugEntryIndex, localScopeRid, options) {
4086
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalScope.call(this, debugEntryIndex, localScopeRid, options);
4271
4087
  }
4272
4088
 
4273
- replaceEmbeddedPortablePdbLocalVariable(debugEntryIndex, localVariableRid, options) {
4274
- this.#ensureEditable();
4275
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4276
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4277
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4278
- }
4279
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4280
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4281
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4282
- }
4283
- const data = replacePortablePdbLocalVariable(
4284
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4285
- localVariableRid,
4286
- options
4287
- );
4288
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4089
+ replaceEmbeddedPortablePdbLocalVariable(debugEntryIndex, localVariableRid, options) {
4090
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalVariable.call(this, debugEntryIndex, localVariableRid, options);
4289
4091
  }
4290
4092
 
4291
- replaceEmbeddedPortablePdbLocalConstant(debugEntryIndex, localConstantRid, options) {
4292
- this.#ensureEditable();
4293
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4294
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4295
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4296
- }
4297
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4298
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4299
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4300
- }
4301
- const data = replacePortablePdbLocalConstant(
4302
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4303
- localConstantRid,
4304
- options
4305
- );
4306
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4093
+ replaceEmbeddedPortablePdbLocalConstant(debugEntryIndex, localConstantRid, options) {
4094
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbLocalConstant.call(this, debugEntryIndex, localConstantRid, options);
4307
4095
  }
4308
4096
 
4309
- replaceEmbeddedPortablePdbCustomDebugInformation(
4310
- debugEntryIndex,
4311
- customDebugInformationRid,
4312
- value
4313
- ) {
4314
- this.#ensureEditable();
4315
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4316
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4317
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4318
- }
4319
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4320
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4321
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4322
- }
4323
- const data = replacePortablePdbCustomDebugInformation(
4324
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4325
- customDebugInformationRid,
4326
- value
4327
- );
4328
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4097
+ replaceEmbeddedPortablePdbCustomDebugInformation(debugEntryIndex, customDebugInformationRid, value) {
4098
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbCustomDebugInformation.call(this, debugEntryIndex, customDebugInformationRid, value);
4329
4099
  }
4330
4100
 
4331
- replaceEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
4332
- this.#ensureEditable();
4333
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4334
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4335
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4336
- }
4337
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4338
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4339
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4340
- }
4341
- const data = replacePortablePdbSource(
4342
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4343
- documentRid,
4344
- source,
4345
- options
4346
- );
4347
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4101
+ replaceEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
4102
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid, source, options);
4348
4103
  }
4349
4104
 
4350
- addEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
4351
- this.#ensureEditable();
4352
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4353
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4354
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4355
- }
4356
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4357
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4358
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4359
- }
4360
- const data = addPortablePdbSource(
4361
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4362
- documentRid,
4363
- source,
4364
- options
4365
- );
4366
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4105
+ addEmbeddedPortablePdbSource(debugEntryIndex, documentRid, source, options) {
4106
+ return this.#portablePdbEditor.addEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid, source, options);
4367
4107
  }
4368
4108
 
4369
- removeEmbeddedPortablePdbSource(debugEntryIndex, documentRid) {
4370
- this.#ensureEditable();
4371
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4372
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4373
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4374
- }
4375
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4376
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4377
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4378
- }
4379
- const data = removePortablePdbSource(
4380
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4381
- documentRid
4382
- );
4383
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4109
+ removeEmbeddedPortablePdbSource(debugEntryIndex, documentRid) {
4110
+ return this.#portablePdbEditor.removeEmbeddedPortablePdbSource.call(this, debugEntryIndex, documentRid);
4384
4111
  }
4385
4112
 
4386
- removeEmbeddedPortablePdbCustomDebugInformation(debugEntryIndex, recordRid) {
4387
- this.#ensureEditable();
4388
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4389
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4390
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4391
- }
4392
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4393
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4394
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4395
- }
4396
- const data = removePortablePdbCustomDebugInformation(
4397
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4398
- recordRid
4399
- );
4400
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4113
+ removeEmbeddedPortablePdbCustomDebugInformation(debugEntryIndex, recordRid) {
4114
+ return this.#portablePdbEditor.removeEmbeddedPortablePdbCustomDebugInformation.call(this, debugEntryIndex, recordRid);
4401
4115
  }
4402
4116
 
4403
- replaceEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
4404
- this.#ensureEditable();
4405
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4406
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4407
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4408
- }
4409
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4410
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4411
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4412
- }
4413
- const data = replacePortablePdbSourceLink(
4414
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4415
- sourceLink
4416
- );
4417
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4117
+ replaceEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
4118
+ return this.#portablePdbEditor.replaceEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex, sourceLink);
4418
4119
  }
4419
4120
 
4420
- removeEmbeddedPortablePdbSourceLink(debugEntryIndex) {
4421
- this.#ensureEditable();
4422
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4423
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4424
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4425
- }
4426
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4427
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4428
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4429
- }
4430
- const data = removePortablePdbSourceLink(
4431
- this.#getPortablePdbForEdit(debugEntryIndex, entry)
4432
- );
4433
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4121
+ removeEmbeddedPortablePdbSourceLink(debugEntryIndex) {
4122
+ return this.#portablePdbEditor.removeEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex);
4434
4123
  }
4435
4124
 
4436
- addEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
4437
- this.#ensureEditable();
4438
- if (!Number.isInteger(debugEntryIndex) || debugEntryIndex < 0 ||
4439
- debugEntryIndex >= this.pe.debugDirectoryEntries.length) {
4440
- throw new RangeError(`Invalid debug-directory entry index ${debugEntryIndex}`);
4441
- }
4442
- const entry = this.pe.debugDirectoryEntries[debugEntryIndex];
4443
- if (entry.type !== 17 || !entry.embeddedPortablePdb) {
4444
- throw new UnsupportedFormatError("Debug-directory entry is not an embedded Portable PDB");
4445
- }
4446
- const data = addPortablePdbSourceLink(
4447
- this.#getPortablePdbForEdit(debugEntryIndex, entry),
4448
- sourceLink
4449
- );
4450
- return this.replaceEmbeddedPortablePdb(debugEntryIndex, data);
4125
+ addEmbeddedPortablePdbSourceLink(debugEntryIndex, sourceLink) {
4126
+ return this.#portablePdbEditor.addEmbeddedPortablePdbSourceLink.call(this, debugEntryIndex, sourceLink);
4451
4127
  }
4452
4128
 
4453
4129
  replaceFieldSignature(rid, signature) {
@@ -6141,801 +5817,26 @@ export class Assembly {
6141
5817
  }
6142
5818
 
6143
5819
  removeMethod(rid) {
5820
+ return this.#methodRemovalEditor.removeMethod.call(this, rid);
5821
+ }
5822
+
5823
+ addParam({ owner, name = "", sequence, flags = 0 }) {
5824
+ return this.#writeParam({ owner, name, sequence, flags }, false).rid;
5825
+ }
5826
+
5827
+ insertParam({ owner, name = "", sequence, flags = 0 }) {
5828
+ return this.#writeParam({ owner, name, sequence, flags }, true);
5829
+ }
5830
+
5831
+ #writeParam({ owner, name = "", sequence, flags = 0 }, insertIntoOwner) {
6144
5832
  this.#ensureEditable();
6145
- if (this._structuralBodies.size > 0) {
6146
- throw new UnsupportedFormatError("Method removal cannot be combined with structural method edits");
5833
+ const ownerRid = metadataTableId(owner?.table) === 6 ? owner.rid : 0;
5834
+ const method = this.methods[ownerRid - 1];
5835
+ if (!Number.isInteger(ownerRid) || ownerRid < 1 || !method) {
5836
+ throw new RangeError("Param owner must identify an existing MethodDef");
6147
5837
  }
6148
- const embeddedPdbIndices = this.pe.debugDirectoryEntries.flatMap((entry, index) =>
6149
- entry.embeddedPortablePdb ? [index] : []
6150
- );
6151
- this.#ensureTokenRemappingSafe("MethodDef", {
6152
- allowEmbeddedPortablePdb: embeddedPdbIndices.length === 1
6153
- });
6154
- const rows = this.tables.rows.get(6) ?? [];
6155
- if (rows.length !== this.tables.counts[6] || rows.length !== this.methods.length) {
6156
- throw new FormatError("MethodDef row count is inconsistent with the metadata table header");
6157
- }
6158
- if (!Number.isInteger(rid) || rid < 1 || rid > rows.length) {
6159
- throw new RangeError(`Invalid MethodDef row ID ${rid}`);
6160
- }
6161
- const cliEntryPointToken = this._cliEntryPointToken ?? this.cli.entryPointToken;
6162
- const isManagedMethodEntryPoint =
6163
- (this.cli.flags & 0x10) === 0 &&
6164
- (cliEntryPointToken >>> 24) === 6;
6165
- const cliEntryPointRid = cliEntryPointToken & 0x00ffffff;
6166
- if (isManagedMethodEntryPoint &&
6167
- (cliEntryPointRid === 0 || cliEntryPointRid > rows.length)) {
6168
- throw new FormatError("CLI entry point references a missing MethodDef");
6169
- }
6170
- if (isManagedMethodEntryPoint && cliEntryPointRid === rid) {
6171
- throw new FormatError(`MethodDef row ${rid} is the CLI entry point`);
6172
- }
6173
- const remappedCliEntryPointToken = isManagedMethodEntryPoint &&
6174
- cliEntryPointRid > rid
6175
- ? cliEntryPointToken - 1
6176
- : cliEntryPointToken;
6177
- const shiftsMethodRids = rid < rows.length;
6178
- if (shiftsMethodRids && this._addedMethodBodies.size > 0) {
6179
- throw new UnsupportedFormatError(
6180
- "MethodDef RID remapping cannot be combined with added method bodies"
6181
- );
6182
- }
6183
- const method = this.methods[rid - 1];
6184
- if (method?.rid !== rid) throw new FormatError(`MethodDef row ${rid} has inconsistent semantic records`);
6185
- const genericParamRows = this.tables.rows.get(42) ?? [];
6186
- if (genericParamRows.length !== (this.tables.counts[42] ?? 0)) {
6187
- throw new FormatError("GenericParam row count is inconsistent with the metadata table header");
6188
- }
6189
- const genericParamRids = new Set(method.genericParams.map((parameter) => parameter.rid));
6190
- if (genericParamRids.size !== method.genericParams.length ||
6191
- method.genericParams.length !== this.genericParams.filter(
6192
- (parameter) => parameter.owner.table === 6 && parameter.owner.rid === rid
6193
- ).length) {
6194
- throw new FormatError(`MethodDef row ${rid} has inconsistent GenericParam ownership`);
6195
- }
6196
- if (genericParamRids.size > 0) {
6197
- const sortedGenericParamRids = [...genericParamRids].sort((a, b) => a - b);
6198
- const firstGenericParamRid = sortedGenericParamRids[0];
6199
- if (firstGenericParamRid < 1 ||
6200
- sortedGenericParamRids.some((parameterRid, index) =>
6201
- parameterRid !== firstGenericParamRid + index
6202
- ) || sortedGenericParamRids.at(-1) > genericParamRows.length) {
6203
- throw new UnsupportedFormatError(
6204
- "MethodDef removal requires its GenericParam rows to form a contiguous table range"
6205
- );
6206
- }
6207
- }
6208
- const genericParamConstraintRows = this.tables.rows.get(44) ?? [];
6209
- if (genericParamConstraintRows.length !== (this.tables.counts[44] ?? 0) ||
6210
- genericParamConstraintRows.length !== this.genericParamConstraints.length) {
6211
- throw new FormatError("GenericParamConstraint row count is inconsistent with the metadata table header");
6212
- }
6213
- const genericParamConstraintRids = new Set(
6214
- this.genericParamConstraints
6215
- .filter((constraint) => genericParamRids.has(constraint.ownerRid))
6216
- .map((constraint) => constraint.rid)
6217
- );
6218
- if (genericParamConstraintRids.size > 0) {
6219
- for (const [tableId, tableRows] of this.tables.rows) {
6220
- const schema = metadataTableSchemas[tableId];
6221
- if (!schema) {
6222
- throw new UnsupportedFormatError(
6223
- `Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
6224
- );
6225
- }
6226
- for (const row of tableRows) {
6227
- if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
6228
- for (const [kind, value, name] of schema) {
6229
- const columnName = name ?? value;
6230
- const column = row[columnName];
6231
- const target = kind === "coded"
6232
- ? column?.target
6233
- : kind === "table" ? { table: value, rid: column?.rid } : null;
6234
- if (target?.table === 44 && genericParamConstraintRids.has(target.rid)) {
6235
- throw new FormatError(
6236
- `GenericParamConstraint row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6237
- );
6238
- }
6239
- if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6240
- columnName === "Token" && row[columnName] >>> 24 === 44 &&
6241
- genericParamConstraintRids.has(row[columnName] & 0x00ffffff)) {
6242
- throw new FormatError(
6243
- `GenericParamConstraint row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6244
- );
6245
- }
6246
- }
6247
- }
6248
- }
6249
- for (const candidate of this.methods) {
6250
- for (const instruction of this.getMethodBody(candidate.rid)?.instructions ?? []) {
6251
- const token = instruction.operand?.kind === "token" ? instruction.operand.value : 0;
6252
- if ((token >>> 24) === 44 && genericParamConstraintRids.has(token & 0x00ffffff)) {
6253
- throw new FormatError(
6254
- `GenericParamConstraint row ${token & 0x00ffffff} is referenced by CIL in MethodDef row ${candidate.rid}`
6255
- );
6256
- }
6257
- }
6258
- }
6259
- }
6260
- const parameterRows = this.tables.rows.get(8) ?? [];
6261
- if (parameterRows.length !== (this.tables.counts[8] ?? 0)) {
6262
- throw new FormatError("Param row count is inconsistent with the metadata table header");
6263
- }
6264
- const parameterRids = new Set(method.parameterRids);
6265
- if (method.parameterRids.length !== method.parameters.length ||
6266
- parameterRids.size !== method.parameterRids.length) {
6267
- throw new FormatError(`MethodDef row ${rid} has inconsistent Param ownership`);
6268
- }
6269
- if (parameterRids.size > 0) {
6270
- const sortedParameterRids = [...parameterRids].sort((a, b) => a - b);
6271
- const firstParameterRid = sortedParameterRids[0];
6272
- if (firstParameterRid < 1 ||
6273
- sortedParameterRids.some((parameterRid, index) => parameterRid !== firstParameterRid + index) ||
6274
- sortedParameterRids.at(-1) > parameterRows.length) {
6275
- throw new UnsupportedFormatError(
6276
- "MethodDef removal requires its Param rows to form a contiguous table range"
6277
- );
6278
- }
6279
- }
6280
- const owners = this.types.filter((type) => type.methodRids.includes(rid));
6281
- if (owners.length !== 1 || !owners[0].methods.some((candidate) => candidate.rid === rid)) {
6282
- throw new FormatError(`MethodDef row ${rid} has no unique resolved TypeDef owner`);
6283
- }
6284
- const supportedStreams = new Set(["#~", "#-", "#Strings", "#US", "#GUID", "#Blob"]);
6285
- for (const streamName of this.metadataRoot.streams.keys()) {
6286
- if (!supportedStreams.has(streamName)) {
6287
- throw new UnsupportedFormatError(
6288
- `Cannot remove MethodDef row ${rid} with unrecognized metadata stream ${streamName}`
6289
- );
6290
- }
6291
- }
6292
-
6293
- const paramPointerRows = parameterRids.size > 0
6294
- ? getBijectivePointerRows(this, 7, 8, "Param")
6295
- : null;
6296
- if (parameterRids.size > 0 && (this.tables.valid & (1n << 7n)) !== 0n) {
6297
- const pointerRids = paramPointerRows
6298
- .filter((pointer) => parameterRids.has(pointer.Param.rid))
6299
- .map((pointer) => pointer.rid);
6300
- const firstPointerRid = Math.min(...pointerRids);
6301
- if (pointerRids.length !== parameterRids.size ||
6302
- [...pointerRids].sort((a, b) => a - b)
6303
- .some((pointerRid, index) => pointerRid !== firstPointerRid + index)) {
6304
- throw new UnsupportedFormatError(
6305
- "MethodDef removal requires its ParamPtr rows to form a contiguous pointer range"
6306
- );
6307
- }
6308
- }
6309
- if (parameterRids.size > 0) {
6310
- for (const [tableId, tableRows] of this.tables.rows) {
6311
- const schema = metadataTableSchemas[tableId];
6312
- if (!schema) {
6313
- throw new UnsupportedFormatError(
6314
- `Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
6315
- );
6316
- }
6317
- for (const row of tableRows) {
6318
- for (const [kind, value, name, pointer] of schema) {
6319
- const columnName = name ?? value;
6320
- if (kind === "coded" && row[columnName]?.target?.table === 8 &&
6321
- parameterRids.has(row[columnName].target.rid)) {
6322
- throw new FormatError(
6323
- `Param row ${row[columnName].target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6324
- );
6325
- }
6326
- if (kind === "table") {
6327
- const targetTable = pointer !== undefined &&
6328
- (this.tables.valid & (1n << BigInt(pointer))) !== 0n ? pointer : value;
6329
- if (targetTable !== 8 || (tableId === 6 && columnName === "ParamList") ||
6330
- (tableId === 7 && columnName === "Param")) continue;
6331
- if (parameterRids.has(row[columnName]?.rid)) {
6332
- throw new FormatError(
6333
- `Param row ${row[columnName].rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6334
- );
6335
- }
6336
- }
6337
- if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6338
- columnName === "Token" && row[columnName] >>> 24 === 8 &&
6339
- parameterRids.has(row[columnName] & 0x00ffffff)) {
6340
- throw new FormatError(
6341
- `Param row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6342
- );
6343
- }
6344
- }
6345
- }
6346
- }
6347
- }
6348
- if (genericParamRids.size > 0) {
6349
- for (const [tableId, tableRows] of this.tables.rows) {
6350
- const schema = metadataTableSchemas[tableId];
6351
- if (!schema) {
6352
- throw new UnsupportedFormatError(
6353
- `Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
6354
- );
6355
- }
6356
- for (const row of tableRows) {
6357
- if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
6358
- for (const [kind, value, name] of schema) {
6359
- const columnName = name ?? value;
6360
- const column = row[columnName];
6361
- const target = kind === "coded"
6362
- ? column?.target
6363
- : kind === "table" ? { table: value, rid: column?.rid } : null;
6364
- if (target?.table === 42 && genericParamRids.has(target.rid)) {
6365
- throw new FormatError(
6366
- `GenericParam row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6367
- );
6368
- }
6369
- if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6370
- columnName === "Token" && row[columnName] >>> 24 === 42 &&
6371
- genericParamRids.has(row[columnName] & 0x00ffffff)) {
6372
- throw new FormatError(
6373
- `GenericParam row ${row[columnName] & 0x00ffffff} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6374
- );
6375
- }
6376
- }
6377
- }
6378
- }
6379
- }
6380
-
6381
- const pointerRows = getBijectivePointerRows(this, 5, 6, "Method");
6382
- const pointerRid = pointerRows
6383
- ? pointerRows.findIndex((pointer) => pointer.Method.rid === rid) + 1
6384
- : 0;
6385
- if (pointerRows && pointerRid === 0) {
6386
- throw new FormatError(`MethodPtr has no pointer to MethodDef row ${rid}`);
6387
- }
6388
- const tokenMap = new Map();
6389
- for (let oldRid = rid + 1; oldRid <= rows.length; oldRid++) {
6390
- tokenMap.set(0x06000000 + oldRid, 0x06000000 + oldRid - 1);
6391
- }
6392
- const lastParameterRid = parameterRids.size > 0
6393
- ? Math.max(...parameterRids)
6394
- : 0;
6395
- const remapParameterRid = (oldRid) =>
6396
- oldRid > lastParameterRid ? oldRid - parameterRids.size : oldRid;
6397
- if (parameterRids.size > 0) {
6398
- for (let oldRid = lastParameterRid + 1; oldRid <= parameterRows.length; oldRid++) {
6399
- tokenMap.set(0x08000000 + oldRid, 0x08000000 + remapParameterRid(oldRid));
6400
- }
6401
- }
6402
- const lastGenericParamRid = genericParamRids.size > 0
6403
- ? Math.max(...genericParamRids)
6404
- : 0;
6405
- const remapGenericParamRid = (oldRid) =>
6406
- oldRid > lastGenericParamRid ? oldRid - genericParamRids.size : oldRid;
6407
- if (genericParamRids.size > 0) {
6408
- for (let oldRid = lastGenericParamRid + 1; oldRid <= genericParamRows.length; oldRid++) {
6409
- tokenMap.set(0x2a000000 + oldRid, 0x2a000000 + remapGenericParamRid(oldRid));
6410
- }
6411
- }
6412
- const remapGenericParamConstraintRid = (oldRid) => oldRid -
6413
- [...genericParamConstraintRids].filter((constraintRid) => constraintRid < oldRid).length;
6414
- if (genericParamConstraintRids.size > 0) {
6415
- for (let oldRid = 1; oldRid <= genericParamConstraintRows.length; oldRid++) {
6416
- if (genericParamConstraintRids.has(oldRid)) continue;
6417
- tokenMap.set(
6418
- 0x2c000000 + oldRid,
6419
- 0x2c000000 + remapGenericParamConstraintRid(oldRid)
6420
- );
6421
- }
6422
- }
6423
- const rowChanges = [];
6424
- for (const [tableId, tableRows] of this.tables.rows) {
6425
- const schema = metadataTableSchemas[tableId];
6426
- if (!schema) {
6427
- throw new UnsupportedFormatError(
6428
- `Cannot remove MethodDef row ${rid} with unknown metadata table ${tableId}`
6429
- );
6430
- }
6431
- for (const row of tableRows) {
6432
- if (tableId === 44 && genericParamConstraintRids.has(row.rid)) continue;
6433
- for (const [kind, value, name, pointer] of schema) {
6434
- const columnName = name ?? value;
6435
- if (kind === "coded") {
6436
- const target = row[columnName]?.target;
6437
- if (target?.table === 44) {
6438
- if (genericParamConstraintRids.has(target.rid)) {
6439
- throw new FormatError(
6440
- `GenericParamConstraint row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6441
- );
6442
- }
6443
- const remappedRid = remapGenericParamConstraintRid(target.rid);
6444
- if (remappedRid !== target.rid) {
6445
- const remappedTarget = { ...target, rid: remappedRid };
6446
- rowChanges.push({
6447
- row,
6448
- columnName,
6449
- value: {
6450
- raw: encodeCodedIndex(44, remappedRid, value),
6451
- target: remappedTarget
6452
- }
6453
- });
6454
- }
6455
- continue;
6456
- }
6457
- if (target?.table === 8 || target?.table === 42) {
6458
- const removedRids = target.table === 8 ? parameterRids : genericParamRids;
6459
- if (removedRids.has(target.rid)) {
6460
- throw new FormatError(
6461
- `${metadataTableNames[target.table]} row ${target.rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6462
- );
6463
- }
6464
- const remappedRid = target.table === 8
6465
- ? remapParameterRid(target.rid)
6466
- : remapGenericParamRid(target.rid);
6467
- if (remappedRid !== target.rid) {
6468
- const remappedTarget = { ...target, rid: remappedRid };
6469
- rowChanges.push({
6470
- row,
6471
- columnName,
6472
- value: {
6473
- raw: encodeCodedIndex(target.table, remappedRid, value),
6474
- target: remappedTarget
6475
- }
6476
- });
6477
- }
6478
- continue;
6479
- }
6480
- if (target?.table !== 6) continue;
6481
- if (tableId === 42 && columnName === "Owner" &&
6482
- genericParamRids.has(row.rid)) continue;
6483
- if (target.rid === rid) {
6484
- throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
6485
- }
6486
- if (target.rid > rid) {
6487
- const remappedTarget = { ...target, rid: target.rid - 1 };
6488
- rowChanges.push({
6489
- row,
6490
- columnName,
6491
- value: {
6492
- raw: encodeCodedIndex(6, remappedTarget.rid, value),
6493
- target: remappedTarget
6494
- }
6495
- });
6496
- }
6497
- } else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6498
- columnName === "Token" && [8, 42].includes(row[columnName] >>> 24)) {
6499
- const tokenTable = row[columnName] >>> 24;
6500
- const targetRid = row[columnName] & 0x00ffffff;
6501
- const removedRids = tokenTable === 8 ? parameterRids : genericParamRids;
6502
- if (removedRids.has(targetRid)) {
6503
- throw new FormatError(
6504
- `${metadataTableNames[tokenTable]} row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6505
- );
6506
- }
6507
- const remappedRid = tokenTable === 8
6508
- ? remapParameterRid(targetRid)
6509
- : remapGenericParamRid(targetRid);
6510
- if (remappedRid !== targetRid) {
6511
- rowChanges.push({
6512
- row,
6513
- columnName,
6514
- value: (tokenTable << 24) | remappedRid
6515
- });
6516
- }
6517
- } else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6518
- columnName === "Token" && row[columnName] >>> 24 === 44) {
6519
- const targetRid = row[columnName] & 0x00ffffff;
6520
- if (genericParamConstraintRids.has(targetRid)) {
6521
- throw new FormatError(
6522
- `GenericParamConstraint row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6523
- );
6524
- }
6525
- const remappedRid = remapGenericParamConstraintRid(targetRid);
6526
- if (remappedRid !== targetRid) {
6527
- rowChanges.push({
6528
- row,
6529
- columnName,
6530
- value: 0x2c000000 | remappedRid
6531
- });
6532
- }
6533
- } else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6534
- columnName === "Token" && row[columnName] >>> 24 === 6 &&
6535
- (row[columnName] & 0x00ffffff) === rid) {
6536
- throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
6537
- } else if (kind === "u4" && (tableId === 30 || tableId === 31) &&
6538
- columnName === "Token" && row[columnName] >>> 24 === 6 &&
6539
- (row[columnName] & 0x00ffffff) > rid) {
6540
- const oldToken = row[columnName];
6541
- rowChanges.push({ row, columnName, value: oldToken - 1 });
6542
- } else if (kind === "table") {
6543
- if (tableId === 2 && columnName === "MethodList") continue;
6544
- const targetTable = pointer !== undefined &&
6545
- (this.tables.valid & (1n << BigInt(pointer))) !== 0n ? pointer : value;
6546
- const targetRid = row[columnName]?.rid;
6547
- if (targetTable === 8) {
6548
- if ((tableId === 6 && columnName === "ParamList") ||
6549
- (tableId === 7 && columnName === "Param")) continue;
6550
- if (parameterRids.has(targetRid)) {
6551
- throw new FormatError(
6552
- `Param row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6553
- );
6554
- }
6555
- const remappedRid = remapParameterRid(targetRid);
6556
- if (remappedRid !== targetRid) {
6557
- rowChanges.push({
6558
- row,
6559
- columnName,
6560
- value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
6561
- });
6562
- }
6563
- continue;
6564
- }
6565
- if (targetTable === 42) {
6566
- if (genericParamRids.has(targetRid)) {
6567
- throw new FormatError(
6568
- `GenericParam row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6569
- );
6570
- }
6571
- const remappedRid = remapGenericParamRid(targetRid);
6572
- if (remappedRid !== targetRid) {
6573
- rowChanges.push({
6574
- row,
6575
- columnName,
6576
- value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
6577
- });
6578
- }
6579
- continue;
6580
- }
6581
- if (targetTable === 44) {
6582
- if (genericParamConstraintRids.has(targetRid)) {
6583
- throw new FormatError(
6584
- `GenericParamConstraint row ${targetRid} is referenced by ${metadataTableNames[tableId]}.${columnName}`
6585
- );
6586
- }
6587
- const remappedRid = remapGenericParamConstraintRid(targetRid);
6588
- if (remappedRid !== targetRid) {
6589
- rowChanges.push({
6590
- row,
6591
- columnName,
6592
- value: { ...row[columnName], raw: remappedRid, rid: remappedRid }
6593
- });
6594
- }
6595
- continue;
6596
- }
6597
- if (targetTable !== 6) continue;
6598
- if (tableId === 5 && columnName === "Method") {
6599
- if (row.rid === pointerRid) continue;
6600
- if (targetRid === rid) {
6601
- throw new FormatError(`MethodDef row ${rid} is referenced by MethodPtr.Method`);
6602
- }
6603
- continue;
6604
- }
6605
- if (targetRid === rid) {
6606
- throw new FormatError(`MethodDef row ${rid} is referenced by ${metadataTableNames[tableId]}.${columnName}`);
6607
- }
6608
- if (targetRid > rid) {
6609
- rowChanges.push({
6610
- row,
6611
- columnName,
6612
- value: { ...row[columnName], raw: targetRid - 1, rid: targetRid - 1 }
6613
- });
6614
- }
6615
- }
6616
- }
6617
- }
6618
- }
6619
- const tokenUpdates = [];
6620
- const patches = [];
6621
- for (const candidate of this.methods) {
6622
- if (candidate.rid === rid) continue;
6623
- const body = this.getMethodBody(candidate.rid);
6624
- for (const instruction of body?.instructions ?? []) {
6625
- const token = instruction.operand?.kind === "token" ? instruction.operand.value : 0;
6626
- if ((token >>> 24) !== 6) continue;
6627
- const targetRid = token & 0x00ffffff;
6628
- if (targetRid === rid) {
6629
- throw new FormatError(`MethodDef row ${rid} is referenced by CIL in MethodDef row ${candidate.rid}`);
6630
- }
6631
- if (targetRid > rid) {
6632
- const replacement = token - 1;
6633
- tokenUpdates.push({ instruction, replacement });
6634
- patches.push(...createOperandPatches(instruction, replacement));
6635
- }
6636
- }
6637
- }
6638
- const sortedKeyColumns = new Map([
6639
- [10, "Class"], [11, "Parent"], [12, "Parent"], [13, "Parent"], [14, "Parent"],
6640
- [28, "MemberForwarded"], [42, "Owner"], [43, "Method"]
6641
- ]);
6642
- const changedSortedKeys = new Map(rowChanges
6643
- .filter((change) => [...sortedKeyColumns.values()].includes(change.columnName))
6644
- .map((change) => [change.row, change.value]));
6645
- for (const [tableId, keyOf] of [
6646
- [10, (row) => [row.Class.raw]],
6647
- [11, (row) => [row.Parent.raw]],
6648
- [12, (row) => [row.Parent.raw]],
6649
- [13, (row) => [row.Parent.raw]],
6650
- [14, (row) => [row.Parent.raw, row.Action]],
6651
- [28, (row) => [row.MemberForwarded.raw]],
6652
- [42, (row) => [row.Owner.raw, row.Number]],
6653
- [43, (row) => [row.Method.raw]]
6654
- ]) {
6655
- if ((this.tables.sorted & (1n << BigInt(tableId))) === 0n) continue;
6656
- let previous = null;
6657
- for (const row of this.tables.get(tableId)) {
6658
- const changedKey = changedSortedKeys.get(row);
6659
- const current = keyOf(row);
6660
- if (changedKey) current[0] = changedKey.raw ?? changedKey;
6661
- let outOfOrder = false;
6662
- if (previous) {
6663
- for (let index = 0; index < current.length; index++) {
6664
- if (current[index] === previous[index]) continue;
6665
- outOfOrder = current[index] < previous[index];
6666
- break;
6667
- }
6668
- }
6669
- if (outOfOrder) {
6670
- throw new FormatError(
6671
- `MethodDef token remapping would violate sorted ${metadataTableNames[tableId]} order`
6672
- );
6673
- }
6674
- previous = current;
6675
- }
6676
- }
6677
-
6678
- const methodPointerPresent = pointerRows !== null;
6679
- if (embeddedPdbIndices.length === 1) {
6680
- const updatedCounts = [...this.tables.counts];
6681
- updatedCounts[6]--;
6682
- if (methodPointerPresent) updatedCounts[5]--;
6683
- if (parameterRids.size > 0) {
6684
- updatedCounts[8] -= parameterRids.size;
6685
- if (paramPointerRows) updatedCounts[7] -= parameterRids.size;
6686
- }
6687
- if (genericParamRids.size > 0) updatedCounts[42] -= genericParamRids.size;
6688
- if (genericParamConstraintRids.size > 0) {
6689
- updatedCounts[44] -= genericParamConstraintRids.size;
6690
- }
6691
- const debugEntryIndex = embeddedPdbIndices[0];
6692
- const debugEntry = this.pe.debugDirectoryEntries[debugEntryIndex];
6693
- const pdb = this.#getPortablePdbForEdit(debugEntryIndex, debugEntry);
6694
- const updatedPdb = removePortablePdbMethod(
6695
- pdb,
6696
- rid,
6697
- this.tables.counts,
6698
- updatedCounts
6699
- );
6700
- this.#replaceEmbeddedPortablePdb(debugEntryIndex, updatedPdb, updatedCounts);
6701
- }
6702
- if (remappedCliEntryPointToken !== cliEntryPointToken) {
6703
- const entryPointBytes = new Uint8Array(4);
6704
- new DataView(entryPointBytes.buffer).setUint32(0, remappedCliEntryPointToken, true);
6705
- patches.push({
6706
- offset: this.cli.offset + 20,
6707
- bytes: entryPointBytes
6708
- });
6709
- this._cliEntryPointToken = remappedCliEntryPointToken;
6710
- }
6711
- if (methodPointerPresent) {
6712
- const remainingPointers = pointerRows.filter((pointer) => pointer.rid !== pointerRid);
6713
- remainingPointers.forEach((pointer, index) => {
6714
- pointer.rid = index + 1;
6715
- if (pointer.Method.rid > rid) {
6716
- pointer.Method = {
6717
- ...pointer.Method,
6718
- raw: pointer.Method.rid - 1,
6719
- rid: pointer.Method.rid - 1
6720
- };
6721
- }
6722
- });
6723
- this.tables.rows.set(5, remainingPointers);
6724
- this.tables.counts[5] = remainingPointers.length;
6725
- if (remainingPointers.length === 0) this.tables.valid &= ~(1n << 5n);
6726
- }
6727
- const listBoundary = methodPointerPresent ? pointerRid : rid;
6728
- const listChanges = [];
6729
- for (const typeRow of this.tables.rows.get(2) ?? []) {
6730
- if (typeRow.MethodList.rid > listBoundary) {
6731
- listChanges.push({
6732
- row: typeRow,
6733
- value: {
6734
- ...typeRow.MethodList,
6735
- raw: typeRow.MethodList.rid - 1,
6736
- rid: typeRow.MethodList.rid - 1
6737
- }
6738
- });
6739
- }
6740
- }
6741
- const removedParamListPositions = paramPointerRows
6742
- ? paramPointerRows.filter((pointer) => parameterRids.has(pointer.Param.rid))
6743
- .map((pointer) => pointer.rid)
6744
- : [...parameterRids];
6745
- const paramListChanges = [];
6746
- if (removedParamListPositions.length > 0) {
6747
- for (const methodRow of this.tables.get(6)) {
6748
- const oldBoundary = methodRow.ParamList.rid;
6749
- const newBoundary = oldBoundary -
6750
- removedParamListPositions.filter((position) => position < oldBoundary).length;
6751
- if (newBoundary === oldBoundary) continue;
6752
- paramListChanges.push({
6753
- row: methodRow,
6754
- value: {
6755
- ...methodRow.ParamList,
6756
- raw: newBoundary,
6757
- rid: newBoundary
6758
- }
6759
- });
6760
- }
6761
- }
6762
- for (const change of rowChanges) change.row[change.columnName] = change.value;
6763
- for (const change of listChanges) change.row.MethodList = change.value;
6764
- for (const change of paramListChanges) change.row.ParamList = change.value;
6765
- for (const update of tokenUpdates) update.instruction.operand.value = update.replacement;
6766
- this._patches.push(...patches);
6767
- if (parameterRids.size > 0) {
6768
- const remainingParams = parameterRows.filter((parameter) => !parameterRids.has(parameter.rid));
6769
- remainingParams.forEach((parameter) => {
6770
- parameter.rid = remapParameterRid(parameter.rid);
6771
- });
6772
- this.tables.rows.set(8, remainingParams);
6773
- this.tables.counts[8] = remainingParams.length;
6774
- if (remainingParams.length === 0) this.tables.valid &= ~(1n << 8n);
6775
- if (paramPointerRows) {
6776
- const remainingParamPointers = paramPointerRows.filter((pointer) =>
6777
- !parameterRids.has(pointer.Param.rid)
6778
- );
6779
- remainingParamPointers.forEach((pointer, index) => {
6780
- pointer.rid = index + 1;
6781
- const remappedRid = remapParameterRid(pointer.Param.rid);
6782
- if (remappedRid !== pointer.Param.rid) {
6783
- pointer.Param = {
6784
- ...pointer.Param,
6785
- raw: remappedRid,
6786
- rid: remappedRid
6787
- };
6788
- }
6789
- });
6790
- this.tables.rows.set(7, remainingParamPointers);
6791
- this.tables.counts[7] = remainingParamPointers.length;
6792
- if (remainingParamPointers.length === 0) this.tables.valid &= ~(1n << 7n);
6793
- }
6794
- for (const candidate of this.methods) {
6795
- candidate.parameterRids = candidate.parameterRids
6796
- .filter((parameterRid) => !parameterRids.has(parameterRid))
6797
- .map(remapParameterRid);
6798
- candidate.parameters = candidate.parameters
6799
- .filter((parameter) => !parameterRids.has(parameter.rid))
6800
- .map((parameter) => {
6801
- parameter.rid = remapParameterRid(parameter.rid);
6802
- return parameter;
6803
- });
6804
- }
6805
- }
6806
- if (genericParamRids.size > 0) {
6807
- const remainingGenericParams = genericParamRows.filter((parameter) =>
6808
- !genericParamRids.has(parameter.rid)
6809
- );
6810
- remainingGenericParams.forEach((parameter) => {
6811
- parameter.rid = remapGenericParamRid(parameter.rid);
6812
- });
6813
- this.tables.rows.set(42, remainingGenericParams);
6814
- this.tables.counts[42] = remainingGenericParams.length;
6815
- if (remainingGenericParams.length === 0) this.tables.valid &= ~(1n << 42n);
6816
- this.genericParams = this.genericParams.filter((parameter) =>
6817
- !genericParamRids.has(parameter.rid)
6818
- );
6819
- for (const parameter of this.genericParams) {
6820
- parameter.rid = remapGenericParamRid(parameter.rid);
6821
- }
6822
- for (const constraint of this.genericParamConstraints) {
6823
- constraint.ownerRid = remapGenericParamRid(constraint.ownerRid);
6824
- }
6825
- }
6826
- if (genericParamConstraintRids.size > 0) {
6827
- const remainingConstraints = this.genericParamConstraints.filter((constraint) =>
6828
- !genericParamConstraintRids.has(constraint.rid)
6829
- );
6830
- remainingConstraints.forEach((constraint) => {
6831
- constraint.rid = remapGenericParamConstraintRid(constraint.rid);
6832
- });
6833
- this.genericParamConstraints.splice(
6834
- 0,
6835
- this.genericParamConstraints.length,
6836
- ...remainingConstraints
6837
- );
6838
- const remainingConstraintRows = genericParamConstraintRows.filter((constraint) =>
6839
- !genericParamConstraintRids.has(constraint.rid)
6840
- );
6841
- remainingConstraintRows.forEach((constraint) => {
6842
- constraint.rid = remapGenericParamConstraintRid(constraint.rid);
6843
- });
6844
- this.tables.rows.set(44, remainingConstraintRows);
6845
- this.tables.counts[44] = remainingConstraintRows.length;
6846
- if (remainingConstraintRows.length === 0) this.tables.valid &= ~(1n << 44n);
6847
- }
6848
- if (parameterRids.size > 0 || genericParamRids.size > 0) {
6849
- for (const attribute of this.customAttributes) {
6850
- if (attribute.parent?.table === 8 && !parameterRids.has(attribute.parent.rid)) {
6851
- attribute.parent = {
6852
- ...attribute.parent,
6853
- rid: remapParameterRid(attribute.parent.rid)
6854
- };
6855
- } else if (attribute.parent?.table === 42 &&
6856
- !genericParamRids.has(attribute.parent.rid)) {
6857
- attribute.parent = {
6858
- ...attribute.parent,
6859
- rid: remapGenericParamRid(attribute.parent.rid)
6860
- };
6861
- } else if (attribute.parent?.table === 44 &&
6862
- !genericParamConstraintRids.has(attribute.parent.rid)) {
6863
- attribute.parent = {
6864
- ...attribute.parent,
6865
- rid: remapGenericParamConstraintRid(attribute.parent.rid)
6866
- };
6867
- }
6868
- }
6869
- }
6870
- const remainingRows = rows.filter((row) => row.rid !== rid);
6871
- remainingRows.forEach((row, index) => {
6872
- row.rid = index + 1;
6873
- });
6874
- this.tables.rows.set(6, remainingRows);
6875
- this.tables.counts[6] = remainingRows.length;
6876
- if (remainingRows.length === 0) this.tables.valid &= ~(1n << 6n);
6877
- for (const type of this.types) {
6878
- type.methodRids = type.methodRids
6879
- .filter((methodRid) => methodRid !== rid)
6880
- .map((methodRid) => methodRid > rid ? methodRid - 1 : methodRid);
6881
- type.methods = type.methods.filter((candidate) => candidate.rid !== rid);
6882
- for (const candidate of type.methods) {
6883
- if (candidate.rid > rid) candidate.rid--;
6884
- }
6885
- }
6886
- this.methods.splice(rid - 1, 1);
6887
- this.methods.forEach((candidate, index) => {
6888
- candidate.rid = index + 1;
6889
- });
6890
- for (const parameter of this.genericParams) {
6891
- if (parameter.owner.table === 6 && parameter.owner.rid > rid) {
6892
- parameter.owner = { ...parameter.owner, rid: parameter.owner.rid - 1 };
6893
- }
6894
- }
6895
- for (const memberRef of this.memberRefs) {
6896
- if (memberRef.parent?.table === 6 && memberRef.parent.rid > rid) {
6897
- memberRef.parent = { ...memberRef.parent, rid: memberRef.parent.rid - 1 };
6898
- }
6899
- }
6900
- for (const methodSpec of this.methodSpecs) {
6901
- if (methodSpec.method?.table === 6 && methodSpec.method.rid > rid) {
6902
- methodSpec.method = { ...methodSpec.method, rid: methodSpec.method.rid - 1 };
6903
- }
6904
- }
6905
- for (const attribute of this.customAttributes) {
6906
- if (attribute.parent?.table === 6 && attribute.parent.rid > rid) {
6907
- attribute.parent = { ...attribute.parent, rid: attribute.parent.rid - 1 };
6908
- }
6909
- }
6910
- const remappedBodyCache = new Map();
6911
- for (const [methodRid, body] of this._bodyCache) {
6912
- if (methodRid === rid) continue;
6913
- remappedBodyCache.set(methodRid > rid ? methodRid - 1 : methodRid, body);
6914
- }
6915
- this._bodyCache = remappedBodyCache;
6916
- this._addedMethodBodies.delete(rid);
6917
- this._bodyCache.delete(rid);
6918
- this._metadataDirty = true;
6919
- return tokenMap;
6920
- }
6921
-
6922
- addParam({ owner, name = "", sequence, flags = 0 }) {
6923
- return this.#writeParam({ owner, name, sequence, flags }, false).rid;
6924
- }
6925
-
6926
- insertParam({ owner, name = "", sequence, flags = 0 }) {
6927
- return this.#writeParam({ owner, name, sequence, flags }, true);
6928
- }
6929
-
6930
- #writeParam({ owner, name = "", sequence, flags = 0 }, insertIntoOwner) {
6931
- this.#ensureEditable();
6932
- const ownerRid = metadataTableId(owner?.table) === 6 ? owner.rid : 0;
6933
- const method = this.methods[ownerRid - 1];
6934
- if (!Number.isInteger(ownerRid) || ownerRid < 1 || !method) {
6935
- throw new RangeError("Param owner must identify an existing MethodDef");
6936
- }
6937
- if (typeof name !== "string" || name.includes("\0")) {
6938
- throw new TypeError("Param name must be a null-free string");
5838
+ if (typeof name !== "string" || name.includes("\0")) {
5839
+ throw new TypeError("Param name must be a null-free string");
6939
5840
  }
6940
5841
  if (!Number.isInteger(flags) || flags < 0 || flags > 0xffff) {
6941
5842
  throw new RangeError("Param flags must be an unsigned 16-bit integer");
@@ -7256,252 +6157,7 @@ export class Assembly {
7256
6157
  }
7257
6158
 
7258
6159
  reorderPointerTable(pointerTable, targetRids) {
7259
- this.#ensureEditable();
7260
- const pointerTableId = metadataTableId(pointerTable);
7261
- const definitions = new Map([
7262
- [3, { targetTableId: 4, column: "Field", owners: this.types, list: "fieldRids", records: "fields" }],
7263
- [5, { targetTableId: 6, column: "Method", owners: this.types, list: "methodRids", records: "methods" }],
7264
- [7, {
7265
- targetTableId: 8,
7266
- column: "Param",
7267
- owners: this.methods,
7268
- list: "parameterRids",
7269
- records: "parameters"
7270
- }],
7271
- [19, { targetTableId: 20, column: "Event", owners: this.types, list: "eventRids", records: "events" }],
7272
- [22, {
7273
- targetTableId: 23,
7274
- column: "Property",
7275
- owners: this.types,
7276
- list: "propertyRids",
7277
- records: "properties"
7278
- }]
7279
- ]);
7280
- const definition = definitions.get(pointerTableId);
7281
- if (!definition) {
7282
- throw new TypeError("Pointer table must be FieldPtr, MethodPtr, ParamPtr, EventPtr, or PropertyPtr");
7283
- }
7284
- const allowsCrossOwnerFields = pointerTableId === 3;
7285
- const allowsCrossOwnerMethods = pointerTableId === 5;
7286
- const allowsCrossOwnerParameters = pointerTableId === 7;
7287
- const allowsCrossOwnerEvents = pointerTableId === 19;
7288
- const allowsCrossOwnerProperties = pointerTableId === 22;
7289
- if ((this.tables.valid & (1n << BigInt(pointerTableId))) === 0n) {
7290
- throw new UnsupportedFormatError(`${metadataTableNames[pointerTableId]} is not present`);
7291
- }
7292
- const pointerRows = getBijectivePointerRows(
7293
- this,
7294
- pointerTableId,
7295
- definition.targetTableId,
7296
- definition.column
7297
- );
7298
- if (!pointerRows) {
7299
- throw new FormatError(
7300
- `${metadataTableNames[pointerTableId]} must be a one-to-one mapping to ${metadataTableNames[definition.targetTableId]}`
7301
- );
7302
- }
7303
- const targetCount = this.tables.counts[definition.targetTableId] ?? 0;
7304
- if (!Array.isArray(targetRids) || targetRids.length !== targetCount) {
7305
- throw new RangeError("Pointer table order must contain every target row exactly once");
7306
- }
7307
- const newRids = [...targetRids];
7308
- const uniqueRids = new Set(newRids);
7309
- if (uniqueRids.size !== targetCount ||
7310
- newRids.some((rid) => !Number.isInteger(rid) || rid < 1 || rid > targetCount)) {
7311
- throw new RangeError("Pointer table order must contain every target row exactly once");
7312
- }
7313
-
7314
- const ownerGroups = definition.owners.map((owner) => owner[definition.list]);
7315
- const currentOwnerRids = ownerGroups.flat();
7316
- if (currentOwnerRids.length !== targetCount ||
7317
- new Set(currentOwnerRids).size !== targetCount) {
7318
- throw new FormatError(
7319
- `${metadataTableNames[definition.targetTableId]} ownership does not cover every row exactly once`
7320
- );
7321
- }
7322
- const currentOwnerByRid = new Map();
7323
- for (let index = 0; index < ownerGroups.length; index++) {
7324
- for (const rid of ownerGroups[index]) {
7325
- currentOwnerByRid.set(rid, definition.owners[index].rid);
7326
- }
7327
- }
7328
- const assignments = [];
7329
- let offset = 0;
7330
- const recordsByRid = new Map(
7331
- definition.owners.flatMap((owner) =>
7332
- owner[definition.records].map((record) => [record.rid, record])
7333
- )
7334
- );
7335
- for (let index = 0; index < definition.owners.length; index++) {
7336
- const owner = definition.owners[index];
7337
- const oldGroup = ownerGroups[index];
7338
- const nextGroup = newRids.slice(offset, offset + oldGroup.length);
7339
- offset += oldGroup.length;
7340
- const oldSet = new Set(oldGroup);
7341
- const movesRowsAcrossOwners = nextGroup.some((rid) => !oldSet.has(rid));
7342
- const allowsCrossOwnerRows = allowsCrossOwnerFields || allowsCrossOwnerMethods ||
7343
- allowsCrossOwnerParameters || allowsCrossOwnerEvents || allowsCrossOwnerProperties;
7344
- if (!allowsCrossOwnerRows && movesRowsAcrossOwners) {
7345
- throw new UnsupportedFormatError("Pointer reordering cannot change row ownership");
7346
- }
7347
- const nextRecords = nextGroup.map((rid) => recordsByRid.get(rid));
7348
- if (nextRecords.some((record) => !record)) {
7349
- throw new FormatError(`${metadataTableNames[definition.targetTableId]} ownership has no semantic record`);
7350
- }
7351
- const movedRecords = nextRecords.filter((record) =>
7352
- currentOwnerByRid.get(record.rid) !== owner.rid
7353
- );
7354
- if (allowsCrossOwnerFields) {
7355
- for (const record of movedRecords) {
7356
- const parsed = parseSignature(record.signature, { counts: this.tables.counts });
7357
- if (parsed.kind !== "field") {
7358
- throw new FormatError(`Field row ${record.rid} has a non-field signature`);
7359
- }
7360
- validateGenericVariableReferences(
7361
- parsed,
7362
- getGenericParameterArity(this.genericParams, 2, owner.rid),
7363
- this
7364
- );
7365
- if ((this.tables.rows.get(16) ?? []).some((layout) =>
7366
- layout.Field.rid === record.rid
7367
- ) && (owner.flags & 0x0018) !== 0x0010) {
7368
- throw new UnsupportedFormatError(
7369
- `Field row ${record.rid} has an explicit offset and requires an explicit-layout owner`
7370
- );
7371
- }
7372
- }
7373
- }
7374
- if (allowsCrossOwnerParameters && movesRowsAcrossOwners) {
7375
- const signature = parseSignature(owner.signature, { counts: this.tables.counts });
7376
- if (signature.kind !== "method") {
7377
- throw new FormatError(`MethodDef row ${owner.rid} has a non-method signature`);
7378
- }
7379
- const sequences = new Set();
7380
- for (const record of nextRecords) {
7381
- if (!Number.isInteger(record.sequence) || record.sequence < 0 ||
7382
- record.sequence > signature.parameters.length) {
7383
- throw new FormatError(
7384
- `Param row ${record.rid} sequence exceeds MethodDef row ${owner.rid}'s signature`
7385
- );
7386
- }
7387
- if (sequences.has(record.sequence)) {
7388
- throw new FormatError(
7389
- `MethodDef row ${owner.rid} would have duplicate Param sequence ${record.sequence}`
7390
- );
7391
- }
7392
- sequences.add(record.sequence);
7393
- }
7394
- }
7395
- if (allowsCrossOwnerMethods && movesRowsAcrossOwners) {
7396
- if ((owner.flags & (0x0080 | 0x0020)) === 0) {
7397
- throw new UnsupportedFormatError(
7398
- "Pointer reordering cannot move abstract methods to a non-abstract TypeDef"
7399
- );
7400
- }
7401
- for (const record of movedRecords) {
7402
- if (record.rva !== 0 || (record.flags & 0x0440) !== 0x0440 ||
7403
- record.genericParams.length > 0) {
7404
- throw new UnsupportedFormatError(
7405
- "Cross-owner MethodPtr reordering supports only bodyless, non-generic abstract virtual methods"
7406
- );
7407
- }
7408
- const signature = parseSignature(record.signature, { counts: this.tables.counts });
7409
- if (signature.kind !== "method") {
7410
- throw new FormatError(`MethodDef row ${record.rid} has a non-method signature`);
7411
- }
7412
- if ((signature.genericParameterCount ?? 0) > 0) {
7413
- throw new UnsupportedFormatError(
7414
- "Cross-owner MethodPtr reordering does not support generic methods"
7415
- );
7416
- }
7417
- validateGenericVariableReferences(
7418
- signature,
7419
- getGenericParameterArity(this.genericParams, 2, owner.rid),
7420
- this,
7421
- null,
7422
- signature.genericParameterCount ?? 0
7423
- );
7424
- const hasMethodSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
7425
- row.Method.rid === record.rid
7426
- );
7427
- const hasMethodImpl = (this.tables.rows.get(25) ?? []).some((row) =>
7428
- row.MethodBody.target?.table === 6 && row.MethodBody.target.rid === record.rid ||
7429
- row.MethodDeclaration.target?.table === 6 && row.MethodDeclaration.target.rid === record.rid
7430
- );
7431
- if (hasMethodSemantics || hasMethodImpl) {
7432
- throw new UnsupportedFormatError(
7433
- "Pointer reordering cannot change row ownership for methods with semantics or MethodImpl rows"
7434
- );
7435
- }
7436
- }
7437
- }
7438
- if (allowsCrossOwnerEvents && movesRowsAcrossOwners) {
7439
- for (const record of movedRecords) {
7440
- const hasSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
7441
- row.Association.target?.table === 20 && row.Association.target.rid === record.rid
7442
- );
7443
- if (hasSemantics) {
7444
- throw new UnsupportedFormatError(
7445
- "Pointer reordering cannot change row ownership for events with MethodSemantics rows"
7446
- );
7447
- }
7448
- if (record.eventType.table === 27) {
7449
- const typeArity = getGenericParameterArity(this.genericParams, 2, owner.rid);
7450
- const typeSpec = this.typeSpecs[record.eventType.rid - 1];
7451
- if (!typeSpec) {
7452
- throw new FormatError(`Event row ${record.rid} references missing TypeSpec row ${record.eventType.rid}`);
7453
- }
7454
- validateTypeSpecDefinitions(this, typeSpec.parsedSignature);
7455
- validateTypeSpecGenericContext(this, record.eventType.rid, typeArity);
7456
- }
7457
- }
7458
- }
7459
- if (allowsCrossOwnerProperties && movesRowsAcrossOwners) {
7460
- for (const record of movedRecords) {
7461
- const hasSemantics = (this.tables.rows.get(24) ?? []).some((row) =>
7462
- row.Association.target?.table === 23 && row.Association.target.rid === record.rid
7463
- );
7464
- if (hasSemantics) {
7465
- throw new UnsupportedFormatError(
7466
- "Pointer reordering cannot change row ownership for properties with MethodSemantics rows"
7467
- );
7468
- }
7469
- const signature = parseSignature(record.signature, { counts: this.tables.counts });
7470
- if (signature.kind !== "property") {
7471
- throw new FormatError(`Property row ${record.rid} has a non-property signature`);
7472
- }
7473
- validateGenericVariableReferences(
7474
- signature,
7475
- getGenericParameterArity(this.genericParams, 2, owner.rid),
7476
- this
7477
- );
7478
- }
7479
- }
7480
- assignments.push({ owner, nextGroup, nextRecords });
7481
- }
7482
- if (offset !== targetCount) {
7483
- throw new FormatError(
7484
- `${metadataTableNames[definition.targetTableId]} ownership does not cover every row exactly once`
7485
- );
7486
- }
7487
-
7488
- const nextPointerRows = newRids.map((rid, index) => ({
7489
- ...pointerRows[index],
7490
- rid: index + 1,
7491
- [definition.column]: {
7492
- raw: rid,
7493
- table: definition.targetTableId,
7494
- tableName: metadataTableNames[definition.targetTableId],
7495
- rid
7496
- }
7497
- }));
7498
- this.tables.rows.set(pointerTableId, nextPointerRows);
7499
- for (const assignment of assignments) {
7500
- assignment.owner[definition.list] = assignment.nextGroup;
7501
- assignment.owner[definition.records] = assignment.nextRecords;
7502
- }
7503
- this._metadataDirty = true;
7504
- return this;
6160
+ return this.#pointerTableEditor.reorderPointerTable.call(this, pointerTable, targetRids);
7505
6161
  }
7506
6162
 
7507
6163
  addField({ owner, name, flags = 0, signature }) {
@@ -8562,147 +7218,23 @@ export class Assembly {
8562
7218
  }
8563
7219
 
8564
7220
  setInstructionOperand(methodRid, instructionOffset, value) {
8565
- this.#ensureEditable();
8566
- const body = this.getMethodBody(methodRid);
8567
- if (!body) throw new FormatError("Method has no CIL body");
8568
- const instruction = body.instructions.find((candidate) => candidate.offset === instructionOffset);
8569
- if (!instruction) throw new RangeError(`No instruction begins at IL_${instructionOffset.toString(16)}`);
8570
- if (!instruction.operand) throw new TypeError("Instruction has no operand");
8571
-
8572
- if (instruction.operand.kind === "branch") {
8573
- this.#validateBranchTarget(body, value);
8574
- } else if (instruction.operand.kind === "switch") {
8575
- if (!Array.isArray(value)) throw new TypeError("Switch operand must be an array of IL target offsets");
8576
- for (const target of value) this.#validateBranchTarget(body, target);
8577
- } else if (instruction.opcode.name === "ldstr") {
8578
- if (!Number.isInteger(value) || (value >>> 24) !== 0x70) {
8579
- throw new TypeError("ldstr operand must be a 0x70-prefixed user-string token");
8580
- }
8581
- this.heaps.getUserString(value);
8582
- } else if (instruction.operand.kind === "token") {
8583
- if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
8584
- throw new RangeError("Metadata token must be an unsigned 32-bit integer");
8585
- }
8586
- const table = value >>> 24;
8587
- const rid = value & 0x00ffffff;
8588
- if (!allowedTokenTables(instruction.opcode.name).includes(table)) {
8589
- throw new FormatError(`Metadata table ${table} is not valid for ${instruction.opcode.name}`);
8590
- }
8591
- if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
8592
- throw new RangeError(`${instruction.opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
8593
- }
8594
- validateInstructionGenericContext(this, methodRid, instruction, value);
8595
- }
8596
-
8597
- if (instruction.operand.kind === "branch" && instruction.operand.targetOffset === value) return this;
8598
- if (instruction.operand.kind === "switch" &&
8599
- instruction.operand.targetOffsets.length === value.length &&
8600
- instruction.operand.targetOffsets.every((target, index) => target === value[index])) return this;
8601
- if (instruction.operand.kind !== "branch" && instruction.operand.kind !== "switch" &&
8602
- instruction.operand.value === value) return this;
8603
-
8604
- if (this._structuralBodies.has(methodRid) || this._addedMethodBodies.has(methodRid)) {
8605
- const state = this.#createStructuralState(methodRid);
8606
- const editableInstruction = state.instructions.find((candidate) => candidate.offset === instructionOffset);
8607
- updateStructuralOperand(state, editableInstruction, value);
8608
- this.#commitStructuralState(methodRid, state);
8609
- } else {
8610
- const patches = createOperandPatches(instruction, value);
8611
- for (const patch of patches) this._patches.push(patch);
8612
- instruction.operand = instruction.operand.kind === "branch"
8613
- ? { kind: "branch", targetOffset: value }
8614
- : instruction.operand.kind === "switch"
8615
- ? { kind: "switch", targetOffsets: [...value] }
8616
- : { ...instruction.operand, value };
8617
- }
8618
- return this;
7221
+ return this.#instructionEditor.setInstructionOperand(methodRid, instructionOffset, value);
8619
7222
  }
8620
7223
 
8621
7224
  setInstructionOpcode(methodRid, instructionOffset, opcodeNameOrCode) {
8622
- this.#ensureEditable();
8623
- const body = this.getMethodBody(methodRid);
8624
- if (!body) throw new FormatError("Method has no CIL body");
8625
- const instruction = body.instructions.find((candidate) => candidate.offset === instructionOffset);
8626
- if (!instruction) throw new RangeError(`No instruction begins at IL_${instructionOffset.toString(16)}`);
8627
- const opcode = listOpcodes().find((candidate) =>
8628
- candidate.name === opcodeNameOrCode || candidate.code === opcodeNameOrCode
8629
- );
8630
- if (!opcode) throw new RangeError(`Unknown CIL opcode ${opcodeNameOrCode}`);
8631
- const encoded = encodeOpcode(opcode);
8632
- if (encoded.length !== instruction.opcodeSize || opcode.operand !== instruction.opcode.operand) {
8633
- throw new FormatError("Opcode edit must preserve the opcode and operand widths");
8634
- }
8635
- if (opcode.code === instruction.opcode.code) return this;
8636
- if (instruction.operand?.kind === "token") {
8637
- if (opcode.name !== "ldstr") {
8638
- const table = instruction.operand.value >>> 24;
8639
- const rid = instruction.operand.value & 0x00ffffff;
8640
- if (!allowedTokenTables(opcode.name).includes(table)) {
8641
- throw new FormatError(`Metadata table ${table} is not valid for ${opcode.name}`);
8642
- }
8643
- if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
8644
- throw new RangeError(`${opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
8645
- }
8646
- validateInstructionGenericContext(
8647
- this, methodRid, { ...instruction, opcode }, instruction.operand.value
8648
- );
8649
- }
8650
- }
8651
- if (this._structuralBodies.has(methodRid) || this._addedMethodBodies.has(methodRid)) {
8652
- const state = this.#createStructuralState(methodRid);
8653
- const editableInstruction = state.instructions.find((candidate) => candidate.offset === instructionOffset);
8654
- editableInstruction.opcode = opcode;
8655
- layoutStructuralState(state);
8656
- this.#commitStructuralState(methodRid, state);
8657
- } else {
8658
- this._patches.push({ offset: instruction.opcodeOffset, bytes: encoded });
8659
- instruction.opcode = opcode;
8660
- }
8661
- return this;
7225
+ return this.#instructionEditor.setInstructionOpcode(methodRid, instructionOffset, opcodeNameOrCode);
8662
7226
  }
8663
7227
 
8664
7228
  insertInstruction(methodRid, beforeOffset, opcodeNameOrCode, operand) {
8665
- this.#ensureEditable();
8666
- const opcode = listOpcodes().find((candidate) =>
8667
- candidate.name === opcodeNameOrCode || candidate.code === opcodeNameOrCode
8668
- );
8669
- if (!opcode) throw new RangeError(`Unknown CIL opcode ${opcodeNameOrCode}`);
8670
- const state = this.#createStructuralState(methodRid);
8671
- const instruction = insertStructuralInstruction(state, beforeOffset, opcode, operand);
8672
- if (instruction.operand?.kind === "token" && opcode.name !== "ldstr") {
8673
- const token = instruction.operand.value;
8674
- const table = token >>> 24;
8675
- const rid = token & 0x00ffffff;
8676
- if (!allowedTokenTables(opcode.name).includes(table)) {
8677
- throw new FormatError(`Metadata table ${table} is not valid for ${opcode.name}`);
8678
- }
8679
- if (rid === 0 || rid > (this.tables.counts[table] ?? 0)) {
8680
- throw new RangeError(`${opcode.name} references missing ${metadataTableNames[table]} row ${rid}`);
8681
- }
8682
- validateInstructionGenericContext(this, methodRid, instruction, token);
8683
- }
8684
- this.#commitStructuralState(methodRid, state);
8685
- return instruction;
7229
+ return this.#instructionEditor.insertInstruction(methodRid, beforeOffset, opcodeNameOrCode, operand);
8686
7230
  }
8687
7231
 
8688
7232
  removeInstruction(methodRid, instructionOffset) {
8689
- this.#ensureEditable();
8690
- const state = this.#createStructuralState(methodRid);
8691
- const instruction = removeStructuralInstruction(state, instructionOffset);
8692
- this.#commitStructuralState(methodRid, state);
8693
- return instruction;
7233
+ return this.#instructionEditor.removeInstruction(methodRid, instructionOffset);
8694
7234
  }
8695
7235
 
8696
7236
  setMethodMaxStack(methodRid, maxStack) {
8697
- this.#ensureEditable();
8698
- if (!Number.isInteger(maxStack) || maxStack < 0 || maxStack > 0xffff) {
8699
- throw new RangeError("maxStack must be an unsigned 16-bit integer");
8700
- }
8701
- const state = this.#createStructuralState(methodRid);
8702
- state.maxStack = maxStack;
8703
- layoutStructuralState(state);
8704
- this.#commitStructuralState(methodRid, state);
8705
- return this;
7237
+ return this.#instructionEditor.setMethodMaxStack(methodRid, maxStack);
8706
7238
  }
8707
7239
 
8708
7240
  addMemberRef({ parent, name, signature }) {
@@ -14649,9 +13181,9 @@ export class Assembly {
14649
13181
  if (signature.rva === 0 && (this.cli.flags & 0x08) !== 0) {
14650
13182
  throw new FormatError("Strong-name-signed CLI header has no signature directory");
14651
13183
  }
14652
- const expectedSize = Math.ceil(privateKey.asymmetricKeyDetails.modulusLength / 8);
13184
+ const expectedSize = Math.ceil(privateKey.n.bitLength() / 8);
14653
13185
  const currentPublicKey = this.heaps.getBlob(assemblyRow.PublicKey);
14654
- const keyChanged = !Buffer.from(currentPublicKey).equals(publicKey);
13186
+ const keyChanged = !equalBytes(currentPublicKey, publicKey);
14655
13187
  const identityChanged = keyChanged ||
14656
13188
  assemblyRow.HashAlgId !== selectedHashAlgorithm ||
14657
13189
  (assemblyRow.Flags & 0x01) === 0;
@@ -14694,11 +13226,11 @@ export class Assembly {
14694
13226
  getStrongNameHashName(hashAlgorithm);
14695
13227
  const expectedPublicKey = encodeStrongNamePublicKey(privateKey, hashAlgorithm);
14696
13228
  const currentPublicKey = this.heaps.getBlob(assemblyRow.PublicKey);
14697
- if (!Buffer.from(currentPublicKey).equals(expectedPublicKey)) {
13229
+ if (!equalBytes(currentPublicKey, expectedPublicKey)) {
14698
13230
  throw new FormatError("Strong-name private key does not match the Assembly public key");
14699
13231
  }
14700
13232
  const signature = this.cli.strongNameSignature;
14701
- const expectedSize = Math.ceil(privateKey.asymmetricKeyDetails.modulusLength / 8);
13233
+ const expectedSize = Math.ceil(privateKey.n.bitLength() / 8);
14702
13234
  if ((signature.rva === 0) !== (signature.size === 0)) {
14703
13235
  throw new FormatError("Strong-name signature directory has only one of RVA and size set");
14704
13236
  }
@@ -14765,7 +13297,8 @@ export class Assembly {
14765
13297
  }
14766
13298
 
14767
13299
  toBuffer() {
14768
- return Buffer.from(this.serialize());
13300
+ const bytes = this.serialize();
13301
+ return typeof Buffer === "undefined" ? bytes : Buffer.from(bytes);
14769
13302
  }
14770
13303
  }
14771
13304