Skip to content

Commit 1ff8603

Browse files
committed
perf: optimize Bitmapset validity checking
1 parent fba12e6 commit 1ff8603

File tree

1 file changed

+39
-96
lines changed

1 file changed

+39
-96
lines changed

src/variables.ts

Lines changed: 39 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -40,47 +40,6 @@ export class NodeVarRegistry {
4040
*/
4141
bmsRefs = new Map<string, constants.BitmapsetReference>(constants.getWellKnownBitmapsetReferences());
4242

43-
/*
44-
* Update stored node types for internal usage from provided
45-
* node tag file. i.e. `nodes.h' or `nodetags.h'.
46-
*/
47-
updateNodeTypesFromFile(file: vscode.TextDocument) {
48-
let added = 0;
49-
for (let lineNo = 0; lineNo < file.lineCount; lineNo++) {
50-
/*
51-
* NodeTag enum value has following representation:
52-
*
53-
* [spaces] T_*tag_name* [= *number*],
54-
*
55-
* We must obtain only *tag_name* part, because 'T_' prefix
56-
* is constant and not important and *number* also not
57-
* important because we must focus on words, not numbers - if
58-
* there was garbage in structure, Node->type will be random numbers.
59-
* That is how we find garbage.
60-
*/
61-
const line = file.lineAt(lineNo);
62-
if (line.isEmptyOrWhitespace) {
63-
continue;
64-
}
65-
66-
const text = line.text.trim();
67-
if (!text.startsWith('T_')) {
68-
continue;
69-
}
70-
71-
const tag = text.replace(',', '')
72-
.replace('T_', '')
73-
.split(' ', 1)[0];
74-
if (tag.trim() === '') {
75-
continue;
76-
}
77-
78-
this.nodeTags.add(tag);
79-
added++;
80-
}
81-
return added;
82-
}
83-
8443
addAliases(aliases: AliasInfo[]) {
8544
aliases.forEach(a => {
8645
this.aliases.set(a.alias.trim(), a.type.trim());
@@ -4081,56 +4040,8 @@ class BitmapSetSpecialMember extends NodeVariable {
40814040
super('Bitmapset', args);
40824041
}
40834042

4084-
async isValidSet(): Promise<boolean> {
4085-
/*
4086-
* First, validate NodeTag. BitmapSetSpecialMember could be
4087-
* created using dumb type check, without actual NodeTag
4088-
* checking. So we do it here
4089-
*/
4090-
if (this.context.hasBmsNodeTag) {
4091-
try {
4092-
const tag = await this.evaluate(`((Bitmapset *)${this.getPointer()})->type`);
4093-
if (tag.result !== 'T_Bitmapset') {
4094-
if (!utils.isValidIdentifier(tag.result)) {
4095-
/* Do not track NodeTag anymore and perform check again */
4096-
this.context.hasBmsNodeTag = false;
4097-
return await this.isValidSet();
4098-
} else {
4099-
/* Tags do not match */
4100-
return false;
4101-
}
4102-
}
4103-
} catch (err) {
4104-
if (!(err instanceof EvaluationError)) {
4105-
throw err;
4106-
}
4107-
4108-
if (err.message.indexOf('no member') === -1) {
4109-
throw err;
4110-
}
4111-
4112-
/* CodeLLDB path */
4113-
this.context.hasBmsNodeTag = false;
4114-
return await this.isValidSet();
4115-
}
4116-
} else {
4117-
/*
4118-
* If we do not have NodeTag, then try to check that we can deref
4119-
* pointer (means that pointer is valid).
4120-
* 'nwords' member is only available option in this case.
4121-
* If output is empty, then pointer is invalid.
4122-
*
4123-
* Also, pointer may give valid (at first glance) result,
4124-
* but it contains garbage and value will be too large - we
4125-
* check this too. 50 seems big enough to start worrying about.
4126-
*/
4127-
const result = await this.evaluate(`((Bitmapset *)${this.getPointer()})->nwords`);
4128-
const nwords = Number(result.result);
4129-
if (!(Number.isInteger(nwords) && nwords < 50)) {
4130-
return false;
4131-
}
4132-
}
4133-
4043+
async isValidSet(members: Variable[]): Promise<boolean> {
4044+
/* This check is enough (if it exists) */
41344045
if (this.context.hasBmsIsValidSet) {
41354046
const expression = `bms_is_valid_set((Bitmapset *)${this.getPointer()})`;
41364047
try {
@@ -4151,6 +4062,34 @@ class BitmapSetSpecialMember extends NodeVariable {
41514062
return true;
41524063
}
41534064
}
4065+
4066+
/* Fallback checking children members for validity/look normal */
4067+
4068+
if (this.context.hasBmsNodeTag) {
4069+
/* Check NodeTag is the most straight-forward approach */
4070+
const nodeTag = members.find(m => m.name === 'type');
4071+
if (nodeTag) {
4072+
return nodeTag.value === 'T_Bitmapset';
4073+
}
4074+
4075+
this.context.hasBmsNodeTag = false;
4076+
}
4077+
4078+
/* If we do not have NodeTag, then check that member values looks normally */
4079+
const nwords = members.find(m => m.name === 'nwords');
4080+
if (!nwords) {
4081+
return false;
4082+
}
4083+
4084+
const n = Number(nwords.value);
4085+
/*
4086+
* For 64-bit system even 20 is large number: 10 * 64 = 640.
4087+
* Human will not be able to handle such amount of data.
4088+
*/
4089+
const maxNWords = 10;
4090+
if (Number.isNaN(n) || maxNWords <= n) {
4091+
return false;
4092+
}
41544093

41554094
return true;
41564095
}
@@ -4188,7 +4127,7 @@ class BitmapSetSpecialMember extends NodeVariable {
41884127
return true;
41894128
}
41904129

4191-
async getSetElements(): Promise<number[] | undefined> {
4130+
async getSetElements(members: Variable[]): Promise<number[] | undefined> {
41924131
/*
41934132
* Must check we do not have breakpoints set in `bms_next_member`.
41944133
* Otherwise, we will get infinite recursion and backend will crash.
@@ -4200,9 +4139,12 @@ class BitmapSetSpecialMember extends NodeVariable {
42004139
/*
42014140
* We MUST check validity of set, because, otherwise,
42024141
* `Assert` will fail or SEGFAULT si thrown and whole
4203-
* backend will crash
4142+
* backend will crash.
4143+
*
4144+
* Check performed using `bms_is_valid_set`, but if it
4145+
* is missing, then check members to look normally.
42044146
*/
4205-
if (!await this.isValidSet()) {
4147+
if (!await this.isValidSet(members)) {
42064148
return;
42074149
}
42084150

@@ -4343,12 +4285,12 @@ class BitmapSetSpecialMember extends NodeVariable {
43434285
const members = await Variable.getVariables(this.variablesReference,
43444286
this.frameId, this.context,
43454287
this);
4346-
if (!members) {
4288+
if (!members?.length) {
43474289
return members;
43484290
}
43494291

43504292
/* Add special members to explore set elements */
4351-
const setMembers = await this.getSetElements();
4293+
const setMembers = await this.getSetElements(members);
43524294
if (setMembers !== undefined) {
43534295
const ref = await this.getBmsRef();
43544296

@@ -4357,6 +4299,7 @@ class BitmapSetSpecialMember extends NodeVariable {
43574299
members.push(new BitmapSetSpecialMember.BmsArrayVariable(this, setMembers, ref));
43584300
}
43594301

4302+
/* Do not show 'words' flexible array member */
43604303
return members.filter(v => v.name !== 'words');
43614304
}
43624305

0 commit comments

Comments
 (0)