Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit e22a599

Browse files
authored
Check that builtins are implemented (#2636)
1 parent 5823c0e commit e22a599

File tree

8 files changed

+1379
-1193
lines changed

8 files changed

+1379
-1193
lines changed

‎src/builtins.ts‎

Lines changed: 1282 additions & 1124 deletions
Large diffs are not rendered by default.

‎src/compiler.ts‎

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
import {
77
BuiltinNames,
8-
BuiltinContext,
9-
builtins,
10-
function_builtins,
8+
BuiltinFunctionContext,
9+
BuiltinVariableContext,
10+
builtinFunctions,
11+
builtinVariables_onAccess,
12+
builtinVariables_onCompile,
1113
compileVisitGlobals,
1214
compileVisitMembers,
1315
compileRTTI
@@ -509,17 +511,6 @@ export class Compiler extends DiagnosticEmitter {
509511
let startFunctionBody = this.currentBody;
510512
assert(startFunctionBody.length == 0);
511513

512-
// add mutable data, heap and rtti offset dummies
513-
if (options.isWasm64) {
514-
module.addGlobal(BuiltinNames.data_end, TypeRef.I64, true, module.i64(0));
515-
module.addGlobal(BuiltinNames.heap_base, TypeRef.I64, true, module.i64(0));
516-
module.addGlobal(BuiltinNames.rtti_base, TypeRef.I64, true, module.i64(0));
517-
} else {
518-
module.addGlobal(BuiltinNames.data_end, TypeRef.I32, true, module.i32(0));
519-
module.addGlobal(BuiltinNames.heap_base, TypeRef.I32, true, module.i32(0));
520-
module.addGlobal(BuiltinNames.rtti_base, TypeRef.I32, true, module.i32(0));
521-
}
522-
523514
// compile entry file(s) while traversing reachable elements
524515
let files = program.filesByName;
525516
// TODO: for (let file of files.values()) {
@@ -1174,13 +1165,13 @@ export class Compiler extends DiagnosticEmitter {
11741165
}
11751166
}
11761167

1177-
// Handle ambient builtins like '__heap_base' that need to be resolved but are added explicitly
1178-
if (global.is(CommonFlags.Ambient)&&global.hasDecorator(DecoratorFlags.Builtin)) {
1168+
// Handle builtins like '__heap_base' that need to be resolved but are added explicitly
1169+
if (global.hasDecorator(DecoratorFlags.Builtin)) {
11791170
let internalName = global.internalName;
1180-
if (internalName==BuiltinNames.data_end)this.runtimeFeatures|=RuntimeFeatures.Data;
1181-
elseif(internalName==BuiltinNames.stack_pointer)this.runtimeFeatures|=RuntimeFeatures.Stack;
1182-
elseif(internalName==BuiltinNames.heap_base)this.runtimeFeatures|=RuntimeFeatures.Heap;
1183-
elseif(internalName==BuiltinNames.rtti_base)this.runtimeFeatures|=RuntimeFeatures.Rtti;
1171+
if (builtinVariables_onCompile.has(internalName)){// optional
1172+
letfn=assert(builtinVariables_onCompile.get(internalName));
1173+
fn(newBuiltinVariableContext(this,global));
1174+
}
11841175
pendingElements.delete(global);
11851176
return true;
11861177
}
@@ -6114,7 +6105,7 @@ export class Compiler extends DiagnosticEmitter {
61146105
);
61156106
}
61166107
let callee = expression.expression;
6117-
let ctx = new BuiltinContext(
6108+
let ctx = new BuiltinFunctionContext(
61186109
this,
61196110
prototype,
61206111
typeArguments,
@@ -6126,26 +6117,17 @@ export class Compiler extends DiagnosticEmitter {
61266117
expression,
61276118
false
61286119
);
6129-
// global builtins
6130-
let internalName = prototype.internalName;
6131-
if (builtins.has(internalName)) {
6132-
let fn = assert(builtins.get(internalName));
6133-
return fn(ctx);
6134-
}
6135-
// class builtins
6136-
let parent = prototype.parent;
6137-
if (parent.kind == ElementKind.Class) {
6138-
let classPrototype = (<Class>parent).prototype;
6139-
if (classPrototype == this.program.functionPrototype) {
6140-
let methodName = prototype.name;
6141-
if (function_builtins.has(methodName)) {
6142-
let fn = assert(function_builtins.get(methodName));
6143-
return fn(ctx);
6144-
}
6145-
}
6120+
let internalName: string;
6121+
if (prototype.is(CommonFlags.Instance)) {
6122+
// omit generic name components, e.g. in `Function<...>#call`
6123+
let parent = assert(prototype.getBoundClassOrInterface());
6124+
internalName = `${parent.prototype.internalName}#${prototype.name}`;
6125+
} else {
6126+
internalName = prototype.internalName;
61466127
}
6147-
assert(false);
6148-
return this.module.unreachable();
6128+
assert(builtinFunctions.has(internalName)); // checked earlier
6129+
let fn = assert(builtinFunctions.get(internalName));
6130+
return fn(ctx);
61496131
}
61506132

61516133
/**
@@ -7361,6 +7343,9 @@ export class Compiler extends DiagnosticEmitter {
73617343
return module.unreachable();
73627344
}
73637345
assert(globalType != Type.void);
7346+
if (global.hasDecorator(DecoratorFlags.Builtin)) {
7347+
return this.compileIdentifierExpressionBuiltin(global, expression, contextualType);
7348+
}
73647349
if (global.is(CommonFlags.Inlined)) {
73657350
return this.compileInlineConstant(global, contextualType, constraints);
73667351
}
@@ -7435,6 +7420,23 @@ export class Compiler extends DiagnosticEmitter {
74357420
return module.unreachable();
74367421
}
74377422

7423+
private compileIdentifierExpressionBuiltin(
7424+
element: VariableLikeElement,
7425+
expression: IdentifierExpression,
7426+
contextualType: Type
7427+
): ExpressionRef {
7428+
if (element.hasDecorator(DecoratorFlags.Unsafe)) this.checkUnsafe(expression, element.identifierNode);
7429+
let internalName = element.internalName;
7430+
assert(builtinVariables_onAccess.has(internalName)); // checked earlier
7431+
let fn = assert(builtinVariables_onAccess.get(internalName));
7432+
return fn(new BuiltinVariableContext(
7433+
this,
7434+
element,
7435+
contextualType,
7436+
expression
7437+
));
7438+
}
7439+
74387440
private compileInstanceOfExpression(
74397441
expression: InstanceOfExpression,
74407442
contextualType: Type,

‎src/module.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2092,9 +2092,11 @@ export class Module {
20922092

20932093
removeGlobal(
20942094
name: string
2095-
): void {
2095+
): bool {
20962096
let cStr = this.allocStringCached(name);
2097+
if (!binaryen._BinaryenGetGlobal(this.ref, cStr)) return false;
20972098
binaryen._BinaryenRemoveGlobal(this.ref, cStr);
2099+
return true;
20982100
}
20992101

21002102
// tags

‎src/program.ts‎

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ import {
147147
} from "./parser";
148148

149149
import {
150-
BuiltinNames
150+
BuiltinNames,
151+
builtinFunctions,
152+
builtinVariables_onAccess
151153
} from "./builtins";
152154

153155
// Memory manager constants
@@ -474,8 +476,6 @@ export class Program extends DiagnosticEmitter {
474476
managedClasses: Map<i32,Class> = new Map();
475477
/** A set of unique function signatures contained in the program, by id. */
476478
uniqueSignatures: Map<string, Signature> = new Map<string, Signature>();
477-
/** Module exports. */
478-
moduleExports: Map<string,Element> = new Map();
479479
/** Module imports. */
480480
moduleImports: Map<string,Map<string,Element>> = new Map();
481481

@@ -1915,16 +1915,7 @@ export class Program extends DiagnosticEmitter {
19151915
let kind = DecoratorKind.fromNode(decorator.name);
19161916
let flag = DecoratorFlags.fromKind(kind);
19171917
if (flag) {
1918-
if (flag == DecoratorFlags.Builtin) {
1919-
if (!(acceptedFlags & flag) && !decorator.range.source.isLibrary) {
1920-
this.error(
1921-
DiagnosticCode.Decorator_0_is_not_valid_here,
1922-
decorator.range, decorator.name.range.toString()
1923-
);
1924-
} else {
1925-
flags |= flag;
1926-
}
1927-
} else if (!(acceptedFlags & flag)) {
1918+
if (!(acceptedFlags & flag)) {
19281919
this.error(
19291920
DiagnosticCode.Decorator_0_is_not_valid_here,
19301921
decorator.range, decorator.name.range.toString()
@@ -2154,12 +2145,21 @@ export class Program extends DiagnosticEmitter {
21542145
if (parent.is(CommonFlags.Ambient)) {
21552146
acceptedFlags |= DecoratorFlags.External;
21562147
}
2148+
if (declaration.range.source.isLibrary) {
2149+
acceptedFlags |= DecoratorFlags.Builtin;
2150+
}
21572151
let element = new FunctionPrototype(
21582152
name,
21592153
parent,
21602154
declaration,
21612155
this.checkDecorators(declaration.decorators, acceptedFlags)
21622156
);
2157+
if (element.hasDecorator(DecoratorFlags.Builtin) && !builtinFunctions.has(element.internalName)) {
2158+
this.error(
2159+
DiagnosticCode.Not_implemented_0,
2160+
declaration.range, `Builtin '${element.internalName}'`
2161+
);
2162+
}
21632163
if (isStatic) { // global function
21642164
assert(declaration.name.kind != NodeKind.Constructor);
21652165
if (!parent.add(name, element)) return null;
@@ -2579,7 +2579,7 @@ export class Program extends DiagnosticEmitter {
25792579
parent: Element
25802580
): FunctionPrototype | null {
25812581
let name = declaration.name.text;
2582-
let validDecorators = DecoratorFlags.Unsafe|DecoratorFlags.Builtin;
2582+
let validDecorators = DecoratorFlags.Unsafe;
25832583
if (declaration.is(CommonFlags.Ambient)) {
25842584
validDecorators |= DecoratorFlags.External | DecoratorFlags.ExternalJs;
25852585
} else {
@@ -2593,12 +2593,21 @@ export class Program extends DiagnosticEmitter {
25932593
validDecorators |= DecoratorFlags.Global;
25942594
}
25952595
}
2596+
if (declaration.range.source.isLibrary) {
2597+
validDecorators |= DecoratorFlags.Builtin;
2598+
}
25962599
let element = new FunctionPrototype(
25972600
name,
25982601
parent,
25992602
declaration,
26002603
this.checkDecorators(declaration.decorators, validDecorators)
26012604
);
2605+
if (element.hasDecorator(DecoratorFlags.Builtin) && !builtinFunctions.has(element.internalName)) {
2606+
this.error(
2607+
DiagnosticCode.Not_implemented_0,
2608+
declaration.range, `Builtin '${element.internalName}'`
2609+
);
2610+
}
26022611
if (!parent.add(name, element)) return null;
26032612
return element;
26042613
}
@@ -2800,12 +2809,21 @@ export class Program extends DiagnosticEmitter {
28002809
if (declaration.is(CommonFlags.Const)) {
28012810
acceptedFlags |= DecoratorFlags.Inline;
28022811
}
2812+
if (declaration.range.source.isLibrary) {
2813+
acceptedFlags |= DecoratorFlags.Builtin;
2814+
}
28032815
let element = new Global(
28042816
name,
28052817
parent,
28062818
this.checkDecorators(declaration.decorators, acceptedFlags),
28072819
declaration
28082820
);
2821+
if (element.hasDecorator(DecoratorFlags.Builtin) && !builtinVariables_onAccess.has(element.internalName)) {
2822+
this.error(
2823+
DiagnosticCode.Not_implemented_0,
2824+
declaration.range, `Builtin '${element.internalName}'`
2825+
);
2826+
}
28092827
if (!parent.add(name, element)) continue; // reports
28102828
}
28112829
}

‎std/assembly/builtins.ts‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,6 @@ export namespace i32 {
452452
@unsafe @builtin
453453
export declare function store(ptr: usize, value: i32, immOffset?: usize): void;
454454

455-
// @ts-ignore: decorator
456-
@builtin
457-
export declare function wait(ptr: usize, expected: i32, timeout: i64): AtomicWaitResult;
458-
459455
export namespace rmw8 {
460456

461457
// @ts-ignore: decorator
@@ -709,10 +705,6 @@ export namespace i64 {
709705
@unsafe @builtin
710706
export declare function store(ptr: usize, value: i64, immOffset?: usize): void;
711707

712-
// @ts-ignore: decorator
713-
@builtin
714-
export declare function wait(ptr: usize, expected: i64, timeout: i64): AtomicWaitResult;
715-
716708
export namespace rmw8 {
717709

718710
// @ts-ignore: decorator

‎std/assembly/index.d.ts‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,6 @@ declare namespace i32 {
387387
export function store16(ptr: usize, value: i32, immOffset?: usize): void;
388388
/** Atomically stores a 32-bit integer value to memory. */
389389
export function store(ptr: usize, value: i32, immOffset?: usize): void;
390-
/** Performs a wait operation on a 32-bit integer value in memory suspending this agent if the condition is met. */
391-
export function wait(ptr: usize, expected: i32, timeout?: i64): AtomicWaitResult;
392390
/** Atomic 32-bit integer read-modify-write operations on 8-bit values. */
393391
export namespace rmw8 {
394392
/** Atomically adds an 8-bit unsigned integer value in memory. */
@@ -522,8 +520,6 @@ declare namespace i64 {
522520
export function store32(ptr: usize, value: i64, immOffset?: usize): void;
523521
/** Atomically stores a 64-bit integer value to memory. */
524522
export function store(ptr: usize, value: i64, immOffset?: usize): void;
525-
/** Performs a wait operation on a 64-bit integer value in memory suspending this agent if the condition is met. */
526-
export function wait(ptr: usize, expected: i64, timeout?: i64): AtomicWaitResult;
527523
/** Atomic 64-bit integer read-modify-write operations on 8-bit values. */
528524
export namespace rmw8 {
529525
/** Atomically adds an 8-bit unsigned integer value in memory. */
@@ -1530,6 +1526,13 @@ declare namespace memory {
15301526
export function data(size: i32, align?: i32): usize;
15311527
/** Gets a pointer to a pre-initialized static chunk of memory. Alignment defaults to the size of `T`. Arguments must be compile-time constants. */
15321528
export function data<T>(values: T[], align?: i32): usize;
1529+
1530+
export namespace atomic {
1531+
/** Performs a wait operation on a 32-bit integer value in memory suspending this agent if the condition is met. */
1532+
export function wait32(ptr: usize, expected: i32, timeout?: i64): AtomicWaitResult;
1533+
/** Performs a wait operation on a 64-bit integer value in memory suspending this agent if the condition is met. */
1534+
export function wait64(ptr: usize, expected: i64, timeout?: i64): AtomicWaitResult;
1535+
}
15331536
}
15341537

15351538
/** Heap memory interface. */

‎std/assembly/memory.ts‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ export namespace memory {
2828
memmove(dst, src, n); // fallback if "bulk-memory" isn't enabled
2929
}
3030

31+
export namespace atomic {
32+
33+
// @ts-ignore: decorator
34+
@unsafe @builtin
35+
export declare function wait32(ptr: usize, expected: i32, timeout: i64): AtomicWaitResult;
36+
37+
// @ts-ignore: decorator
38+
@unsafe @builtin
39+
export declare function wait64(ptr: usize, expected: i64, timeout: i64): AtomicWaitResult;
40+
}
41+
3142
/** Initializes a memory segment. */
3243
// @ts-ignore: decorator
3344
@unsafe

‎std/assembly/number.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { strtol, strtod } from "./util/string";
33

44
// @ts-ignore: decorator
55
@builtin @inline
6-
export const NaN: f64 = 0 / 0;
6+
export const NaN: f64 = 0 / 0;// context-aware
77

88
// @ts-ignore: decorator
99
@builtin @inline
10-
export const Infinity: f64 = 1 / 0;
10+
export const Infinity: f64 = 1 / 0;// context-aware
1111

1212
// @ts-ignore: decorator
1313
@builtin

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /