From 746b3b7c3e429761fcd4afbab07e83352c4865bd Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 22 Nov 2022 16:08:12 +0100 Subject: [PATCH 1/2] Use proper flows when compiling switch statements --- src/compiler.ts | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 0ee4365ecb..2140ed090e 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2825,15 +2825,16 @@ export class Compiler extends DiagnosticEmitter { // nest blocks in order let currentBlock = module.block(`case0|${context}`, breaks, TypeRef.None); - let commonCategorical = FlowFlags.AnyCategorical; - let commonConditional = 0; + let fallThroughFlow: Flow | null = null; + let commonBreakingFlow: Flow | null = null; for (let i = 0; i < numCases; ++i) { let case_ = cases[i]; let statements = case_.statements; let numStatements = statements.length; - // Each switch case initiates a new branch + // Can get here by matching the case or by fall-through let innerFlow = outerFlow.fork(); + if (fallThroughFlow) innerFlow.inheritBranch(fallThroughFlow); this.currentFlow = innerFlow; let breakLabel = `break|${context}`; innerFlow.breakLabel = breakLabel; @@ -2843,38 +2844,38 @@ export class Compiler extends DiagnosticEmitter { let stmts = new Array(1 + numStatements); stmts[0] = currentBlock; let count = 1; - let terminates = false; + let possiblyFallsThrough = true; for (let j = 0; j < numStatements; ++j) { let stmt = this.compileStatement(statements[j]); if (getExpressionId(stmt) != ExpressionId.Nop) { stmts[count++] = stmt; } if (innerFlow.isAny(FlowFlags.Terminates | FlowFlags.Breaks)) { - if (innerFlow.is(FlowFlags.Terminates)) terminates = true; + possiblyFallsThrough = false; break; } } stmts.length = count; - if (terminates || isLast || innerFlow.isAny(FlowFlags.Breaks | FlowFlags.ConditionallyBreaks)) { - commonCategorical &= innerFlow.flags; + fallThroughFlow = possiblyFallsThrough ? innerFlow : null; + let possiblyBreaks = innerFlow.isAny(FlowFlags.Breaks | FlowFlags.ConditionallyBreaks); + innerFlow.unset(FlowFlags.Breaks | FlowFlags.ConditionallyBreaks); // clear + if (possiblyBreaks || (isLast && possiblyFallsThrough)) { + if (commonBreakingFlow) commonBreakingFlow.inheritBranch(innerFlow); + else commonBreakingFlow = innerFlow; } - - commonConditional |= innerFlow.deriveConditionalFlags(); - - // Switch back to the parent flow - innerFlow.unset( - FlowFlags.Breaks | - FlowFlags.ConditionallyBreaks - ); this.currentFlow = outerFlow; currentBlock = module.block(nextLabel, stmts, TypeRef.None); // must be a labeled block } outerFlow.popBreakLabel(); - // If the switch has a default (guaranteed to handle any value), propagate common flags - if (defaultIndex >= 0) outerFlow.flags |= commonCategorical & ~FlowFlags.Breaks; - outerFlow.flags |= commonConditional & ~FlowFlags.ConditionallyBreaks; - // TODO: what about local states? + // If the switch has a default, we only get past through a breaking flow + if (defaultIndex >= 0) { + if (commonBreakingFlow) outerFlow.inherit(commonBreakingFlow); + else outerFlow.set(FlowFlags.Terminates); + // Otherwise either skipping or any breaking flow can get past + } else if (commonBreakingFlow) { + outerFlow.inheritBranch(commonBreakingFlow); + } return currentBlock; } From 66ff86224150efa2d2801b65c694d561c8136472 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 22 Nov 2022 16:27:53 +0100 Subject: [PATCH 2/2] breaking flows are mutual --- src/compiler.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler.ts b/src/compiler.ts index 2140ed090e..20aae02762 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -2826,7 +2826,7 @@ export class Compiler extends DiagnosticEmitter { // nest blocks in order let currentBlock = module.block(`case0|${context}`, breaks, TypeRef.None); let fallThroughFlow: Flow | null = null; - let commonBreakingFlow: Flow | null = null; + let mutualBreakingFlow: Flow | null = null; for (let i = 0; i < numCases; ++i) { let case_ = cases[i]; let statements = case_.statements; @@ -2860,21 +2860,21 @@ export class Compiler extends DiagnosticEmitter { let possiblyBreaks = innerFlow.isAny(FlowFlags.Breaks | FlowFlags.ConditionallyBreaks); innerFlow.unset(FlowFlags.Breaks | FlowFlags.ConditionallyBreaks); // clear if (possiblyBreaks || (isLast && possiblyFallsThrough)) { - if (commonBreakingFlow) commonBreakingFlow.inheritBranch(innerFlow); - else commonBreakingFlow = innerFlow; + if (mutualBreakingFlow) mutualBreakingFlow.inheritMutual(mutualBreakingFlow, innerFlow); + else mutualBreakingFlow = innerFlow; } this.currentFlow = outerFlow; currentBlock = module.block(nextLabel, stmts, TypeRef.None); // must be a labeled block } outerFlow.popBreakLabel(); - // If the switch has a default, we only get past through a breaking flow + // If the switch has a default, we only get past through any breaking flow if (defaultIndex >= 0) { - if (commonBreakingFlow) outerFlow.inherit(commonBreakingFlow); + if (mutualBreakingFlow) outerFlow.inherit(mutualBreakingFlow); else outerFlow.set(FlowFlags.Terminates); // Otherwise either skipping or any breaking flow can get past - } else if (commonBreakingFlow) { - outerFlow.inheritBranch(commonBreakingFlow); + } else if (mutualBreakingFlow) { + outerFlow.inheritBranch(mutualBreakingFlow); } return currentBlock; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy