@@ -221,6 +221,12 @@ import {
221
221
lowerRequiresExportRuntime
222
222
} from "./bindings/js" ;
223
223
224
+ /** Features enabled by default. */
225
+ export const defaultFeatures = Feature . MutableGlobals
226
+ | Feature . SignExtension
227
+ | Feature . NontrappingF2I
228
+ | Feature . BulkMemory ;
229
+
224
230
/** Compiler options. */
225
231
export class Options {
226
232
constructor ( ) { /* as internref */ }
@@ -261,11 +267,8 @@ export class Options {
261
267
tableBase : u32 = 0 ;
262
268
/** Global aliases, mapping alias names as the key to internal names to be aliased as the value. */
263
269
globalAliases : Map < string , string > | null = null ;
264
- /** Features to activate by default. These are the finished proposals. */
265
- features : Feature = Feature . MutableGlobals
266
- | Feature . SignExtension
267
- | Feature . NontrappingF2I
268
- | Feature . BulkMemory ;
270
+ /** Features to activate by default. */
271
+ features : Feature = defaultFeatures ;
269
272
/** If true, disallows unsafe features in user code. */
270
273
noUnsafe : bool = false ;
271
274
/** If true, enables pedantic diagnostics. */
@@ -317,6 +320,27 @@ export class Options {
317
320
return this . optimizeLevelHint > 0 || this . shrinkLevelHint > 0 ;
318
321
}
319
322
323
+ /** Sets whether a feature is enabled. */
324
+ setFeature ( feature : Feature , on : bool = true ) : void {
325
+ if ( on ) {
326
+ // Enabling Stringref also enables GC
327
+ if ( feature & Feature . Stringref ) feature |= Feature . GC ;
328
+ // Enabling GC also enables Reference Types
329
+ if ( feature & Feature . GC ) feature |= Feature . ReferenceTypes ;
330
+ // Enabling Relaxed SIMD also enables SIMD
331
+ if ( feature & Feature . RelaxedSimd ) feature |= Feature . Simd ;
332
+ this . features |= feature ;
333
+ } else {
334
+ // Disabling Reference Types also disables GC
335
+ if ( feature & Feature . ReferenceTypes ) feature |= Feature . GC ;
336
+ // Disabling GC also disables Stringref
337
+ if ( feature & Feature . GC ) feature |= Feature . Stringref ;
338
+ // Disabling SIMD also disables Relaxed SIMD
339
+ if ( feature & Feature . Simd ) feature |= Feature . RelaxedSimd ;
340
+ this . features &= ~ feature ;
341
+ }
342
+ }
343
+
320
344
/** Tests if a specific feature is activated. */
321
345
hasFeature ( feature : Feature ) : bool {
322
346
return ( this . features & feature ) != 0 ;
@@ -1357,7 +1381,14 @@ export class Compiler extends DiagnosticEmitter {
1357
1381
findDecorator ( DecoratorKind . Inline , global . decoratorNodes ) ! . range , "inline"
1358
1382
) ;
1359
1383
}
1360
- module . addGlobal ( internalName , typeRef , true , this . makeZero ( type ) ) ;
1384
+ let internalType = type ;
1385
+ if ( type . isExternalReference && ! type . is ( TypeFlags . Nullable ) ) {
1386
+ // There is no default value for non-nullable external references, so
1387
+ // make the global nullable internally and use `null`.
1388
+ global . set ( CommonFlags . InternallyNullable ) ;
1389
+ internalType = type . asNullable ( ) ;
1390
+ }
1391
+ module . addGlobal ( internalName , internalType . toRef ( ) , true , this . makeZero ( internalType ) ) ;
1361
1392
this . currentBody . push (
1362
1393
module . global_set ( internalName , initExpr )
1363
1394
) ;
@@ -1757,7 +1788,7 @@ export class Compiler extends DiagnosticEmitter {
1757
1788
// Implicitly return `this` if the flow falls through
1758
1789
if ( ! flow . is ( FlowFlags . Terminates ) ) {
1759
1790
stmts . push (
1760
- module . local_get ( thisLocal . index , this . options . sizeTypeRef )
1791
+ module . local_get ( thisLocal . index , thisLocal . type . toRef ( ) )
1761
1792
) ;
1762
1793
flow . set ( FlowFlags . Returns | FlowFlags . ReturnsNonNull | FlowFlags . Terminates ) ;
1763
1794
}
@@ -4854,17 +4885,17 @@ export class Compiler extends DiagnosticEmitter {
4854
4885
module . binary ( BinaryOp . EqI8x16 , leftExpr , rightExpr )
4855
4886
) ;
4856
4887
}
4857
- case TypeKind . Eqref :
4858
- case TypeKind . Structref :
4859
- case TypeKind . Arrayref :
4860
- case TypeKind . I31ref : return module . ref_eq ( leftExpr , rightExpr ) ;
4861
- case TypeKind . Stringref : return module . string_eq ( leftExpr , rightExpr ) ;
4888
+ case TypeKind . Eq :
4889
+ case TypeKind . Struct :
4890
+ case TypeKind . Array :
4891
+ case TypeKind . I31 : return module . ref_eq ( leftExpr , rightExpr ) ;
4892
+ case TypeKind . String : return module . string_eq ( leftExpr , rightExpr ) ;
4862
4893
case TypeKind . StringviewWTF8 :
4863
4894
case TypeKind . StringviewWTF16 :
4864
4895
case TypeKind . StringviewIter :
4865
- case TypeKind . Funcref :
4866
- case TypeKind . Externref :
4867
- case TypeKind . Anyref : {
4896
+ case TypeKind . Func :
4897
+ case TypeKind . Extern :
4898
+ case TypeKind . Any : {
4868
4899
this . error (
4869
4900
DiagnosticCode . Operation_0_cannot_be_applied_to_type_1 ,
4870
4901
reportNode . range ,
@@ -4904,25 +4935,25 @@ export class Compiler extends DiagnosticEmitter {
4904
4935
module . binary ( BinaryOp . NeI8x16 , leftExpr , rightExpr )
4905
4936
) ;
4906
4937
}
4907
- case TypeKind . Eqref :
4908
- case TypeKind . Structref :
4909
- case TypeKind . Arrayref :
4910
- case TypeKind . I31ref : {
4938
+ case TypeKind . Eq :
4939
+ case TypeKind . Struct :
4940
+ case TypeKind . Array :
4941
+ case TypeKind . I31 : {
4911
4942
return module . unary ( UnaryOp . EqzI32 ,
4912
4943
module . ref_eq ( leftExpr , rightExpr )
4913
4944
) ;
4914
4945
}
4915
- case TypeKind . Stringref : {
4946
+ case TypeKind . String : {
4916
4947
return module . unary ( UnaryOp . EqzI32 ,
4917
4948
module . string_eq ( leftExpr , rightExpr )
4918
4949
) ;
4919
4950
}
4920
4951
case TypeKind . StringviewWTF8 :
4921
4952
case TypeKind . StringviewWTF16 :
4922
4953
case TypeKind . StringviewIter :
4923
- case TypeKind . Funcref :
4924
- case TypeKind . Externref :
4925
- case TypeKind . Anyref : {
4954
+ case TypeKind . Func :
4955
+ case TypeKind . Extern :
4956
+ case TypeKind . Any : {
4926
4957
this . error (
4927
4958
DiagnosticCode . Operation_0_cannot_be_applied_to_type_1 ,
4928
4959
reportNode . range ,
@@ -7332,10 +7363,12 @@ export class Compiler extends DiagnosticEmitter {
7332
7363
) ;
7333
7364
}
7334
7365
assert ( localIndex >= 0 ) ;
7335
- if ( localType . isNullableReference && flow . isLocalFlag ( localIndex , LocalFlags . NonNull , false ) ) {
7336
- localType = localType . nonNullableType ;
7366
+ let isNonNull = flow . isLocalFlag ( localIndex , LocalFlags . NonNull , false ) ;
7367
+ if ( localType . isNullableReference && isNonNull && ( ! localType . isExternalReference || this . options . hasFeature ( Feature . GC ) ) ) {
7368
+ this . currentType = localType . nonNullableType ;
7369
+ } else {
7370
+ this . currentType = localType ;
7337
7371
}
7338
- this . currentType = localType ;
7339
7372
7340
7373
if ( target . parent != flow . targetFunction ) {
7341
7374
// TODO: closures
@@ -7346,7 +7379,14 @@ export class Compiler extends DiagnosticEmitter {
7346
7379
) ;
7347
7380
return module . unreachable ( ) ;
7348
7381
}
7349
- return module . local_get ( localIndex , localType . toRef ( ) ) ;
7382
+ let expr = module . local_get ( localIndex , localType . toRef ( ) ) ;
7383
+ if ( isNonNull && localType . isNullableExternalReference && this . options . hasFeature ( Feature . GC ) ) {
7384
+ // If the local's type is nullable, but its value is known to be non-null, propagate
7385
+ // non-nullability info to Binaryen. Only applicable if GC is enabled, since without
7386
+ // GC, here incl. typed function references, there is no nullability dimension.
7387
+ expr = module . ref_as_nonnull ( expr ) ;
7388
+ }
7389
+ return expr ;
7350
7390
}
7351
7391
case ElementKind . Global : {
7352
7392
let global = < Global > target ;
@@ -7424,7 +7464,7 @@ export class Compiler extends DiagnosticEmitter {
7424
7464
// TODO: Concrete function types currently map to first class functions implemented in
7425
7465
// linear memory (on top of `usize`), leaving only generic `funcref` for use here. In the
7426
7466
// future, once functions become Wasm GC objects, the actual signature type can be used.
7427
- this . currentType = Type . funcref ;
7467
+ this . currentType = Type . func ;
7428
7468
return module . ref_func ( functionInstance . internalName , ensureType ( functionInstance . type ) ) ;
7429
7469
}
7430
7470
let offset = this . ensureRuntimeFunction ( functionInstance ) ;
@@ -9897,20 +9937,21 @@ export class Compiler extends DiagnosticEmitter {
9897
9937
case TypeKind . F32 : return module . f32 ( 0 ) ;
9898
9938
case TypeKind . F64 : return module . f64 ( 0 ) ;
9899
9939
case TypeKind . V128 : return module . v128 ( v128_zero ) ;
9900
- case TypeKind . Funcref :
9901
- case TypeKind . Externref :
9902
- case TypeKind . Anyref :
9903
- case TypeKind . Eqref :
9904
- case TypeKind . Structref :
9905
- case TypeKind . Arrayref :
9906
- case TypeKind . Stringref :
9940
+ case TypeKind . Func :
9941
+ case TypeKind . Extern :
9942
+ case TypeKind . Any :
9943
+ case TypeKind . Eq :
9944
+ case TypeKind . Struct :
9945
+ case TypeKind . Array :
9946
+ case TypeKind . String :
9907
9947
case TypeKind . StringviewWTF8 :
9908
9948
case TypeKind . StringviewWTF16 :
9909
9949
case TypeKind . StringviewIter : {
9910
- // TODO: what if not nullable?
9911
- return module . ref_null ( type . toRef ( ) ) ;
9950
+ if ( type . is ( TypeFlags . Nullable ) ) return module . ref_null ( type . toRef ( ) ) ;
9951
+ assert ( false ) ; // TODO: check that refs are nullable in callers?
9952
+ return module . unreachable ( ) ;
9912
9953
}
9913
- case TypeKind . I31ref : {
9954
+ case TypeKind . I31 : {
9914
9955
if ( type . is ( TypeFlags . Nullable ) ) return module . ref_null ( type . toRef ( ) ) ;
9915
9956
return module . i31_new ( module . i32 ( 0 ) ) ;
9916
9957
}
@@ -9935,7 +9976,7 @@ export class Compiler extends DiagnosticEmitter {
9935
9976
case TypeKind . U64 : return module . i64 ( 1 ) ;
9936
9977
case TypeKind . F32 : return module . f32 ( 1 ) ;
9937
9978
case TypeKind . F64 : return module . f64 ( 1 ) ;
9938
- case TypeKind . I31ref : return module . i31_new ( module . i32 ( 1 ) ) ;
9979
+ case TypeKind . I31 : return module . i31_new ( module . i32 ( 1 ) ) ;
9939
9980
}
9940
9981
}
9941
9982
@@ -9957,7 +9998,7 @@ export class Compiler extends DiagnosticEmitter {
9957
9998
case TypeKind . F32 : return module . f32 ( - 1 ) ;
9958
9999
case TypeKind . F64 : return module . f64 ( - 1 ) ;
9959
10000
case TypeKind . V128 : return module . v128 ( v128_ones ) ;
9960
- case TypeKind . I31ref : return module . i31_new ( module . i32 ( - 1 ) ) ;
10001
+ case TypeKind . I31 : return module . i31_new ( module . i32 ( - 1 ) ) ;
9961
10002
}
9962
10003
}
9963
10004
@@ -10056,14 +10097,14 @@ export class Compiler extends DiagnosticEmitter {
10056
10097
case TypeKind . V128 : {
10057
10098
return module . unary ( UnaryOp . AnyTrueV128 , expr ) ;
10058
10099
}
10059
- case TypeKind . Funcref :
10060
- case TypeKind . Externref :
10061
- case TypeKind . Anyref :
10062
- case TypeKind . Eqref :
10063
- case TypeKind . Structref :
10064
- case TypeKind . Arrayref :
10065
- case TypeKind . I31ref :
10066
- case TypeKind . Stringref :
10100
+ case TypeKind . Func :
10101
+ case TypeKind . Extern :
10102
+ case TypeKind . Any :
10103
+ case TypeKind . Eq :
10104
+ case TypeKind . Struct :
10105
+ case TypeKind . Array :
10106
+ case TypeKind . I31 :
10107
+ case TypeKind . String :
10067
10108
case TypeKind . StringviewWTF8 :
10068
10109
case TypeKind . StringviewWTF16 :
10069
10110
case TypeKind . StringviewIter : {
0 commit comments