@@ -59,7 +59,8 @@ import {
59
59
isConstExpressionNaN ,
60
60
ensureType ,
61
61
createType ,
62
- getConstValueInteger
62
+ getConstValueInteger ,
63
+ isConstNonZero
63
64
} from "./module" ;
64
65
65
66
import {
@@ -10026,95 +10027,6 @@ export class Compiler extends DiagnosticEmitter {
10026
10027
// === Specialized code generation ==============================================================
10027
10028
10028
10029
/** Makes a constant zero of the specified type. */
10029
- /** Checks if an expression evaluates to a zero value for the given type. */
10030
- shouldSkipZeroInit ( expr : ExpressionRef , type : Type ) : bool {
10031
- let module = this . module ;
10032
- // Try to evaluate the expression at compile time
10033
- let evaled = module . runExpression ( expr , ExpressionRunnerFlags . Default ) ;
10034
- if ( ! evaled ) return false ; // Can't evaluate at compile time
10035
-
10036
- const evaledType = getExpressionType ( evaled ) ;
10037
- switch ( type . kind ) {
10038
- case TypeKind . Bool :
10039
- case TypeKind . I8 :
10040
- case TypeKind . I16 :
10041
- case TypeKind . I32 :
10042
- case TypeKind . U8 :
10043
- case TypeKind . U16 :
10044
- case TypeKind . U32 :
10045
- // All small integer types are represented as i32 in WebAssembly
10046
- // But we still check for safety and consistency
10047
- if ( evaledType == TypeRef . I32 ) {
10048
- return getConstValueI32 ( evaled ) === 0 ;
10049
- }
10050
- return false ;
10051
- case TypeKind . I64 :
10052
- case TypeKind . U64 :
10053
- case TypeKind . Isize :
10054
- case TypeKind . Usize :
10055
- // Only call getConstValueI64* if the expression is actually i64
10056
- if ( evaledType == TypeRef . I64 ) {
10057
- return getConstValueI64Low ( evaled ) === 0 && getConstValueI64High ( evaled ) === 0 ;
10058
- }
10059
- // For size types on 32-bit platforms, they might be i32
10060
- if ( evaledType == TypeRef . I32 && ( type . kind == TypeKind . Isize || type . kind == TypeKind . Usize ) ) {
10061
- return getConstValueI32 ( evaled ) === 0 ;
10062
- }
10063
- return false ;
10064
- case TypeKind . F32 :
10065
- if ( evaledType == TypeRef . F32 ) {
10066
- return getConstValueF32 ( evaled ) === 0.0 ;
10067
- }
10068
- return false ;
10069
- case TypeKind . F64 :
10070
- if ( evaledType == TypeRef . F64 ) {
10071
- return getConstValueF64 ( evaled ) === 0.0 ;
10072
- }
10073
- return false ;
10074
- default :
10075
- // For reference types, zero means null
10076
- if ( type . isReference && type . is ( TypeFlags . Nullable ) ) {
10077
- return getExpressionId ( evaled ) === ExpressionId . RefNull ;
10078
- }
10079
- return false ;
10080
- }
10081
- }
10082
-
10083
- /** Checks if a field type can use the default zero-initialized memory value. */
10084
- canUseZeroDefault ( type : Type ) : bool {
10085
- switch ( type . kind ) {
10086
- default : assert ( false ) ;
10087
- case TypeKind . Bool :
10088
- case TypeKind . I8 :
10089
- case TypeKind . I16 :
10090
- case TypeKind . I32 :
10091
- case TypeKind . U8 :
10092
- case TypeKind . U16 :
10093
- case TypeKind . U32 :
10094
- case TypeKind . I64 :
10095
- case TypeKind . U64 :
10096
- case TypeKind . Isize :
10097
- case TypeKind . Usize :
10098
- case TypeKind . F32 :
10099
- case TypeKind . F64 :
10100
- case TypeKind . V128 :
10101
- return true ; // Value types default to zero in zero-initialized memory
10102
- case TypeKind . Func :
10103
- case TypeKind . Extern :
10104
- case TypeKind . Any :
10105
- case TypeKind . Eq :
10106
- case TypeKind . Struct :
10107
- case TypeKind . Array :
10108
- case TypeKind . String :
10109
- case TypeKind . StringviewWTF8 :
10110
- case TypeKind . StringviewWTF16 :
10111
- case TypeKind . StringviewIter :
10112
- case TypeKind . I31 :
10113
- // Reference types: only nullable refs can use zero (null) default
10114
- return type . is ( TypeFlags . Nullable ) ;
10115
- }
10116
- }
10117
-
10118
10030
makeZero ( type : Type ) : ExpressionRef {
10119
10031
let module = this . module ;
10120
10032
switch ( type . kind ) {
@@ -10502,7 +10414,10 @@ export class Compiler extends DiagnosticEmitter {
10502
10414
// Explicit initializer
10503
10415
// Check if we need to initialize this field
10504
10416
const valueExpr : ExpressionRef = this . compileExpression ( initializerNode , fieldType , Constraints . ConvImplicit ) ;
10505
- if ( ! this . shouldSkipZeroInit ( valueExpr , fieldType ) ) {
10417
+ // Memory will be filled with 0 on itcms.__new
10418
+ // Memory grow will default to initialized with 0 as wasm spec
10419
+ // So, optimize the active initialization away if it's zero
10420
+ if ( ( this . options . runtime == Runtime . Incremental || this . options . runtime == Runtime . Stub ) && isConstNonZero ( valueExpr ) ) {
10506
10421
let expr = this . makeCallDirect ( setterInstance , [
10507
10422
module . local_get ( thisLocalIndex , sizeTypeRef ) ,
10508
10423
valueExpr
@@ -10512,9 +10427,6 @@ export class Compiler extends DiagnosticEmitter {
10512
10427
}
10513
10428
stmts . push ( expr ) ;
10514
10429
}
10515
- } else {
10516
- // No explicit initializer
10517
- assert ( this . canUseZeroDefault ( fieldType ) ) ;
10518
10430
}
10519
10431
}
10520
10432
}
0 commit comments