DVX_GUI/apps/dvxbasic/compiler/strip.c

111 lines
2.9 KiB
C

// strip.c -- Release build stripping
//
// Removes debug information from a compiled module:
// - Clears debug variable info (names, scopes, types)
// - Clears debug UDT definitions
// - Mangles procedure names that aren't needed for runtime dispatch.
// The form runtime dispatches events by name (Control_Event pattern)
// and SetEvent looks up handlers by name at runtime, so those proc
// names must be preserved. Everything else becomes F1, F2, F3...
//
// OP_LINE removal is deferred to a future version (requires
// bytecode compaction and offset rewriting).
#include "strip.h"
#include "../runtime/values.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Events fired by name via basFormRtFireEvent* in formrt.c. Any proc
// ending in "_<EventName>" must keep its name so the dispatcher can
// find it.
static const char *sEventSuffixes[] = {
"Load", "Unload", "QueryUnload", "Resize", "Activate", "Deactivate",
"Click", "DblClick", "Change", "Timer",
"GotFocus", "LostFocus",
"KeyPress", "KeyDown", "KeyUp",
"MouseDown", "MouseUp", "MouseMove",
"Scroll", "Reposition", "Validate",
NULL
};
static bool nameEndsWithEventSuffix(const char *name) {
const char *underscore = strrchr(name, '_');
if (!underscore) {
return false;
}
const char *suffix = underscore + 1;
for (int32_t i = 0; sEventSuffixes[i]; i++) {
if (strcasecmp(suffix, sEventSuffixes[i]) == 0) {
return true;
}
}
return false;
}
static bool nameInConstantPool(const BasModuleT *mod, const char *name) {
for (int32_t i = 0; i < mod->constCount; i++) {
const BasStringT *s = mod->constants[i];
if (s && strcasecmp(s->data, name) == 0) {
return true;
}
}
return false;
}
void basStripModule(BasModuleT *mod) {
if (!mod) {
return;
}
// Clear debug variable info
free(mod->debugVars);
mod->debugVars = NULL;
mod->debugVarCount = 0;
// Clear debug UDT definitions
if (mod->debugUdtDefs) {
for (int32_t i = 0; i < mod->debugUdtDefCount; i++) {
free(mod->debugUdtDefs[i].fields);
}
free(mod->debugUdtDefs);
mod->debugUdtDefs = NULL;
mod->debugUdtDefCount = 0;
}
// Mangle proc names. Keep names that are needed for runtime name
// lookup: event handlers (Control_Event pattern) and any name
// referenced as a string constant (e.g. SetEvent's target name).
int32_t nextMangled = 1;
for (int32_t i = 0; i < mod->procCount; i++) {
BasProcEntryT *proc = &mod->procs[i];
if (proc->name[0] == '\0') {
continue;
}
if (nameEndsWithEventSuffix(proc->name)) {
continue;
}
if (nameInConstantPool(mod, proc->name)) {
continue;
}
snprintf(proc->name, sizeof(proc->name), "F%ld", (long)nextMangled++);
}
}