@@ -221,6 +221,12 @@ import {
221221 lowerRequiresExportRuntime
222222} from "./bindings/js" ;
223223
224+ /** Features enabled by default. */
225+ export const defaultFeatures = Feature . MutableGlobals
226+ | Feature . SignExtension
227+ | Feature . NontrappingF2I
228+ | Feature . BulkMemory ;
229+
224230/** Compiler options. */
225231export class Options {
226232 constructor ( ) { /* as internref */ }
@@ -261,11 +267,8 @@ export class Options {
261267 tableBase : u32 = 0 ;
262268 /** Global aliases, mapping alias names as the key to internal names to be aliased as the value. */
263269 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 ;
269272 /** If true, disallows unsafe features in user code. */
270273 noUnsafe : bool = false ;
271274 /** If true, enables pedantic diagnostics. */
@@ -317,6 +320,27 @@ export class Options {
317320 return this . optimizeLevelHint > 0 || this . shrinkLevelHint > 0 ;
318321 }
319322
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+
320344 /** Tests if a specific feature is activated. */
321345 hasFeature ( feature : Feature ) : bool {
322346 return ( this . features & feature ) != 0 ;
@@ -1357,7 +1381,14 @@ export class Compiler extends DiagnosticEmitter {
13571381 findDecorator ( DecoratorKind . Inline , global . decoratorNodes ) ! . range , "inline"
13581382 ) ;
13591383 }
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 ) ) ;
13611392 this . currentBody . push (
13621393 module . global_set ( internalName , initExpr )
13631394 ) ;
@@ -1757,7 +1788,7 @@ export class Compiler extends DiagnosticEmitter {
17571788 // Implicitly return `this` if the flow falls through
17581789 if ( ! flow . is ( FlowFlags . Terminates ) ) {
17591790 stmts . push (
1760- module . local_get ( thisLocal . index , this . options . sizeTypeRef )
1791+ module . local_get ( thisLocal . index , thisLocal . type . toRef ( ) )
17611792 ) ;
17621793 flow . set ( FlowFlags . Returns | FlowFlags . ReturnsNonNull | FlowFlags . Terminates ) ;
17631794 }
@@ -4854,17 +4885,17 @@ export class Compiler extends DiagnosticEmitter {
48544885 module . binary ( BinaryOp . EqI8x16 , leftExpr , rightExpr )
48554886 ) ;
48564887 }
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 ) ;
48624893 case TypeKind . StringviewWTF8 :
48634894 case TypeKind . StringviewWTF16 :
48644895 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 : {
48684899 this . error (
48694900 DiagnosticCode . Operation_0_cannot_be_applied_to_type_1 ,
48704901 reportNode . range ,
@@ -4904,25 +4935,25 @@ export class Compiler extends DiagnosticEmitter {
49044935 module . binary ( BinaryOp . NeI8x16 , leftExpr , rightExpr )
49054936 ) ;
49064937 }
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 : {
49114942 return module . unary ( UnaryOp . EqzI32 ,
49124943 module . ref_eq ( leftExpr , rightExpr )
49134944 ) ;
49144945 }
4915- case TypeKind . Stringref : {
4946+ case TypeKind . String : {
49164947 return module . unary ( UnaryOp . EqzI32 ,
49174948 module . string_eq ( leftExpr , rightExpr )
49184949 ) ;
49194950 }
49204951 case TypeKind . StringviewWTF8 :
49214952 case TypeKind . StringviewWTF16 :
49224953 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 : {
49264957 this . error (
49274958 DiagnosticCode . Operation_0_cannot_be_applied_to_type_1 ,
49284959 reportNode . range ,
@@ -7332,10 +7363,12 @@ export class Compiler extends DiagnosticEmitter {
73327363 ) ;
73337364 }
73347365 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 ;
73377371 }
7338- this . currentType = localType ;
73397372
73407373 if ( target . parent != flow . targetFunction ) {
73417374 // TODO: closures
@@ -7346,7 +7379,14 @@ export class Compiler extends DiagnosticEmitter {
73467379 ) ;
73477380 return module . unreachable ( ) ;
73487381 }
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 ;
73507390 }
73517391 case ElementKind . Global : {
73527392 let global = < Global > target ;
@@ -7424,7 +7464,7 @@ export class Compiler extends DiagnosticEmitter {
74247464 // TODO: Concrete function types currently map to first class functions implemented in
74257465 // linear memory (on top of `usize`), leaving only generic `funcref` for use here. In the
74267466 // future, once functions become Wasm GC objects, the actual signature type can be used.
7427- this . currentType = Type . funcref ;
7467+ this . currentType = Type . func ;
74287468 return module . ref_func ( functionInstance . internalName , ensureType ( functionInstance . type ) ) ;
74297469 }
74307470 let offset = this . ensureRuntimeFunction ( functionInstance ) ;
@@ -9897,20 +9937,21 @@ export class Compiler extends DiagnosticEmitter {
98979937 case TypeKind . F32 : return module . f32 ( 0 ) ;
98989938 case TypeKind . F64 : return module . f64 ( 0 ) ;
98999939 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 :
99079947 case TypeKind . StringviewWTF8 :
99089948 case TypeKind . StringviewWTF16 :
99099949 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 ( ) ;
99129953 }
9913- case TypeKind . I31ref : {
9954+ case TypeKind . I31 : {
99149955 if ( type . is ( TypeFlags . Nullable ) ) return module . ref_null ( type . toRef ( ) ) ;
99159956 return module . i31_new ( module . i32 ( 0 ) ) ;
99169957 }
@@ -9935,7 +9976,7 @@ export class Compiler extends DiagnosticEmitter {
99359976 case TypeKind . U64 : return module . i64 ( 1 ) ;
99369977 case TypeKind . F32 : return module . f32 ( 1 ) ;
99379978 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 ) ) ;
99399980 }
99409981 }
99419982
@@ -9957,7 +9998,7 @@ export class Compiler extends DiagnosticEmitter {
99579998 case TypeKind . F32 : return module . f32 ( - 1 ) ;
99589999 case TypeKind . F64 : return module . f64 ( - 1 ) ;
995910000 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 ) ) ;
996110002 }
996210003 }
996310004
@@ -10056,14 +10097,14 @@ export class Compiler extends DiagnosticEmitter {
1005610097 case TypeKind . V128 : {
1005710098 return module . unary ( UnaryOp . AnyTrueV128 , expr ) ;
1005810099 }
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 :
1006710108 case TypeKind . StringviewWTF8 :
1006810109 case TypeKind . StringviewWTF16 :
1006910110 case TypeKind . StringviewIter : {
0 commit comments