@@ -1072,7 +1072,7 @@ private void ImportStoreVar(int index, bool argument)
10721072 TypeDesc varType ;
10731073 StackEntry toStore = _stack . Pop ( ) ;
10741074 LLVMValueRef varAddress = LoadVarAddress ( index , argument ? LocalVarKind . Argument : LocalVarKind . Local , out varType ) ;
1075- CastingStore ( varAddress , toStore , varType , $ "Variable{ index } _") ;
1075+ CastingStore ( varAddress , toStore , varType , false , $ "Variable{ index } _") ;
10761076 }
10771077
10781078 private void ImportStoreHelper ( LLVMValueRef toStore , LLVMTypeRef valueType , LLVMValueRef basePtr , uint offset , string name = null , LLVMBuilderRef builder = default ( LLVMBuilderRef ) )
@@ -1104,10 +1104,75 @@ private LLVMValueRef CastToPointerToTypeDesc(LLVMValueRef source, TypeDesc type,
11041104 return CastIfNecessary ( source , LLVMTypeRef . CreatePointer ( GetLLVMTypeForTypeDesc ( type ) , 0 ) , ( name ?? "" ) + type . ToString ( ) ) ;
11051105 }
11061106
1107- private void CastingStore ( LLVMValueRef address , StackEntry value , TypeDesc targetType , string targetName = null )
1107+ private void CastingStore ( LLVMValueRef address , StackEntry value , TypeDesc targetType , bool withBarrier , string targetName = null )
11081108 {
1109- var typedStoreLocation = CastToPointerToTypeDesc ( address , targetType , targetName ) ;
1110- _builder . BuildStore ( value . ValueAsType ( targetType , _builder ) , typedStoreLocation ) ;
1109+ if ( withBarrier && targetType . IsGCPointer )
1110+ {
1111+ CallRuntime ( _method . Context , "InternalCalls" , "RhpAssignRef" , new StackEntry [ ]
1112+ {
1113+ new ExpressionEntry ( StackValueKind . Int32 , "address" , address ) , value
1114+ } ) ;
1115+ }
1116+ else
1117+ {
1118+ var typedStoreLocation = CastToPointerToTypeDesc ( address , targetType , targetName ) ;
1119+ var llvmValue = value . ValueAsType ( targetType , _builder ) ;
1120+ if ( withBarrier && IsStruct ( targetType ) )
1121+ {
1122+ StoreStruct ( address , llvmValue , targetType , typedStoreLocation ) ;
1123+ }
1124+ else
1125+ {
1126+ _builder . BuildStore ( llvmValue , typedStoreLocation ) ;
1127+ }
1128+ }
1129+ }
1130+
1131+ private static bool IsStruct ( TypeDesc typeDesc )
1132+ {
1133+ return typeDesc . IsValueType && ! typeDesc . IsPrimitive && ! typeDesc . IsEnum ;
1134+ }
1135+
1136+ private void StoreStruct ( LLVMValueRef address , LLVMValueRef llvmValue , TypeDesc targetType , LLVMValueRef typedStoreLocation , bool childStruct = false )
1137+ {
1138+ foreach ( FieldDesc f in targetType . GetFields ( ) )
1139+ {
1140+ if ( f . IsStatic ) continue ;
1141+ if ( IsStruct ( f . FieldType ) && llvmValue . TypeOf . IsPackedStruct )
1142+ {
1143+ LLVMValueRef targetAddress = _builder . BuildGEP ( address , new [ ] { BuildConstInt32 ( f . Offset . AsInt ) } ) ;
1144+ uint index = LLVMSharpInterop . ElementAtOffset ( _compilation . TargetData , llvmValue . TypeOf , ( ulong ) f . Offset . AsInt ) ;
1145+ LLVMValueRef fieldValue = _builder . BuildExtractValue ( llvmValue , index ) ;
1146+ //recurse into struct
1147+ StoreStruct ( targetAddress , fieldValue , f . FieldType , CastToPointerToTypeDesc ( targetAddress , f . FieldType ) , true ) ;
1148+ }
1149+ else if ( f . FieldType . IsGCPointer )
1150+ {
1151+ LLVMValueRef targetAddress = _builder . BuildGEP ( address , new [ ] { BuildConstInt32 ( f . Offset . AsInt ) } ) ;
1152+ LLVMValueRef fieldValue ;
1153+ if ( llvmValue . TypeOf . IsPackedStruct )
1154+ {
1155+ uint index = LLVMSharpInterop . ElementAtOffset ( _compilation . TargetData , llvmValue . TypeOf , ( ulong ) f . Offset . AsInt ) ;
1156+ fieldValue = _builder . BuildExtractValue ( llvmValue , index ) ;
1157+ Debug . Assert ( fieldValue . TypeOf . Kind == LLVMTypeKind . LLVMPointerTypeKind , "expected an LLVM pointer type" ) ;
1158+ }
1159+ else
1160+ {
1161+ // single field IL structs are not LLVM structs
1162+ fieldValue = llvmValue ;
1163+ }
1164+ CallRuntime ( _method . Context , "InternalCalls" , "RhpAssignRef" ,
1165+ new StackEntry [ ]
1166+ {
1167+ new ExpressionEntry ( StackValueKind . Int32 , "targetAddress" , targetAddress ) ,
1168+ new ExpressionEntry ( StackValueKind . ObjRef , "sourceAddress" , fieldValue )
1169+ } ) ;
1170+ }
1171+ }
1172+ if ( ! childStruct )
1173+ {
1174+ _builder . BuildStore ( llvmValue , typedStoreLocation ) ; // just copy all the fields again for simplicity, if all the fields where set using RhpAssignRef then a possible optimisation would be to skip this line
1175+ }
11111176 }
11121177
11131178 private LLVMValueRef CastIfNecessary ( LLVMValueRef source , LLVMTypeRef valueType , string name = null , bool unsigned = false )
@@ -3578,7 +3643,6 @@ private void ImportLoadIndirect(TypeDesc type)
35783643 {
35793644 var pointer = _stack . Pop ( ) ;
35803645 Debug . Assert ( pointer is ExpressionEntry || pointer is ConstantEntry ) ;
3581- var expressionPointer = pointer as ExpressionEntry ;
35823646 if ( type == null )
35833647 {
35843648 type = GetWellKnownType ( WellKnownType . Object ) ;
@@ -3600,19 +3664,36 @@ private void ImportStoreIndirect(TypeDesc type)
36003664 StackEntry destinationPointer = _stack . Pop ( ) ;
36013665 LLVMValueRef typedValue ;
36023666 LLVMValueRef typedPointer ;
3667+ bool requireWriteBarrier ;
36033668
36043669 if ( type != null )
36053670 {
3606- typedValue = value . ValueAsType ( type , _builder ) ;
36073671 typedPointer = destinationPointer . ValueAsType ( type . MakePointerType ( ) , _builder ) ;
3672+ typedValue = value . ValueAsType ( type , _builder ) ;
3673+ if ( IsStruct ( type ) )
3674+ {
3675+ StoreStruct ( typedPointer , typedValue , type , typedPointer ) ;
3676+ return ;
3677+ }
3678+ requireWriteBarrier = type . IsGCPointer ;
36083679 }
36093680 else
36103681 {
36113682 typedPointer = destinationPointer . ValueAsType ( LLVMTypeRef . CreatePointer ( LLVMTypeRef . Int32 , 0 ) , _builder ) ;
36123683 typedValue = value . ValueAsInt32 ( _builder , false ) ;
3684+ requireWriteBarrier = ( value is ExpressionEntry ) && ! ( ( ExpressionEntry ) value ) . RawLLVMValue . IsNull && value . Type . IsGCPointer ;
3685+ }
3686+ if ( requireWriteBarrier )
3687+ {
3688+ CallRuntime ( _method . Context , "InternalCalls" , "RhpAssignRef" , new StackEntry [ ]
3689+ {
3690+ new ExpressionEntry ( StackValueKind . Int32 , "typedPointer" , typedPointer ) , value
3691+ } ) ;
3692+ }
3693+ else
3694+ {
3695+ _builder . BuildStore ( typedValue , typedPointer ) ;
36133696 }
3614-
3615- _builder . BuildStore ( typedValue , typedPointer ) ;
36163697 }
36173698
36183699 private void ImportBinaryOperation ( ILOpcode opcode )
@@ -4720,7 +4801,7 @@ private void ImportStoreField(int token, bool isStatic)
47204801 StackEntry valueEntry = _stack . Pop ( ) ;
47214802
47224803 LLVMValueRef fieldAddress = GetFieldAddress ( runtimeDeterminedField , field , isStatic ) ;
4723- CastingStore ( fieldAddress , valueEntry , field . FieldType ) ;
4804+ CastingStore ( fieldAddress , valueEntry , field . FieldType , true ) ;
47244805 }
47254806
47264807 // Loads symbol address. Address is represented as a i32*
@@ -4936,7 +5017,7 @@ private void ImportStoreElement(TypeDesc elementType)
49365017 StackEntry arrayReference = _stack . Pop ( ) ;
49375018 var nullSafeElementType = elementType ?? GetWellKnownType ( WellKnownType . Object ) ;
49385019 LLVMValueRef elementAddress = GetElementAddress ( index . ValueAsInt32 ( _builder , true ) , arrayReference . ValueAsType ( LLVMTypeRef . CreatePointer ( LLVMTypeRef . Int8 , 0 ) , _builder ) , nullSafeElementType ) ;
4939- CastingStore ( elementAddress , value , nullSafeElementType ) ;
5020+ CastingStore ( elementAddress , value , nullSafeElementType , true ) ;
49405021 }
49415022
49425023 private void ImportLoadLength ( )
0 commit comments