Make Destructor Offset Code Less Dumb

This commit is contained in:
TheBrokenRail 2024-05-03 01:13:51 -04:00
parent 83b7e6db98
commit dcc35de95c
2 changed files with 43 additions and 28 deletions

View File

@ -12,7 +12,6 @@ export class Struct {
readonly #dependencies: string[]; readonly #dependencies: string[];
readonly #staticProperties: StaticProperty[]; readonly #staticProperties: StaticProperty[];
#directParent: string | null; #directParent: string | null;
#vtableDestructorOffset: number;
// Constructor // Constructor
constructor(name: string) { constructor(name: string) {
@ -24,7 +23,6 @@ export class Struct {
this.#dependencies = []; this.#dependencies = [];
this.#staticProperties = []; this.#staticProperties = [];
this.#directParent = null; this.#directParent = null;
this.#vtableDestructorOffset = 0;
} }
// Dependencies // Dependencies
@ -38,17 +36,15 @@ export class Struct {
// Ensure VTable Exists // Ensure VTable Exists
ensureVTable() { ensureVTable() {
if (this.#vtable === null) { if (this.#vtable === null) {
this.#vtable = new VTable(this.#name, this.#vtableDestructorOffset); this.#vtable = new VTable(this.#name);
this.addProperty(this.#vtable.property); this.addProperty(this.#vtable.property);
} }
} }
// Set VTable Destructor Offset // Set VTable Destructor Offset
setVTableDestructorOffset(offset: number) { setVTableDestructorOffset(offset: number) {
if (this.#vtable) { this.ensureVTable();
throw new Error('VTable Already Created'); this.#vtable!.setDestructorOffset(offset);
}
this.#vtableDestructorOffset = offset;
} }
// Setters // Setters

View File

@ -3,25 +3,22 @@ import { Method } from './method';
import { Property } from './property'; import { Property } from './property';
export class VTable { export class VTable {
readonly #name: string; readonly #self: string;
#address: number | null; #address: number | null;
#size: number | null; #size: number | null;
readonly #methods: Method[]; readonly #methods: Method[];
readonly property: Property; readonly property: Property;
#destructorOffset: number;
// Constructor // Constructor
constructor(name: string, destructorOffset: number) { constructor(self: string) {
this.#name = name; this.#self = self;
this.#address = null; this.#address = null;
this.#size = null; this.#size = null;
this.#methods = []; this.#methods = [];
// Add Destructors (https://stackoverflow.com/a/17960941) this.#destructorOffset = 0;
const destructor_return = `${name} *`;
const destructor_args = `(${getSelfArg(name)})`;
this.add(new Method(name, 'destructor_complete', destructor_return, destructor_args, 0x0 + destructorOffset, false));
this.add(new Method(name, 'destructor_deleting', destructor_return, destructor_args, 0x4 + destructorOffset, false));
// Create Property // Create Property
this.property = new Property(0, this.#getName() + ' *', 'vtable', this.#name); this.property = new Property(0, this.#getName() + ' *', 'vtable', this.#self);
} }
// Setters // Setters
@ -31,9 +28,12 @@ export class VTable {
setSize(size: number) { setSize(size: number) {
this.#size = size; this.#size = size;
} }
setDestructorOffset(destructorOffset: number) {
this.#destructorOffset = destructorOffset;
}
// Add To VTable // Add To VTable
add(method: Method) { #add(target: Method[], method: Method) {
// Check Offset // Check Offset
const offset = method.address; const offset = method.address;
if ((offset % POINTER_SIZE) !== 0) { if ((offset % POINTER_SIZE) !== 0) {
@ -41,15 +41,18 @@ export class VTable {
} }
// Add // Add
const index = offset / POINTER_SIZE; const index = offset / POINTER_SIZE;
if (this.#methods[index]) { if (target[index]) {
throw new Error(`Duplicate Virtual Method At Offset: ${toHex(offset)}`); throw new Error(`Duplicate Virtual Method At Offset: ${toHex(offset)}`);
} }
this.#methods[index] = method; target[index] = method;
}
add(method: Method) {
this.#add(this.#methods, method);
} }
// Get Structure Name // Get Structure Name
#getName() { #getName() {
return this.#name + '_vtable'; return this.#self + '_vtable';
} }
// Check // Check
@ -67,6 +70,20 @@ export class VTable {
} }
} }
// Get Full Methods Table
#getMethods() {
// Copy Array
const out = [];
out.push(...this.#methods);
// Add Destructors (https://stackoverflow.com/a/17960941)
const destructor_return = `${this.#self} *`;
const destructor_args = `(${getSelfArg(this.#self)})`;
this.#add(out, new Method(this.#self, 'destructor_complete', destructor_return, destructor_args, 0x0 + this.#destructorOffset, false));
this.#add(out, new Method(this.#self, 'destructor_deleting', destructor_return, destructor_args, 0x4 + this.#destructorOffset, false));
// Return
return out;
}
// Generate Header Code // Generate Header Code
generate(directParent: string | null) { generate(directParent: string | null) {
let out = ''; let out = '';
@ -75,8 +92,9 @@ export class VTable {
this.#check(); this.#check();
// Method Prototypes // Method Prototypes
for (let i = 0; i < this.#methods.length; i++) { const methods = this.#getMethods();
const info = this.#methods[i]; for (let i = 0; i < methods.length; i++) {
const info = methods[i];
if (info) { if (info) {
out += info.generateTypedef(); out += info.generateTypedef();
} }
@ -85,10 +103,10 @@ export class VTable {
// Structure // Structure
out += `typedef struct ${this.#getName()} ${this.#getName()};\n`; out += `typedef struct ${this.#getName()} ${this.#getName()};\n`;
out += `struct ${this.#getName()} {\n`; out += `struct ${this.#getName()} {\n`;
for (let i = 0; i < this.#methods.length; i++) { for (let i = 0; i < methods.length; i++) {
let name = `unknown${i}`; let name = `unknown${i}`;
let type = 'void *'; let type = 'void *';
const info = this.#methods[i]; const info = methods[i];
if (info) { if (info) {
name = info.shortName; name = info.shortName;
type = info.getType() + ' '; type = info.getType() + ' ';
@ -107,8 +125,8 @@ export class VTable {
// Base // Base
out += `extern ${this.#getName()} *${this.#getName()}_base;\n`; out += `extern ${this.#getName()} *${this.#getName()}_base;\n`;
// Methods // Methods
for (let i = 0; i < this.#methods.length; i++) { for (let i = 0; i < methods.length; i++) {
const info = this.#methods[i]; const info = methods[i];
if (info) { if (info) {
const type = `${info.getType()} *`; const type = `${info.getType()} *`;
out += `extern ${type}${info.getName()}_vtable_addr;\n`; out += `extern ${type}${info.getName()}_vtable_addr;\n`;
@ -140,8 +158,9 @@ export class VTable {
init += `${INDENT}${this.#getName()}_base = (${this.#getName()} *) ${toHex(this.#address)};\n`; init += `${INDENT}${this.#getName()}_base = (${this.#getName()} *) ${toHex(this.#address)};\n`;
declarations += `${this.#getName()} *${this.#getName()}_base;\n`; declarations += `${this.#getName()} *${this.#getName()}_base;\n`;
// Methods // Methods
for (let i = 0; i < this.#methods.length; i++) { const methods = this.#getMethods();
const info = this.#methods[i]; for (let i = 0; i < methods.length; i++) {
const info = methods[i];
if (info) { if (info) {
const vtableAddress = this.#address + (i * POINTER_SIZE); const vtableAddress = this.#address + (i * POINTER_SIZE);
const type = `${info.getType()} *`; const type = `${info.getType()} *`;