Skip to content

Commit 544fd64

Browse files
committed
Add --uncheckedBehavior to customize the use of unchecked() contexts
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 280a8ef commit 544fd64

File tree

6 files changed

+58
-5
lines changed

6 files changed

+58
-5
lines changed

cli/index.js

Lines changed: 8 additions & 1 deletion
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,6 +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);
329+
assemblyscript.setUncheckedBehavior(compilerOptions, uncheckedBehavior);
323330
assemblyscript.setNoUnsafe(compilerOptions, opts.noUnsafe);
324331
assemblyscript.setPedantic(compilerOptions, opts.pedantic);
325332
assemblyscript.setLowMemoryLimit(compilerOptions, opts.lowMemoryLimit >>> 0);

cli/options.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@
9898
],
9999
"type": "s"
100100
},
101+
"uncheckedBehavior": {
102+
"category": "Debugging",
103+
"description": [
104+
"Changes the behavior of unchecked() expressions.",
105+
"Using this option can potentially cause breakage.",
106+
"",
107+
" default The default behavior: unchecked operations are",
108+
" only used inside of unchecked().",
109+
" never Unchecked operations are never used, even when",
110+
" inside of unchecked().",
111+
" always Unchecked operations are always used if possible,",
112+
" whether or not unchecked() is used."
113+
],
114+
"type": "s",
115+
"default": "default"
116+
},
101117
"debug": {
102118
"category": "Debugging",
103119
"description": "Enables debug information in emitted binaries.",

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-
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ export class Options {
245245
exportTable: bool = false;
246246
/** If true, generates information necessary for source maps. */
247247
sourceMap: bool = false;
248+
/** Unchecked behavior. Defaults to only using unchecked operations inside unchecked(). */
249+
uncheckedBehavior: UncheckedBehavior = UncheckedBehavior.Default;
248250
/** If given, exports the start function instead of calling it implicitly. */
249251
exportStart: string | null = null;
250252
/** Static memory start offset. */
@@ -315,6 +317,16 @@ export class Options {
315317
}
316318
}
317319

320+
/** Behaviors regarding unchecked operations. */
321+
export const enum UncheckedBehavior {
322+
/** Only use unchecked operations inside unchecked(). */
323+
Default = 0,
324+
/** Never use unchecked operations. */
325+
Never = 1,
326+
/** Always use unchecked operations if possible. */
327+
Always = 2
328+
}
329+
318330
/** Various constraints in expression compilation. */
319331
export const enum Constraints {
320332
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: 7 additions & 1 deletion
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,6 +103,11 @@ export function setSourceMap(options: Options, sourceMap: bool): void {
102103
options.sourceMap = sourceMap;
103104
}
104105

106+
/** Sets the `uncheckedBehavior` option. */
107+
export function setUncheckedBehavior(options: Options, uncheckedBehavior: UncheckedBehavior): void {
108+
options.uncheckedBehavior = uncheckedBehavior;
109+
}
110+
105111
/** Sets the `memoryBase` option. */
106112
export function setMemoryBase(options: Options, memoryBase: u32): void {
107113
options.memoryBase = memoryBase;

0 commit comments

Comments
 (0)