From 6945862ffcd9c00636f9dd858b0d38a96a1b15bc Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Sat, 7 Dec 2019 17:41:36 +0800 Subject: [PATCH 1/4] fix: bitmask overflow better handle global --- src/compiler/compile/render_dom/Renderer.ts | 66 +++++++++++-------- .../samples/bitmask-overflow-2/_config.js | 3 + .../samples/bitmask-overflow-2/main.svelte | 35 ++++++++++ 3 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 test/runtime/samples/bitmask-overflow-2/_config.js create mode 100644 test/runtime/samples/bitmask-overflow-2/main.svelte diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 6de1c92f0794..1f6550e2b489 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -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; @@ -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 bitmask; - 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; @@ -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() { diff --git a/test/runtime/samples/bitmask-overflow-2/_config.js b/test/runtime/samples/bitmask-overflow-2/_config.js new file mode 100644 index 000000000000..0b637912923f --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-2/_config.js @@ -0,0 +1,3 @@ +export default { + error: `potato is not defined`, +}; \ No newline at end of file diff --git a/test/runtime/samples/bitmask-overflow-2/main.svelte b/test/runtime/samples/bitmask-overflow-2/main.svelte new file mode 100644 index 000000000000..10fa1bd5e258 --- /dev/null +++ b/test/runtime/samples/bitmask-overflow-2/main.svelte @@ -0,0 +1,35 @@ + +

{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}

\ No newline at end of file From 3178e31571e42f79c8340a3856611f3801b26e1f Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 9 Dec 2019 22:32:39 +0800 Subject: [PATCH 2/4] code review --- src/compiler/compile/render_dom/Renderer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 1f6550e2b489..85a460b20e50 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -210,7 +210,7 @@ export default class Renderer { names.forEach((name) => { const member = renderer.context_lookup.get(name); - if (!member) return bitmask; + if (!member) return; if (member.index.value === -1) { throw new Error(`unset index`); From 66341cad2583a0fc364c49b88e5112466398164c Mon Sep 17 00:00:00 2001 From: Conduitry Date: Mon, 9 Dec 2019 09:48:56 -0500 Subject: [PATCH 3/4] tidy --- src/compiler/compile/render_dom/Renderer.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 85a460b20e50..5e4f6a34dc87 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -225,7 +225,6 @@ export default class Renderer { bitmask[i].n |= n; bitmask[i].names.push(name); }); - return bitmask; }; let operator; @@ -241,7 +240,7 @@ export default class Renderer { // this indirection was unnecessary if (!bitmask) { bitmask = get_bitmask(); - + if (!bitmask.length) { ({ operator, left, right } = x`${dirty} & /*${names.join(', ')}*/ 0` as BinaryExpression); } else if (renderer.context_overflow) { @@ -250,7 +249,7 @@ export default class Renderer { .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); From 5d0aff8b3e4495bc2db69707a6e0007431408068 Mon Sep 17 00:00:00 2001 From: Tan Li Hau Date: Mon, 9 Dec 2019 22:53:00 +0800 Subject: [PATCH 4/4] fix after tidy --- src/compiler/compile/render_dom/Renderer.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index 5e4f6a34dc87..29389ed3c3d8 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -225,6 +225,7 @@ export default class Renderer { bitmask[i].n |= n; bitmask[i].names.push(name); }); + return bitmask; }; let operator;