Skip to content

Commit 439428b

Browse files
committed
Replace --ignoreUnchecked with --uncheckedBehavior
This new option allows users to use unchecked() as usual, ignore it entirely, and *force unchecked contexts everywhere*. Ignoring unchecked is useful for debugging, and, if you're certain you want to accept the risk, forcing unchecked could be beneficial for performance.
1 parent a96c794 commit 439428b

File tree

6 files changed

+53
-15
lines changed

6 files changed

+53
-15
lines changed

cli/index.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,20 @@ export async function main(argv, options) {
295295
}
296296

297297
// Set up options
298-
let program, runtime;
298+
let program, runtime, uncheckedBehavior;
299299
const compilerOptions = assemblyscript.newOptions();
300300
switch (opts.runtime) {
301301
case "stub": runtime = 0; break;
302302
case "minimal": runtime = 1; break;
303303
/* incremental */
304304
default: runtime = 2; break;
305305
}
306+
switch (opts.uncheckedBehavior) {
307+
/* default */
308+
default: uncheckedBehavior = 0; break;
309+
case "never": uncheckedBehavior = 1; break;
310+
case "always": uncheckedBehavior = 2; break;
311+
}
306312
assemblyscript.setTarget(compilerOptions, 0);
307313
assemblyscript.setDebugInfo(compilerOptions, !!opts.debug);
308314
assemblyscript.setRuntime(compilerOptions, runtime);
@@ -320,7 +326,7 @@ export async function main(argv, options) {
320326
assemblyscript.setMemoryBase(compilerOptions, opts.memoryBase >>> 0);
321327
assemblyscript.setTableBase(compilerOptions, opts.tableBase >>> 0);
322328
assemblyscript.setSourceMap(compilerOptions, opts.sourceMap != null);
323-
assemblyscript.setIgnoreUnchecked(compilerOptions, opts.ignoreUnchecked);
329+
assemblyscript.setUncheckedBehavior(compilerOptions, uncheckedBehavior);
324330
assemblyscript.setNoUnsafe(compilerOptions, opts.noUnsafe);
325331
assemblyscript.setPedantic(compilerOptions, opts.pedantic);
326332
assemblyscript.setLowMemoryLimit(compilerOptions, opts.lowMemoryLimit >>> 0);

cli/options.json

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,20 @@
9898
],
9999
"type": "s"
100100
},
101-
"ignoreUnchecked": {
101+
"uncheckedBehavior": {
102102
"category": "Debugging",
103-
"description": "Ignores unchecked() expressions.",
104-
"type": "b",
105-
"default": false
103+
"description": [
104+
"Changes the behavior of unchecked() expressions.",
105+
"",
106+
" default The default behavior: unchecked operations are",
107+
" only used inside of unchecked().",
108+
" never Unchecked operations are never used, even when",
109+
" inside of unchecked().",
110+
" always Unchecked operations are always used if possible,",
111+
" whether or not unchecked() is used."
112+
],
113+
"type": "s",
114+
"default": "default"
106115
},
107116
"debug": {
108117
"category": "Debugging",

src/builtins.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
import {
2727
Compiler,
2828
Constraints,
29-
RuntimeFeatures
29+
RuntimeFeatures,
30+
UncheckedBehavior
3031
} from "./compiler";
3132

3233
import {
@@ -3587,8 +3588,9 @@ function builtin_unchecked(ctx: BuiltinContext): ExpressionRef {
35873588
checkArgsRequired(ctx, 1)
35883589
) return module.unreachable();
35893590
let flow = compiler.currentFlow;
3590-
let alreadyUnchecked = flow.is(FlowFlags.UncheckedContext);
3591-
if (!compiler.options.ignoreUnchecked) flow.set(FlowFlags.UncheckedContext);
3591+
let ignoreUnchecked = compiler.options.uncheckedBehavior === UncheckedBehavior.Never;
3592+
let alreadyUnchecked = !ignoreUnchecked && flow.is(FlowFlags.UncheckedContext);
3593+
if (!ignoreUnchecked) flow.set(FlowFlags.UncheckedContext);
35923594
// eliminate unnecessary tees by preferring contextualType(=void)
35933595
let expr = compiler.compileExpression(ctx.operands[0], ctx.contextualType);
35943596
if (!alreadyUnchecked) flow.unset(FlowFlags.UncheckedContext);

src/compiler.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,8 @@ export class Options {
246246
exportTable: bool = false;
247247
/** If true, generates information necessary for source maps. */
248248
sourceMap: bool = false;
249-
/** If true, unchecked() expressions are ignored. */
250-
ignoreUnchecked: bool = false;
249+
/** Unchecked behavior. Defaults to only using unchecked operations inside unchecked(). */
250+
uncheckedBehavior: UncheckedBehavior = UncheckedBehavior.Default;
251251
/** If given, exports the start function instead of calling it implicitly. */
252252
exportStart: string | null = null;
253253
/** Static memory start offset. */
@@ -318,6 +318,16 @@ export class Options {
318318
}
319319
}
320320

321+
/** Behaviors regarding unchecked operations. */
322+
export const enum UncheckedBehavior {
323+
/** Only use unchecked operations inside unchecked(). */
324+
Default = 0,
325+
/** Never use unchecked operations. */
326+
Never = 1,
327+
/** Always use unchecked operations if possible. */
328+
Always = 2
329+
}
330+
321331
/** Various constraints in expression compilation. */
322332
export const enum Constraints {
323333
None = 0,

src/flow.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ import {
7878
CommonFlags
7979
} from "./common";
8080

81+
import {
82+
UncheckedBehavior
83+
} from "./compiler";
84+
8185
import {
8286
DiagnosticCode
8387
} from "./diagnostics";
@@ -203,6 +207,9 @@ export class Flow {
203207
if (targetFunction.is(CommonFlags.Constructor)) {
204208
flow.initThisFieldFlags();
205209
}
210+
if (targetFunction.program.options.uncheckedBehavior === UncheckedBehavior.Always) {
211+
flow.set(FlowFlags.UncheckedContext);
212+
}
206213
return flow;
207214
}
208215

@@ -215,6 +222,9 @@ export class Flow {
215222
if (inlineFunction.is(CommonFlags.Constructor)) {
216223
flow.initThisFieldFlags();
217224
}
225+
if (targetFunction.program.options.uncheckedBehavior === UncheckedBehavior.Always) {
226+
flow.set(FlowFlags.UncheckedContext);
227+
}
218228
return flow;
219229
}
220230

src/index-wasm.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222

2323
import {
2424
Compiler,
25-
Options
25+
Options,
26+
UncheckedBehavior
2627
} from "./compiler";
2728

2829
import {
@@ -102,9 +103,9 @@ export function setSourceMap(options: Options, sourceMap: bool): void {
102103
options.sourceMap = sourceMap;
103104
}
104105

105-
/** Sets the `ignoreUnchecked` option. */
106-
export function setIgnoreUnchecked(options: Options, ignoreUnchecked: bool): void {
107-
options.ignoreUnchecked = ignoreUnchecked;
106+
/** Sets the `uncheckedBehavior` option. */
107+
export function setUncheckedBehavior(options: Options, uncheckedBehavior: UncheckedBehavior): void {
108+
options.uncheckedBehavior = uncheckedBehavior;
108109
}
109110

110111
/** Sets the `memoryBase` option. */

0 commit comments

Comments
 (0)