Skip to content

fix: bitmask overflow better handle global #4063

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 39 additions & 27 deletions src/compiler/compile/render_dom/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ interface ContextMember {
priority: number;
}

type BitMasks = Array<{
n: number;
names: string[];
}>;

export default class Renderer {
component: Component; // TODO Maybe Renderer shouldn't know about Component?
options: CompileOptions;
Expand Down Expand Up @@ -199,26 +204,29 @@ export default class Renderer {
? x`$$self.$$.dirty`
: x`#dirty`) as Identifier | MemberExpression;

const get_bitmask = () => names.reduce((bitmask, name) => {
const member = renderer.context_lookup.get(name);

if (!member) return bitmask;
let bitmask;
const get_bitmask = () => {
const bitmask: BitMasks = [];
names.forEach((name) => {
const member = renderer.context_lookup.get(name);

if (member.index.value === -1) {
throw new Error(`unset index`);
}
if (!member) return;

const value = member.index.value as number;
const i = (value / 31) | 0;
const n = 1 << (value % 31);
if (member.index.value === -1) {
throw new Error(`unset index`);
}

if (!bitmask[i]) bitmask[i] = { n: 0, names: [] };
const value = member.index.value as number;
const i = (value / 31) | 0;
const n = 1 << (value % 31);

bitmask[i].n |= n;
bitmask[i].names.push(name);
if (!bitmask[i]) bitmask[i] = { n: 0, names: [] };

bitmask[i].n |= n;
bitmask[i].names.push(name);
});
return bitmask;
}, Array((this.context.length / 31) | 0).fill(null));
};

let operator;
let left;
Expand All @@ -231,21 +239,25 @@ export default class Renderer {
// to lazily create the node. TODO would be better if
// context was determined before rendering, so that
// this indirection was unnecessary

const bitmask = get_bitmask();

if (renderer.context_overflow) {
const expression = bitmask
.map((b, i) => ({ b, i }))
.filter(({ b }) => b)
.map(({ b, i }) => x`${dirty}[${i}] & /*${b.names.join(', ')}*/ ${b.n}`)
.reduce((lhs, rhs) => x`${lhs} | ${rhs}`);

({ operator, left, right } = expression);
} else {
({ operator, left, right } = x`${dirty} & /*${names.join(', ')}*/ ${bitmask[0] ? bitmask[0].n : 0}` as BinaryExpression); // TODO the `: 0` case should never apply
if (!bitmask) {
bitmask = get_bitmask();

if (!bitmask.length) {
({ operator, left, right } = x`${dirty} & /*${names.join(', ')}*/ 0` as BinaryExpression);
} else if (renderer.context_overflow) {
const expression = bitmask
.map((b, i) => ({ b, i }))
.filter(({ b }) => b)
.map(({ b, i }) => x`${dirty}[${i}] & /*${b.names.join(', ')}*/ ${b.n}`)
.reduce((lhs, rhs) => x`${lhs} | ${rhs}`);

({ operator, left, right } = expression as BinaryExpression);
} else {
({ operator, left, right } = x`${dirty} & /*${names.join(', ')}*/ ${bitmask[0].n}` as BinaryExpression);
}
}


return 'BinaryExpression';
},
get operator() {
Expand Down
3 changes: 3 additions & 0 deletions test/runtime/samples/bitmask-overflow-2/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
error: `potato is not defined`,
};
35 changes: 35 additions & 0 deletions test/runtime/samples/bitmask-overflow-2/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<script>
export let x1;
export let x2;
export let x3;
export let x4;
export let x5;
export let x6;
export let x7;
export let x8;
export let x9;
export let x10;
export let x11;
export let x12;
export let x13;
export let x14;
export let x15;
export let x16;
export let x17;
export let x18;
export let x19;
export let x20;
export let x21;
export let x22;
export let x23;
export let x24;
export let x25;
export let x26;
export let x27;
export let x28;
export let x29;
export let x30;
export let x31;
export let x32;
</script>
<p {...potato}>{x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 + x30 + x31 + x32}</p>