Add basic support of VArray<Mfvc>
diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
index 4863bd7..07da6f1 100644
--- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
+++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt
@@ -241,6 +241,8 @@
             configuration.get(JVMConfigurationKeys.STRING_CONCAT) ?: JvmStringConcat.INDY_WITH_CONSTANTS
         else JvmStringConcat.INLINE
 
+    val mfvcVArrayFlatteningScheme = JvmMfvcVArrayFlatteningScheme.PER_SIZE // TODO init with respect to configuration
+
     val samConversionsScheme = run {
         val fromConfig = configuration.get(JVMConfigurationKeys.SAM_CONVERSIONS)
         if (fromConfig != null && target >= fromConfig.minJvmTarget)
diff --git a/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmMfvcVArrayFlatteningScheme.kt b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmMfvcVArrayFlatteningScheme.kt
new file mode 100644
index 0000000..24d9909
--- /dev/null
+++ b/compiler/config.jvm/src/org/jetbrains/kotlin/config/JvmMfvcVArrayFlatteningScheme.kt
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.config
+
+/**
+ * VArray<Mfvc> flattening scheme
+ *
+ * See [explanation](https://github.com/grechkovlad/vArrayBenchmarksReport) what do these schemes mean
+ */
+enum class JvmMfvcVArrayFlatteningScheme {
+    PER_TYPE, PER_SIZE, THREE_ARRAYS, TWO_ARRAYS
+}
\ No newline at end of file
diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt
index 3e9f952..12e11f1 100644
--- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt
+++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt
@@ -415,6 +415,14 @@
         }
     }
 
+    override val vArrayIteratorFunction: IrSimpleFunctionSymbol? by lazy {
+        findFunctions(kotlinPackage, Name.identifier("iterator")).firstOrNull {
+            it.owner.extensionReceiverParameter?.type?.classOrNull == vArrayClass
+                    && it.owner.valueParameters.size == 0
+        }
+    }
+
+
     override lateinit var checkNotNullSymbol: IrSimpleFunctionSymbol private set
     override val arrayOfNulls: IrSimpleFunctionSymbol by lazy {
         findFunctions(kotlinPackage, Name.identifier("arrayOfNulls")).first {
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
index 65ceff7..2d7182b 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java
@@ -52198,6 +52198,124 @@
         public void testVarargParameterOfInlineType() throws Exception {
             runTest("compiler/testData/codegen/box/vArrays/varargParameterOfInlineType.kt");
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+            }
+
+            @Test
+            @TestMetadata("customIterator.kt")
+            public void testCustomIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("typesEncodings.kt")
+            public void testTypesEncodings() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt");
+            }
+
+            @Test
+            @TestMetadata("vArray2D.kt")
+            public void testVArray2D() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsFunctionParameter.kt")
+            public void testVArrayAsFunctionParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaParameter.kt")
+            public void testVArrayAsLambdaParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaReturnType.kt")
+            public void testVArrayAsLambdaReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsMfvcProperty.kt")
+            public void testVArrayAsMfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsProperty.kt")
+            public void testVArrayAsProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsPropertyNoBackingField.kt")
+            public void testVArrayAsPropertyNoBackingField() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsReturnType.kt")
+            public void testVArrayAsReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsSfvcProperty.kt")
+            public void testVArrayAsSfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayChainAssignment.kt")
+            public void testVArrayChainAssignment() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayExpression.kt")
+            public void testVArrayExpression() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInIfElseBlock.kt")
+            public void testVArrayInIfElseBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInTryBlock.kt")
+            public void testVArrayInTryBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInWhenExpr.kt")
+            public void testVArrayInWhenExpr() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayIterator.kt")
+            public void testVArrayIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("vArraySize.kt")
+            public void testVArraySize() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt");
+            }
+        }
     }
 
     @Nested
diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
index db04d46..89e56b1 100644
--- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
+++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java
@@ -52198,6 +52198,124 @@
         public void testVarargParameterOfInlineType() throws Exception {
             runTest("compiler/testData/codegen/box/vArrays/varargParameterOfInlineType.kt");
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+            }
+
+            @Test
+            @TestMetadata("customIterator.kt")
+            public void testCustomIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("typesEncodings.kt")
+            public void testTypesEncodings() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt");
+            }
+
+            @Test
+            @TestMetadata("vArray2D.kt")
+            public void testVArray2D() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsFunctionParameter.kt")
+            public void testVArrayAsFunctionParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaParameter.kt")
+            public void testVArrayAsLambdaParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaReturnType.kt")
+            public void testVArrayAsLambdaReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsMfvcProperty.kt")
+            public void testVArrayAsMfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsProperty.kt")
+            public void testVArrayAsProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsPropertyNoBackingField.kt")
+            public void testVArrayAsPropertyNoBackingField() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsReturnType.kt")
+            public void testVArrayAsReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsSfvcProperty.kt")
+            public void testVArrayAsSfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayChainAssignment.kt")
+            public void testVArrayChainAssignment() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayExpression.kt")
+            public void testVArrayExpression() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInIfElseBlock.kt")
+            public void testVArrayInIfElseBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInTryBlock.kt")
+            public void testVArrayInTryBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInWhenExpr.kt")
+            public void testVArrayInWhenExpr() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayIterator.kt")
+            public void testVArrayIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("vArraySize.kt")
+            public void testVArraySize() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt");
+            }
+        }
     }
 
     @Nested
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberHashCode.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberHashCode.kt
index 3e969c7..3a8548f 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberHashCode.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberHashCode.kt
@@ -9,16 +9,22 @@
 import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
 import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
 import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
+import org.jetbrains.kotlin.ir.types.classFqName
 import org.jetbrains.kotlin.ir.util.isPrimitiveArray
 
 object IrDataClassArrayMemberHashCode : IntrinsicMethod() {
     override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? =
         with(codegen) {
             val arrayType = expression.getValueArgument(0)!!.type
-            val asmArrayType = codegen.typeMapper.mapType(arrayType)
-            gen(expression.getValueArgument(0)!!, asmArrayType, arrayType, data)
-            val hashCodeArgumentDescriptor = if (arrayType.isPrimitiveArray()) asmArrayType.descriptor else "[Ljava/lang/Object;"
-            mv.invokestatic("java/util/Arrays", "hashCode", "($hashCodeArgumentDescriptor)I", false)
+            // TODO: temporary solution until implementation of VArrays.hashCode()
+            if (arrayType.classFqName!!.shortName().asString().startsWith("VArrayWrapper")) {
+                mv.aconst(0)
+            } else {
+                val asmArrayType = codegen.typeMapper.mapType(arrayType)
+                gen(expression.getValueArgument(0)!!, asmArrayType, arrayType, data)
+                val hashCodeArgumentDescriptor = if (arrayType.isPrimitiveArray()) asmArrayType.descriptor else "[Ljava/lang/Object;"
+                mv.invokestatic("java/util/Arrays", "hashCode", "($hashCodeArgumentDescriptor)I", false)
+            }
             return expression.onStack
         }
 }
diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberToString.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberToString.kt
index 162d58d..f29311f 100644
--- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberToString.kt
+++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrDataClassArrayMemberToString.kt
@@ -9,16 +9,22 @@
 import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
 import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
 import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
+import org.jetbrains.kotlin.ir.types.classFqName
 import org.jetbrains.kotlin.ir.util.isPrimitiveArray
 
 object IrDataClassArrayMemberToString : IntrinsicMethod() {
     override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? =
         with(codegen) {
             val arrayType = expression.getValueArgument(0)!!.type
-            val asmArrayType = codegen.typeMapper.mapType(arrayType)
-            gen(expression.getValueArgument(0)!!, asmArrayType, arrayType, data)
-            val toStringArgumentDescriptor = if (arrayType.isPrimitiveArray()) asmArrayType.descriptor else "[Ljava/lang/Object;"
-            mv.invokestatic("java/util/Arrays", "toString", "($toStringArgumentDescriptor)Ljava/lang/String;", false)
+            // TODO: temporary solution until implementation of VArrays.toString()
+            if (arrayType.classFqName!!.shortName().asString().startsWith("VArrayWrapper")) {
+                mv.aconst("STUB")
+            } else {
+                val asmArrayType = codegen.typeMapper.mapType(arrayType)
+                gen(expression.getValueArgument(0)!!, asmArrayType, arrayType, data)
+                val toStringArgumentDescriptor = if (arrayType.isPrimitiveArray()) asmArrayType.descriptor else "[Ljava/lang/Object;"
+                mv.invokestatic("java/util/Arrays", "toString", "($toStringArgumentDescriptor)Ljava/lang/String;", false)
+            }
             return expression.onStack
         }
 }
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
index 21f1bb8..c16460b 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt
@@ -14,6 +14,7 @@
 import org.jetbrains.kotlin.builtins.StandardNames
 import org.jetbrains.kotlin.config.ApiVersion
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
+import org.jetbrains.kotlin.descriptors.InlineClassRepresentation
 import org.jetbrains.kotlin.ir.IrStatement
 import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
 import org.jetbrains.kotlin.ir.builders.*
@@ -101,6 +102,8 @@
     }
 
     override fun handleSpecificNewClass(declaration: IrClass) {
+        transformInlineClassRepresentationIfNeeded(declaration)
+
         val irConstructor = declaration.primaryConstructor!!
         // The field getter is used by reflection and cannot be removed here unless it is internal.
         declaration.declarations.removeIf {
@@ -113,6 +116,16 @@
         addJvmInlineAnnotation(declaration)
     }
 
+    private fun transformInlineClassRepresentationIfNeeded(declaration: IrClass) {
+        require(declaration.inlineClassRepresentation != null)
+        val inlineClassRepresentation = declaration.inlineClassRepresentation!!
+        val transformedUnderlyingType =
+            applyVArrayWrappingTypeTransformation(inlineClassRepresentation.underlyingType, replacements.flatteningSymbolsHelper)
+        require(transformedUnderlyingType is IrSimpleType)
+        declaration.valueClassRepresentation =
+            InlineClassRepresentation(inlineClassRepresentation.underlyingPropertyName, transformedUnderlyingType)
+    }
+
     private fun addJvmInlineAnnotation(valueClass: IrClass) {
         if (valueClass.hasAnnotation(JVM_INLINE_ANNOTATION_FQ_NAME)) return
         val constructor = context.ir.symbols.jvmInlineAnnotation.constructors.first()
diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
index 164a1e1..f657cd5 100644
--- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
+++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmMultiFieldValueClassLowering.kt
@@ -8,6 +8,7 @@
 import org.jetbrains.kotlin.backend.common.ScopeWithIr
 import org.jetbrains.kotlin.backend.common.ir.inline
 import org.jetbrains.kotlin.backend.common.lower.irCatch
+import org.jetbrains.kotlin.backend.common.lower.irThrow
 import org.jetbrains.kotlin.backend.common.pop
 import org.jetbrains.kotlin.backend.common.push
 import org.jetbrains.kotlin.backend.jvm.*
@@ -19,9 +20,7 @@
 import org.jetbrains.kotlin.backend.jvm.lower.BlockOrBody.Block
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
 import org.jetbrains.kotlin.descriptors.Modality
-import org.jetbrains.kotlin.ir.IrElement
-import org.jetbrains.kotlin.ir.IrStatement
-import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
+import org.jetbrains.kotlin.ir.*
 import org.jetbrains.kotlin.ir.builders.*
 import org.jetbrains.kotlin.ir.builders.declarations.buildFun
 import org.jetbrains.kotlin.ir.declarations.*
@@ -30,16 +29,13 @@
 import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
 import org.jetbrains.kotlin.ir.expressions.impl.IrEnumConstructorCallImpl
 import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
-import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
-import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
-import org.jetbrains.kotlin.ir.symbols.IrSymbol
-import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
+import org.jetbrains.kotlin.ir.symbols.*
 import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
-import org.jetbrains.kotlin.ir.transformStatement
 import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.ir.visitors.*
 import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.name.StandardClassIds
 import org.jetbrains.kotlin.utils.addIfNotNull
 
 internal class JvmMultiFieldValueClassLowering(
@@ -196,6 +192,49 @@
             return getterExpression
         }
 
+        fun IrBlockBuilder.lowerMfvcVArrayGet(expression: IrCall): IrExpression {
+            val mfvcNode = replacements.getRootMfvcNode(expression.type.erasedUpperBound)
+            val mapper = replacements.getMfvcVArrayMapper(mfvcNode)
+            require(expression.dispatchReceiver != null)
+            val vArrayWrapperTempVariable = savableStandaloneVariableWithSetter(
+                expression = expression.dispatchReceiver!!,
+                origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+                saveVariable = ::variablesSaver
+            )
+            require(expression.valueArgumentsCount == 1)
+            val indexInVArrayExpr = expression.getValueArgument(0)!!
+            val indexInVArrayTempVariable = savableStandaloneVariableWithSetter(
+                expression = indexInVArrayExpr,
+                origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+                saveVariable = ::variablesSaver
+            )
+            val tempVariables = List(mfvcNode.leavesCount) { leafIndex ->
+                val mapping = mapper.map(indexInVArrayTempVariable, leafIndex, this, replacements.flatteningSymbolsHelper)
+                val leafValue = irCall(mapping.wrapperArrayGetFunction).apply {
+                    dispatchReceiver = irGetField(
+                        irGet(vArrayWrapperTempVariable),
+                        mapping.wrapperField.owner
+                    )
+                    putValueArgument(0, mapping.indexInWrapperArray)
+                }
+                val decodedValue = mapping.decodeFunction(leafValue, this)
+                // TODO: Investigate how to get rid of temporary variables. They are presumably blame for excess bytecode.
+                savableStandaloneVariableWithSetter(
+                    decodedValue,
+                    name = null,
+                    isMutable = false,
+                    origin = JvmLoweredDeclarationOrigin.MULTI_FIELD_VALUE_CLASS_REPRESENTATION_VARIABLE,
+                    saveVariable = ::variablesSaver
+                )
+            }
+            val typeArguments = makeTypeArgumentsFromType(expression.type as IrSimpleType)
+            val nodeInstance = ValueDeclarationMfvcNodeInstance(mfvcNode, typeArguments, tempVariables)
+            val resultExpr = nodeInstance.makeGetterExpression(this, irCurrentClass, ::registerPossibleExtraBoxUsage)
+            registerReplacement(resultExpr, nodeInstance)
+            +resultExpr
+            return resultExpr
+        }
+
         private fun makeTypeArgumentsFromField(expression: IrFieldAccessExpression) = buildMap {
             val field = expression.symbol.owner
             putAll(makeTypeArgumentsFromType(field.type as IrSimpleType))
@@ -303,9 +342,15 @@
             }
         }
 
+        transformVArrayTypes(declaration)
+
         return declaration
     }
 
+    private fun transformVArrayTypes(declaration: IrClass) {
+        declaration.transformChildrenVoid(MfvcVArrayTypeWrapperVisitor(replacements.flatteningSymbolsHelper))
+    }
+
     override fun visitClassNewDeclarationsWhenParallel(declaration: IrDeclaration) =
         postActionAfterTransformingClassDeclaration(declaration)
 
@@ -963,6 +1008,24 @@
                 }
             }
 
+            isCreationOfFlattenedVArray(expression, context) -> {
+                context.createJvmIrBuilder(currentScope.symbol, expression).irBlock {
+                    require(expression.typeArgumentsCount == 1)
+                    val rootNode = replacements.getRootMfvcNode(expression.getTypeArgument(0)!!.erasedUpperBound)
+                    val flatteningScheme = replacements.getMfvcVArrayMapper(rootNode)
+                    require(expression.valueArgumentsCount == 1)
+                    val vArraySizeExpr = expression.getValueArgument(0)!!
+                    val constructorCall =
+                        flatteningScheme.getVArrayWrapperCreationCall(
+                            vArraySizeExpr,
+                            this,
+                            replacements.flatteningSymbolsHelper,
+                            ::variablesSaver
+                        )
+                    +constructorCall
+                }.unwrapBlock()
+            }
+
             replacement != null -> context.createJvmIrBuilder(currentScope.symbol, expression).irBlock {
                 buildReplacement(function, expression, replacement)
             }.unwrapBlock()
@@ -1069,9 +1132,177 @@
                 }
             }.unwrapBlock()
         }
+        if (isGetOnFlattenedVArray(expression, replacements.flatteningSymbolsHelper)) {
+            expression.transformChildrenVoid()
+            return context.createJvmIrBuilder(getCurrentScopeSymbol(), expression).irBlock {
+                with(valueDeclarationsRemapper) {
+                    lowerMfvcVArrayGet(expression)
+                }
+            }.unwrapBlock()
+        }
+        if (isSetOnFlattenVArray(expression, replacements.flatteningSymbolsHelper)) {
+            expression.transformChildrenVoid()
+            val flattenSetBlock = context.createJvmIrBuilder(getCurrentScopeSymbol(), expression).irBlock {
+                lowerMfvcVArraySet(expression)
+            }
+            return flattenSetBlock
+        }
+        if (isGetSizeOnFlattenedVArray(expression, replacements.flatteningSymbolsHelper)) {
+            expression.transformChildrenVoid()
+            return context.createJvmIrBuilder(getCurrentScopeSymbol(), expression)
+                .irGetField(expression.dispatchReceiver!!, replacements.flatteningSymbolsHelper.wrapperSizeField.owner)
+        }
+        if (isFlattenedVArrayIteratorCreation(expression, context)) {
+            require(expression.extensionReceiver != null)
+            expression.transformChildrenVoid()
+            return with(context.createJvmIrBuilder(getCurrentScopeSymbol(), expression)) {
+                irCall(replacements.flatteningSymbolsHelper.vArrayWrapperIteratorStateHolderConstructor).apply {
+                    putValueArgument(0, expression.extensionReceiver)
+                    putValueArgument(1, irInt(0))
+                }
+            }
+        }
+        if (isFlattenedVArrayIteratorHasNext(expression)) {
+            expression.transformChildrenVoid()
+            return context.createJvmIrBuilder(getCurrentScopeSymbol(), expression).irBlock {
+                lowerMfvcVArrayIteratorHasNext(expression)
+            }
+        }
+        if (isFlattenedVArrayIteratorNext(expression)) {
+            val lowered = context.createJvmIrBuilder(getCurrentScopeSymbol(), expression).irBlock {
+                lowerMfvcVArrayIteratorNext(expression)
+            }
+            lowered.transformChildrenVoid()
+            return lowered
+        }
         return super.visitCall(expression)
     }
 
+    private fun IrBlockBuilder.lowerMfvcVArrayIteratorNext(expression: IrCall) {
+        require(expression.dispatchReceiver != null)
+        val symbols = replacements.flatteningSymbolsHelper
+        // Generate IR for:
+        // try { it.array[it.index++] } catch (e: ArrayIndexOutOfBoundsException) { it.index--; throw NoSuchElementException(e.message) }
+        val iteratorTempVariable = savableStandaloneVariableWithSetter(
+            expression = expression.dispatchReceiver!!,
+            origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+            saveVariable = ::variablesSaver
+        )
+        val vArrayGet = irCall(symbols.vArrayGet!!, expression.type).apply {
+            dispatchReceiver = irGetField(irGet(iteratorTempVariable), symbols.vArrayWrapperIteratorStateHolderArrayField.owner)
+            putValueArgument(0, irBlock {
+                val indexTempVariable = savableStandaloneVariableWithSetter(
+                    expression = irGetField(irGet(iteratorTempVariable), symbols.vArrayWrapperIteratorStateHolderIndexField.owner),
+                    origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+                    saveVariable = ::variablesSaver
+                )
+                +irSetField(
+                    irGet(iteratorTempVariable),
+                    symbols.vArrayWrapperIteratorStateHolderIndexField.owner,
+                    irCall(context.irBuiltIns.intClass.getSimpleFunction("inc")!!).apply {
+                        dispatchReceiver = irGet(indexTempVariable)
+                    }
+                )
+                +irGet(indexTempVariable)
+            })
+        }
+        val catchParameter = savableStandaloneVariable(
+            type = this@JvmMultiFieldValueClassLowering.context.ir.symbols.arrayIndexOutOfBoundsException.defaultType,
+            isVar = false,
+            origin = IrDeclarationOrigin.CATCH_PARAMETER,
+            saveVariable = {}
+        )
+        +irTry(
+            type = expression.type,
+            tryResult = vArrayGet,
+            catches = listOf(irCatch(
+                catchParameter = catchParameter,
+                result = irBlock {
+                    +irSetField(
+                        irGet(iteratorTempVariable),
+                        symbols.vArrayWrapperIteratorStateHolderIndexField.owner,
+                        irCall(context.irBuiltIns.intClass.getSimpleFunction("dec")!!).apply {
+                            dispatchReceiver =
+                                irGetField(irGet(iteratorTempVariable), symbols.vArrayWrapperIteratorStateHolderIndexField.owner)
+                        })
+                    +irThrow(irCall(symbols.noSuchElementExceptionConstructor).apply {
+                        putValueArgument(0, irCall(symbols.throwableMessageGetter).apply {
+                            dispatchReceiver = irGet(catchParameter)
+                        })
+                    })
+                }
+            )),
+            finallyExpression = null
+        )
+    }
+
+    private fun IrBlockBuilder.lowerMfvcVArrayIteratorHasNext(expression: IrCall) {
+        require(expression.dispatchReceiver != null)
+        val iteratorTempVariable = savableStandaloneVariableWithSetter(
+            expression = expression.dispatchReceiver!!,
+            origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+            saveVariable = ::variablesSaver
+        )
+        // IR for: iteratorStateHolder.index < iteratorStateHolder.array.size
+        +irCall(context.irBuiltIns.lessFunByOperandType[context.irBuiltIns.intType.classifierOrFail]!!).apply {
+            putValueArgument(
+                0,
+                irGetField(
+                    irGet(iteratorTempVariable),
+                    replacements.flatteningSymbolsHelper.vArrayWrapperIteratorStateHolderIndexField.owner
+                )
+            )
+            putValueArgument(
+                1,
+                irGetField(
+                    irGetField(
+                        irGet(iteratorTempVariable),
+                        replacements.flatteningSymbolsHelper.vArrayWrapperIteratorStateHolderArrayField.owner
+                    ), replacements.flatteningSymbolsHelper.wrapperSizeField.owner
+                )
+            )
+        }
+    }
+
+    private fun IrBlockBuilder.lowerMfvcVArraySet(setCall: IrCall) {
+        require(setCall.valueArgumentsCount == 2)
+        val vArrayIndexExpr = setCall.getValueArgument(0)!!
+        val vArrayIndexTempVariable = savableStandaloneVariableWithSetter(
+            expression = vArrayIndexExpr,
+            origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+            saveVariable = ::variablesSaver
+        )
+        val tempVariableForSetValue = savableStandaloneVariableWithSetter(
+            setCall.getValueArgument(1)!!,
+            origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+            saveVariable = ::variablesSaver
+        )
+        require(setCall.dispatchReceiver != null)
+        val vArrayWrapperTempVariable = savableStandaloneVariableWithSetter(
+            expression = setCall.dispatchReceiver!!,
+            origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+            saveVariable = ::variablesSaver
+        )
+        val mfvcNode = replacements.getRootMfvcNode(setCall.getValueArgument(1)!!.type.erasedUpperBound)
+        val mapper = replacements.getMfvcVArrayMapper(mfvcNode)
+        mfvcNode.leaves.forEachIndexed { leafIndex, leaf ->
+            val mapping = mapper.map(vArrayIndexTempVariable, leafIndex, this, replacements.flatteningSymbolsHelper)
+            val leafValue = irCall(leaf.unboxMethod).apply {
+                dispatchReceiver = irGet(tempVariableForSetValue)
+            }
+            val encodedValue = mapping.encodeFunction(leafValue, this)
+            val leafSetCall = irCall(mapping.wrapperArraySetFunction).apply {
+                dispatchReceiver = irGetField(
+                    irGet(vArrayWrapperTempVariable),
+                    mapping.wrapperField.owner
+                )
+                putValueArgument(0, mapping.indexInWrapperArray)
+                putValueArgument(1, encodedValue)
+            }
+            +leafSetCall
+        }
+    }
+
     private fun IrBlockBuilder.buildReplacement(
         originalFunction: IrFunction,
         original: IrMemberAccessExpression<*>,
@@ -1671,3 +1902,70 @@
     clear()
     addAll(replacement)
 }
+
+private fun isFlattenedVArrayIterator(type: IrType): Boolean {
+    if (type !is IrSimpleType) return false
+    if (type.classFqName != StandardClassIds.vArrayIterator.asSingleFqName()) return false
+    require(type.arguments.size == 1)
+    val typeArg = type.arguments[0]
+    require(typeArg is IrSimpleType)
+    return typeArg.needsMfvcFlattening()
+}
+
+private fun isFlattenedVArrayIteratorNext(expression: IrCall): Boolean {
+    if (expression.dispatchReceiver == null) return false
+    return isFlattenedVArrayIterator(expression.dispatchReceiver!!.type) && expression.symbol.owner.name == Name.identifier("next")
+}
+
+private fun isFlattenedVArrayIteratorHasNext(expression: IrCall): Boolean {
+    if (expression.dispatchReceiver == null) return false
+    return isFlattenedVArrayIterator(expression.dispatchReceiver!!.type) && expression.symbol.owner.name == Name.identifier("hasNext")
+}
+
+private fun isFlattenedVArrayIteratorCreation(expression: IrCall, context: JvmBackendContext) =
+    expression.symbol == context.irBuiltIns.vArrayIteratorFunction && expression.extensionReceiver?.type?.isFlattenedVArray() == true
+
+private fun isCreationOfFlattenedVArray(expression: IrFunctionAccessExpression, context: JvmBackendContext) =
+    expression.symbol == context.irBuiltIns.vArrayOfNulls && expression.type.isFlattenedVArray()
+
+private fun isGetSizeOnFlattenedVArray(expression: IrCall, symbols: FlatteningSymbolsHelper) =
+    expression.symbol == symbols.vArraySizeGetter && expression.dispatchReceiver?.type?.isFlattenedVArray() == true
+
+private fun isGetOnFlattenedVArray(expression: IrCall, symbols: FlatteningSymbolsHelper) =
+    expression.symbol == symbols.vArrayGet && expression.type.needsMfvcFlattening()
+
+private fun isSetOnFlattenVArray(expression: IrCall, symbols: FlatteningSymbolsHelper) =
+    expression.symbol == symbols.vArraySet && expression.getValueArgument(1)?.type?.needsMfvcFlattening() == true
+
+private class MfvcVArrayTypeWrapperVisitor(private val symbols: FlatteningSymbolsHelper) :
+    IrElementTransformerVoid() {
+
+    override fun visitCall(expression: IrCall): IrExpression {
+        return visitExpression(expression)
+    }
+
+    override fun visitExpression(expression: IrExpression): IrExpression {
+        expression.type = applyVArrayWrappingTypeTransformation(expression.type, symbols)
+        return super.visitExpression(expression)
+    }
+
+    override fun visitValueParameter(declaration: IrValueParameter): IrStatement {
+        declaration.type = applyVArrayWrappingTypeTransformation(declaration.type, symbols)
+        return super.visitValueParameter(declaration)
+    }
+
+    override fun visitField(declaration: IrField): IrStatement {
+        declaration.type = applyVArrayWrappingTypeTransformation(declaration.type, symbols)
+        return super.visitField(declaration)
+    }
+
+    override fun visitVariable(declaration: IrVariable): IrStatement {
+        declaration.type = applyVArrayWrappingTypeTransformation(declaration.type, symbols)
+        return super.visitVariable(declaration)
+    }
+
+    override fun visitFunction(declaration: IrFunction): IrStatement {
+        declaration.returnType = applyVArrayWrappingTypeTransformation(declaration.returnType, symbols)
+        return super.visitFunction(declaration)
+    }
+}
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
index 0606ee3..24286e6 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmSymbols.kt
@@ -649,6 +649,54 @@
     val arrayOfAnyType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyType)
     val arrayOfAnyNType = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
 
+    private fun IrClass.addPrimaryConstructorByFields() {
+        addConstructor { isPrimary = true }.apply {
+            fields.forEach { field -> addValueParameter(field.name, field.type) }
+        }
+    }
+
+    val vArrayWrapperPerSizeClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.VArrayWrapperPerSize")) { klass ->
+        klass.addField("ones", irBuiltIns.byteArray.defaultType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("twos", irBuiltIns.shortArray.defaultType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("fours", irBuiltIns.intArray.defaultType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("eights", irBuiltIns.longArray.defaultType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("refs", arrayOfAnyNType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("size", irBuiltIns.intType, DescriptorVisibilities.PUBLIC)
+
+        klass.addPrimaryConstructorByFields()
+    }
+
+    val vArrayWrapperTwoArrays: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.VArrayWrapperTwoArrays")) { klass ->
+        klass.addField("longs", irBuiltIns.longArray.defaultType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("refs", arrayOfAnyNType.makeNullable(), DescriptorVisibilities.PUBLIC)
+        klass.addField("size", irBuiltIns.intType, DescriptorVisibilities.PUBLIC)
+
+        klass.addPrimaryConstructorByFields()
+    }
+
+    val vArrayPerSizeIteratorStateHolder: IrClassSymbol =
+        createClass(FqName("kotlin.jvm.internal.VArrayPerSizeIteratorStateHolder")) { klass ->
+            klass.addField("array", vArrayWrapperPerSizeClass.owner.defaultType, DescriptorVisibilities.PUBLIC)
+            klass.addField("index", irBuiltIns.intType, DescriptorVisibilities.PUBLIC)
+
+            klass.addPrimaryConstructorByFields()
+        }
+
+    val vArrayTwoArraysIteratorStateHolder: IrClassSymbol =
+        createClass(FqName("kotlin.jvm.internal.VArrayTwoArraysIteratorStateHolder")) { klass ->
+            klass.addField("array", vArrayWrapperTwoArrays.owner.defaultType, DescriptorVisibilities.PUBLIC)
+            klass.addField("index", irBuiltIns.intType, DescriptorVisibilities.PUBLIC)
+
+            klass.addPrimaryConstructorByFields()
+        }
+
+    val arrayIndexOutOfBoundsException: IrClassSymbol = createClass(FqName("java.lang.ArrayIndexOutOfBoundsException"))
+    val noSuchElementException: IrClassSymbol = createClass(FqName("java.util.NoSuchElementException")) { klass ->
+        klass.addConstructor().apply {
+            addValueParameter("message", string.defaultType)
+        }
+    }
+
     // Intrinsic to represent closure creation using INVOKEDYNAMIC with LambdaMetafactory.{metafactory, altMetafactory}
     // as a bootstrap method.
     //      fun <SAM_TYPE> `<jvm-indy-lambda-metafactory>`(
@@ -832,6 +880,60 @@
         }
     }
 
+    val charCodeGetter: IrFunctionSymbol =
+        irFactory.buildProperty {
+            name = Name.identifier("code")
+        }.apply {
+            parent = createClass(FqName("kotlin.CharCodeKt")).owner
+            addGetter().apply {
+                isInline = true
+                addExtensionReceiver(irBuiltIns.charType)
+                returnType = irBuiltIns.intType
+            }
+        }.getter!!.symbol
+
+    val floatToRawBits: IrFunctionSymbol =
+        irFactory.buildFun {
+            name = Name.identifier("toRawBits")
+        }.apply {
+            isInline = true
+            parent = createClass(FqName("kotlin.NumbersKt__NumbersJVMKt")).owner
+            addExtensionReceiver(irBuiltIns.floatType)
+            returnType = irBuiltIns.intType
+        }.symbol
+
+    val floatFromBits: IrSimpleFunctionSymbol =
+        irFactory.buildFun {
+            name = Name.identifier("fromBits")
+        }.apply {
+            isInline = true
+            parent = createClass(FqName("kotlin.NumbersKt__NumbersJVMKt")).owner
+            addExtensionReceiver(irBuiltIns.floatClass.owner.companionObject()!!.defaultType)
+            addValueParameter("bits", irBuiltIns.intType)
+            returnType = irBuiltIns.floatType
+        }.symbol
+
+    val doubleFromBits: IrSimpleFunctionSymbol =
+        irFactory.buildFun {
+            name = Name.identifier("fromBits")
+        }.apply {
+            isInline = true
+            parent = createClass(FqName("kotlin.NumbersKt__NumbersJVMKt")).owner
+            addExtensionReceiver(irBuiltIns.doubleClass.owner.companionObject()!!.defaultType)
+            addValueParameter("bits", irBuiltIns.longType)
+            returnType = irBuiltIns.doubleType
+        }.symbol
+
+    val doubleToRawBits: IrFunctionSymbol =
+        irFactory.buildFun {
+            name = Name.identifier("toRawBits")
+        }.apply {
+            isInline = true
+            parent = createClass(FqName("kotlin.NumbersKt__NumbersJVMKt")).owner
+            addExtensionReceiver(irBuiltIns.doubleType)
+            returnType = irBuiltIns.longType
+        }.symbol
+
     val kClassJava: IrPropertySymbol =
         irFactory.buildProperty {
             name = Name.identifier("java")
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
index 48e194d..254134f 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedMultiFieldValueClassReplacements.kt
@@ -7,6 +7,7 @@
 
 import org.jetbrains.kotlin.backend.jvm.MemoizedMultiFieldValueClassReplacements.RemappedParameter.MultiFieldValueClassMapping
 import org.jetbrains.kotlin.backend.jvm.ir.*
+import org.jetbrains.kotlin.config.JvmMfvcVArrayFlatteningScheme
 import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
 import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
 import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
@@ -15,9 +16,7 @@
 import org.jetbrains.kotlin.ir.declarations.*
 import org.jetbrains.kotlin.ir.expressions.IrExpression
 import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
-import org.jetbrains.kotlin.ir.types.IrSimpleType
-import org.jetbrains.kotlin.ir.types.IrType
-import org.jetbrains.kotlin.ir.types.defaultType
+import org.jetbrains.kotlin.ir.types.*
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.name.Name
 import org.jetbrains.kotlin.resolve.InlineClassDescriptorResolver
@@ -307,6 +306,15 @@
         getRootNode(context, it)
     }
 
+    val getMfvcVArrayMapper: (RootMfvcNode) -> MfvcVArrayMapper = storageManager.createMemoizedFunction {
+        when (context.state.mfvcVArrayFlatteningScheme) {
+            JvmMfvcVArrayFlatteningScheme.PER_TYPE -> TODO("Scheme is not implemented yet")
+            JvmMfvcVArrayFlatteningScheme.PER_SIZE -> PerSizeMapper(it, flatteningSymbolsHelper)
+            JvmMfvcVArrayFlatteningScheme.THREE_ARRAYS -> TODO("Scheme is not implemented yet")
+            JvmMfvcVArrayFlatteningScheme.TWO_ARRAYS -> TwoArraysMapper(it, flatteningSymbolsHelper)
+        }
+    }
+
     fun getRootMfvcNodeOrNull(irClass: IrClass): RootMfvcNode? =
         if (irClass.defaultType.needsMfvcFlattening()) getRootMfvcNode(irClass) else null
 
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt
index 8304a1d..f4bda22 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MemoizedValueClassAbstractReplacements.kt
@@ -26,6 +26,8 @@
 ) {
     private val propertyMap = ConcurrentHashMap<IrPropertySymbol, IrProperty>()
 
+    val flatteningSymbolsHelper = FlatteningSymbolsHelper(context)
+
     /**
      * Get a replacement for a function or a constructor.
      */
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
index c5abecd..7e4f1cc 100644
--- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/MfvcNode.kt
@@ -24,6 +24,7 @@
 import org.jetbrains.kotlin.ir.util.*
 import org.jetbrains.kotlin.load.java.JvmAbi
 import org.jetbrains.kotlin.name.Name
+import org.jetbrains.kotlin.name.StandardClassIds
 
 typealias TypeArguments = Map<IrTypeParameterSymbol, IrType>
 
@@ -458,3 +459,27 @@
         classifierOrNull.let { classifier ->
             classifier is IrTypeParameterSymbol && classifier.owner.superTypes.any { it.needsMfvcFlattening() }
         } // add not is annotated as @UseBox etc
+
+fun IrType.isFlattenedVArray() =
+    isVArray && (this as? IrSimpleType)?.arguments?.let { it.size == 1 && ((it[0] as? IrType)?.needsMfvcFlattening() == true) } == true
+
+fun applyVArrayWrappingTypeTransformation(irType: IrType, symbols: FlatteningSymbolsHelper): IrType = when {
+    // TODO Investigate if we need to transform arguments of non-reified type, i.e. X<VArray<MFVC>> -> X<VArrayWrapper>
+    irType.isFlattenedVArray() -> symbols.vArrayWrapperClass.defaultType
+    irType.isVArray -> {
+        val typeArg = (irType as IrSimpleType).arguments[0]
+        require(typeArg is IrType)
+        symbols.backendContext.irBuiltIns.vArrayClass!!.typeWith(applyVArrayWrappingTypeTransformation(typeArg, symbols))
+    }
+    irType.isBoxedArray -> irType // TODO Transform array type argument, i.e. Array<VArray<Mfvc>> -> Array<VArrayWrapper>
+    isFlattenedVArrayIterator(irType) -> symbols.vArrayWrapperIteratorStateHolderClass.defaultType
+    else -> irType
+}
+
+fun isFlattenedVArrayIterator(irType: IrType): Boolean {
+    if (irType !is IrSimpleType) return false
+    if (irType.classFqName != StandardClassIds.vArrayIterator.asSingleFqName()) return false
+    val typeArg = irType.arguments[0]
+    if (typeArg !is IrType) return false
+    return typeArg.needsMfvcFlattening()
+}
diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mfvcVArrayMapping.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mfvcVArrayMapping.kt
new file mode 100644
index 0000000..6d9e623
--- /dev/null
+++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/mfvcVArrayMapping.kt
@@ -0,0 +1,554 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.backend.jvm
+
+import org.jetbrains.kotlin.config.JvmMfvcVArrayFlatteningScheme
+import org.jetbrains.kotlin.ir.builders.*
+import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
+import org.jetbrains.kotlin.ir.declarations.IrVariable
+import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
+import org.jetbrains.kotlin.ir.expressions.IrExpression
+import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
+import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
+import org.jetbrains.kotlin.ir.types.*
+import org.jetbrains.kotlin.ir.util.*
+import org.jetbrains.kotlin.name.Name
+
+/**
+ * Mapping of [LeafMfvcNode] of VArray<Mfvc> element
+ *
+ * Contains information how [LeafMfvcNode] of VArray<Mfvc> maps onto element of flattened array representation
+ *
+ * @property wrapperField Field of wrapper of flattened representation which contains the leaf value
+ * @property indexInWrapperArray Index in array stored in [wrapperField] which contains the leaf value
+ * @property wrapperArrayGetFunction Array *get* function for array stored in [wrapperField]
+ * @property wrapperArraySetFunction Array *set* function for array stored in [wrapperField]
+ * @property encodeFunction Function that returns IR for encoded value, which actually stored in [wrapperField] by original leaf value
+ * @property decodeFunction Function that returns IR for decoded, original leaf value
+ */
+class MfvcVArrayMapping(
+    val wrapperField: IrFieldSymbol,
+    val indexInWrapperArray: IrExpression,
+    val wrapperArrayGetFunction: IrFunctionSymbol,
+    val wrapperArraySetFunction: IrFunctionSymbol,
+    val encodeFunction: (IrExpression, IrBuilderWithScope) -> IrExpression,
+    val decodeFunction: (IrExpression, IrBuilderWithScope) -> IrExpression
+)
+
+abstract class MfvcVArrayMapper(protected val mfvcNode: RootMfvcNode) {
+    internal abstract val wrapperField: Map<LeafType, IrFieldSymbol>
+    internal abstract val groupSizeForType: Map<LeafType, Int>
+    internal abstract val groupSizes: List<Int>
+    internal abstract val arrayConstructors: List<IrFunctionSymbol>
+    internal abstract val arrayGetFunctions: Map<LeafType, IrFunctionSymbol>
+    internal abstract val arraySetFunctions: Map<LeafType, IrFunctionSymbol>
+    internal abstract val encodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+    internal abstract val decodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+    abstract val indexOfLeafInGroup: IntArray
+
+    fun map(
+        indexInVArrayVariable: IrVariable,
+        leafIndex: Int,
+        builder: IrBlockBuilder,
+        symbols: FlatteningSymbolsHelper
+    ): MfvcVArrayMapping {
+        val leafType = LeafType.fromIrType(mfvcNode.leaves[leafIndex].type)
+
+        // Suppose Mfvc has group_size leafs that stored in the same array as given leaf.
+        // Suppose that given leaf is leaf_index-th in the set of leafs stored in that array.
+        // Then, leaf has index indexInVArrayVariable * group_size + leaf_index in that array.
+        val indexInWrapperArray = with(builder) {
+            irCallOp(
+                symbols.backendContext.irBuiltIns.intPlusSymbol,
+                symbols.backendContext.irBuiltIns.intType,
+                irCallOp(
+                    symbols.backendContext.irBuiltIns.intTimesSymbol,
+                    symbols.backendContext.irBuiltIns.intType,
+                    irGet(indexInVArrayVariable),
+                    irInt(groupSizeForType[leafType]!!)
+                ),
+                irInt(indexOfLeafInGroup[leafIndex])
+            )
+        }
+
+        return MfvcVArrayMapping(
+            wrapperField = wrapperField[leafType]!!,
+            indexInWrapperArray = indexInWrapperArray,
+            wrapperArrayGetFunction = arrayGetFunctions[leafType]!!,
+            wrapperArraySetFunction = arraySetFunctions[leafType]!!,
+            encodeFunction = encodingFunctions[leafType]!!,
+            decodeFunction = decodingFunctions[leafType]!!
+        )
+    }
+
+    fun getVArrayWrapperCreationCall(
+        vArraySize: IrExpression,
+        builder: IrBlockBuilder,
+        symbols: FlatteningSymbolsHelper,
+        saveVariable: (IrVariable) -> Unit
+    ): IrConstructorCall =
+
+        with(builder) {
+
+            val vArraySizeTempVariable = savableStandaloneVariableWithSetter(
+                expression = vArraySize,
+                origin = IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
+                saveVariable = saveVariable
+            )
+
+            fun getArrayArgument(leafsOfThisTypeCount: Int, arrayCreationFunction: IrFunctionSymbol): IrExpression {
+                if (leafsOfThisTypeCount == 0) return irNull()
+                val arrayType = if (arrayCreationFunction == symbols.backendContext.irBuiltIns.arrayOfNulls)
+                    symbols.backendContext.irBuiltIns.arrayClass.typeWith(listOf(symbols.backendContext.irBuiltIns.anyNType))
+                else
+                    arrayCreationFunction.owner.returnType
+                return irCall(arrayCreationFunction, arrayType).apply {
+                    putValueArgument(
+                        0, irCallOp(
+                            context.irBuiltIns.intTimesSymbol,
+                            context.irBuiltIns.intType,
+                            irGet(vArraySizeTempVariable),
+                            irInt(leafsOfThisTypeCount)
+                        )
+                    )
+                    if (arrayCreationFunction == symbols.backendContext.irBuiltIns.arrayOfNulls) {
+                        putTypeArgument(0, symbols.backendContext.irBuiltIns.anyNType)
+                    }
+                }
+            }
+
+            val wrapperConstructorArguments = buildList {
+                groupSizes.zip(arrayConstructors).map { (groupSize, arrayConstructor) ->
+                    add(getArrayArgument(groupSize, arrayConstructor))
+                }
+                add(irGet(vArraySizeTempVariable))
+            }
+
+            return irCall(symbols.vArrayWrapperConstructor).apply {
+                wrapperConstructorArguments.forEachIndexed { index, argument ->
+                    putValueArgument(index, argument)
+                }
+            }
+        }
+}
+
+private object Names {
+    const val GET = "get"
+    const val SET = "set"
+    const val ONES = "ones"
+    const val TWOS = "twos"
+    const val FOURS = "fours"
+    const val EIGHTS = "eights"
+    const val REFS = "refs"
+    const val LONGS = "longs"
+}
+
+class FlatteningSymbolsHelper(val backendContext: JvmBackendContext) {
+
+    val bytesGetFunction = backendContext.irBuiltIns.byteArray.functionByName(Names.GET)
+    val shortsGetFunction = backendContext.irBuiltIns.shortArray.functionByName(Names.GET)
+    val intsGetFunction = backendContext.irBuiltIns.intArray.functionByName(Names.GET)
+    val longsGetFunction = backendContext.irBuiltIns.longArray.functionByName(Names.GET)
+    val refsGetFunction = backendContext.irBuiltIns.arrayClass.functionByName(Names.GET)
+
+    val bytesSetFunction = backendContext.irBuiltIns.byteArray.functionByName(Names.SET)
+    val shortsSetFunction = backendContext.irBuiltIns.shortArray.functionByName(Names.SET)
+    val intsSetFunction = backendContext.irBuiltIns.intArray.functionByName(Names.SET)
+    val longsSetFunction = backendContext.irBuiltIns.longArray.functionByName(Names.SET)
+    val refsSetFunction = backendContext.irBuiltIns.arrayClass.functionByName(Names.SET)
+
+    val byteToLong = backendContext.irBuiltIns.byteClass.functionByName("toLong")
+    val shortToLong = backendContext.irBuiltIns.shortClass.functionByName("toLong")
+    val intToLong = backendContext.irBuiltIns.intClass.functionByName("toLong")
+
+    val intToShort = backendContext.irBuiltIns.intClass.functionByName("toShort")
+    val intToChar = backendContext.irBuiltIns.intClass.functionByName("toChar")
+    val shortToInt = backendContext.irBuiltIns.shortClass.functionByName("toInt")
+
+    val longToByte = backendContext.irBuiltIns.longClass.functionByName("toByte")
+    val longToShort = backendContext.irBuiltIns.longClass.functionByName("toShort")
+    val longToInt = backendContext.irBuiltIns.longClass.functionByName("toInt")
+
+    val floatCompanion = backendContext.irBuiltIns.floatClass.owner.companionObject()!!.symbol
+    val doubleCompanion = backendContext.irBuiltIns.doubleClass.owner.companionObject()!!.symbol
+
+    val byteArrayConstructor = backendContext.irBuiltIns.byteArray.constructors.single { it.owner.valueParameters.size == 1 }
+    val shortArrayConstructor = backendContext.irBuiltIns.shortArray.constructors.single { it.owner.valueParameters.size == 1 }
+    val intArrayConstructor = backendContext.irBuiltIns.intArray.constructors.single { it.owner.valueParameters.size == 1 }
+    val longArrayConstructor = backendContext.irBuiltIns.longArray.constructors.single { it.owner.valueParameters.size == 1 }
+
+    val vArrayWrapperClass = when (backendContext.state.mfvcVArrayFlatteningScheme) {
+        JvmMfvcVArrayFlatteningScheme.PER_TYPE -> TODO("Flattening scheme is not implemented yet")
+        JvmMfvcVArrayFlatteningScheme.PER_SIZE -> backendContext.ir.symbols.vArrayWrapperPerSizeClass
+        JvmMfvcVArrayFlatteningScheme.THREE_ARRAYS -> TODO("Flattening scheme is not implemented yet")
+        JvmMfvcVArrayFlatteningScheme.TWO_ARRAYS -> backendContext.ir.symbols.vArrayWrapperTwoArrays
+    }
+
+    val vArrayWrapperIteratorStateHolderClass = when (backendContext.state.mfvcVArrayFlatteningScheme) {
+        JvmMfvcVArrayFlatteningScheme.PER_TYPE -> TODO("Flattening scheme is not implemented yet")
+        JvmMfvcVArrayFlatteningScheme.PER_SIZE -> backendContext.ir.symbols.vArrayPerSizeIteratorStateHolder
+        JvmMfvcVArrayFlatteningScheme.THREE_ARRAYS -> TODO("Flattening scheme is not implemented yet")
+        JvmMfvcVArrayFlatteningScheme.TWO_ARRAYS -> backendContext.ir.symbols.vArrayTwoArraysIteratorStateHolder
+    }
+
+    val vArrayWrapperConstructor = vArrayWrapperClass.constructors.single { it.owner.isPrimary }
+    val vArrayWrapperIteratorStateHolderConstructor = vArrayWrapperIteratorStateHolderClass.constructors.single { it.owner.isPrimary }
+
+    val vArrayGet = backendContext.irBuiltIns.vArrayClass?.functions?.single { it.owner.name == Name.identifier("get") }
+    val vArraySet = backendContext.irBuiltIns.vArrayClass?.functions?.single { it.owner.name == Name.identifier("set") }
+    val vArraySizeGetter = backendContext.irBuiltIns.vArrayClass?.getPropertyGetter("size")
+
+    val wrapperSizeField = vArrayWrapperClass.fieldByName("size")
+    val vArrayWrapperIteratorStateHolderIndexField = vArrayWrapperIteratorStateHolderClass.fieldByName("index")
+    val vArrayWrapperIteratorStateHolderArrayField = vArrayWrapperIteratorStateHolderClass.fieldByName("array")
+
+    val noSuchElementExceptionConstructor = backendContext.ir.symbols.noSuchElementException.constructors.single()
+
+    val throwableMessageGetter = backendContext.irBuiltIns.throwableClass.getPropertyGetter("message")!!
+}
+
+internal enum class LeafType {
+    BOOL, BYTE, SHORT, CHAR, INT, FLOAT, LONG, DOUBLE, REF;
+
+    companion object {
+        fun fromIrType(type: IrType) = when {
+            type.isBoolean() -> BOOL
+            type.isByte() -> BYTE
+            type.isShort() -> SHORT
+            type.isChar() -> CHAR
+            type.isInt() -> INT
+            type.isFloat() -> FLOAT
+            type.isLong() -> LONG
+            type.isDouble() -> DOUBLE
+            else -> REF
+        }
+    }
+}
+
+fun boolToByte(boolExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irIfThenElse(
+        type = symbols.backendContext.irBuiltIns.byteType,
+        condition = boolExpr,
+        thenPart = irByte(1),
+        elsePart = irByte(0)
+    )
+}
+
+fun boolToLong(boolExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irIfThenElse(
+        type = symbols.backendContext.irBuiltIns.longType,
+        condition = boolExpr,
+        thenPart = irLong(1),
+        elsePart = irLong(0)
+    )
+}
+
+fun byteToLong(byteExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.byteToLong).apply {
+        dispatchReceiver = byteExpr
+    }
+}
+
+fun shortToLong(shortExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.shortToLong).apply {
+        dispatchReceiver = shortExpr
+    }
+}
+
+fun charToLong(charExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) =
+    shortToLong(charToShort(charExpr, irBuilder, symbols), irBuilder, symbols)
+
+fun floatToLong(floatExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) =
+    intToLong(floatToInt(floatExpr, irBuilder, symbols), irBuilder, symbols)
+
+fun intToLong(intExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.intToLong).apply {
+        dispatchReceiver = intExpr
+    }
+}
+
+fun numericToBool(numericExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper, zero: IrExpression) =
+    with(irBuilder) {
+        irCallOp(
+            callee = symbols.backendContext.irBuiltIns.booleanNotSymbol,
+            type = symbols.backendContext.irBuiltIns.booleanType,
+            dispatchReceiver = irCall(symbols.backendContext.irBuiltIns.eqeqSymbol).apply {
+                putValueArgument(0, numericExpr)
+                putValueArgument(1, zero)
+            }
+        )
+    }
+
+fun byteToBool(byteExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) =
+    numericToBool(byteExpr, irBuilder, symbols, irBuilder.irByte(0))
+
+fun longToBool(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) =
+    numericToBool(longExpr, irBuilder, symbols, irBuilder.irLong(0))
+
+fun longToByte(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.longToByte).apply {
+        dispatchReceiver = longExpr
+    }
+}
+
+fun longToShort(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.longToShort).apply {
+        dispatchReceiver = longExpr
+    }
+}
+
+fun longToInt(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.longToInt).apply {
+        dispatchReceiver = longExpr
+    }
+}
+
+fun longToChar(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.intToChar).apply {
+        dispatchReceiver = longToInt(longExpr, irBuilder, symbols)
+    }
+}
+
+fun longToFloat(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) =
+    intToFloat(longToInt(longExpr, irBuilder, symbols), irBuilder, symbols)
+
+fun charToShort(charExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.intToShort).apply {
+        dispatchReceiver = irCall(symbols.backendContext.ir.symbols.charCodeGetter).apply {
+            extensionReceiver = charExpr
+        }
+    }
+}
+
+fun shortToChar(shortExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.intToChar).apply {
+        dispatchReceiver = irCall(symbols.shortToInt).apply {
+            dispatchReceiver = shortExpr
+        }
+    }
+}
+
+
+private fun floatToInt(floatExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.backendContext.ir.symbols.floatToRawBits).apply {
+        extensionReceiver = floatExpr
+    }
+}
+
+private fun intToFloat(intExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.backendContext.ir.symbols.floatFromBits).apply {
+        extensionReceiver = irGetObject(symbols.floatCompanion)
+        putValueArgument(0, intExpr)
+    }
+}
+
+private fun longToDouble(longExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.backendContext.ir.symbols.doubleFromBits).apply {
+        extensionReceiver = irGetObject(symbols.doubleCompanion)
+        putValueArgument(0, longExpr)
+    }
+}
+
+private fun doubleToLong(doubleExpr: IrExpression, irBuilder: IrBuilderWithScope, symbols: FlatteningSymbolsHelper) = with(irBuilder) {
+    irCall(symbols.backendContext.ir.symbols.doubleToRawBits).apply {
+        extensionReceiver = doubleExpr
+    }
+}
+
+class PerSizeMapper(mvfcNode: RootMfvcNode, symbols: FlatteningSymbolsHelper) : MfvcVArrayMapper(mvfcNode) {
+
+    private val onesField = symbols.backendContext.ir.symbols.vArrayWrapperPerSizeClass.fieldByName(Names.ONES)
+    private val twosField = symbols.backendContext.ir.symbols.vArrayWrapperPerSizeClass.fieldByName(Names.TWOS)
+    private val fourField = symbols.backendContext.ir.symbols.vArrayWrapperPerSizeClass.fieldByName(Names.FOURS)
+    private val eightsField = symbols.backendContext.ir.symbols.vArrayWrapperPerSizeClass.fieldByName(Names.EIGHTS)
+    private val refsField = symbols.backendContext.ir.symbols.vArrayWrapperPerSizeClass.fieldByName(Names.REFS)
+
+    override val indexOfLeafInGroup: IntArray
+    override val wrapperField: Map<LeafType, IrFieldSymbol>
+    override val groupSizeForType: Map<LeafType, Int>
+    override val groupSizes: List<Int>
+    override val arrayConstructors: List<IrFunctionSymbol>
+    override val arrayGetFunctions: Map<LeafType, IrFunctionSymbol>
+    override val arraySetFunctions: Map<LeafType, IrFunctionSymbol>
+    override val encodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+    override val decodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+
+    init {
+        var onesCount = 0;
+        var twosCount = 0;
+        var foursCount = 0;
+        var eightsCount = 0;
+        var refsCount = 0;
+        indexOfLeafInGroup = IntArray(mfvcNode.leavesCount)
+        mfvcNode.leaves.forEachIndexed { leafIndex, leaf ->
+            indexOfLeafInGroup[leafIndex] = when {
+                leaf.type.isBoolean() -> onesCount++
+                leaf.type.isByte() -> onesCount++
+                leaf.type.isChar() -> twosCount++
+                leaf.type.isShort() -> twosCount++
+                leaf.type.isInt() -> foursCount++
+                leaf.type.isFloat() -> foursCount++
+                leaf.type.isLong() -> eightsCount++
+                leaf.type.isDouble() -> eightsCount++
+                else -> refsCount++
+            }
+        }
+
+        groupSizes = listOf(onesCount, twosCount, foursCount, eightsCount, refsCount)
+
+        with(symbols) {
+            arrayConstructors = listOf(
+                byteArrayConstructor,
+                shortArrayConstructor,
+                intArrayConstructor,
+                longArrayConstructor,
+                backendContext.irBuiltIns.arrayOfNulls
+            )
+        }
+
+        wrapperField = mapOf(
+            LeafType.BOOL to onesField,
+            LeafType.BYTE to onesField,
+            LeafType.SHORT to twosField,
+            LeafType.CHAR to twosField,
+            LeafType.INT to fourField,
+            LeafType.FLOAT to fourField,
+            LeafType.LONG to eightsField,
+            LeafType.DOUBLE to eightsField,
+            LeafType.REF to refsField
+        )
+
+        groupSizeForType = mapOf(
+            LeafType.BOOL to onesCount,
+            LeafType.BYTE to onesCount,
+            LeafType.CHAR to twosCount,
+            LeafType.SHORT to twosCount,
+            LeafType.INT to foursCount,
+            LeafType.FLOAT to foursCount,
+            LeafType.LONG to eightsCount,
+            LeafType.DOUBLE to eightsCount,
+            LeafType.REF to refsCount
+        )
+
+        with(symbols) {
+            arraySetFunctions = mapOf(
+                LeafType.BOOL to bytesSetFunction,
+                LeafType.BYTE to bytesSetFunction,
+                LeafType.CHAR to shortsSetFunction,
+                LeafType.SHORT to shortsSetFunction,
+                LeafType.INT to intsSetFunction,
+                LeafType.FLOAT to intsSetFunction,
+                LeafType.LONG to longsSetFunction,
+                LeafType.DOUBLE to longsSetFunction,
+                LeafType.REF to refsSetFunction
+            )
+        }
+
+        with(symbols) {
+            arrayGetFunctions = mapOf(
+                LeafType.BOOL to bytesGetFunction,
+                LeafType.BYTE to bytesGetFunction,
+                LeafType.CHAR to shortsGetFunction,
+                LeafType.SHORT to shortsGetFunction,
+                LeafType.INT to intsGetFunction,
+                LeafType.FLOAT to intsGetFunction,
+                LeafType.LONG to longsGetFunction,
+                LeafType.DOUBLE to longsGetFunction,
+                LeafType.REF to refsGetFunction
+            )
+        }
+
+        encodingFunctions = mapOf(
+            LeafType.BOOL to { boolExpr, irBuilder -> boolToByte(boolExpr, irBuilder, symbols) },
+            LeafType.BYTE to { byteExpr, _ -> byteExpr },
+            LeafType.SHORT to { shortExpr, _ -> shortExpr },
+            LeafType.CHAR to { charExpr, irBuilder -> charToShort(charExpr, irBuilder, symbols) },
+            LeafType.INT to { intExpr, _ -> intExpr },
+            LeafType.FLOAT to { floatExpr, irBuilder -> floatToInt(floatExpr, irBuilder, symbols) },
+            LeafType.LONG to { longExpr, _ -> longExpr },
+            LeafType.DOUBLE to { doubleExpr, irBuilder -> doubleToLong(doubleExpr, irBuilder, symbols) },
+            LeafType.REF to { refExpr, _ -> refExpr }
+        )
+
+        decodingFunctions = mapOf(
+            LeafType.BOOL to { byteExpr, irBuilder -> byteToBool(byteExpr, irBuilder, symbols) },
+            LeafType.BYTE to { byteExpr, _ -> byteExpr },
+            LeafType.SHORT to { shortExpr, _ -> shortExpr },
+            LeafType.CHAR to { shortExpr, irBuilder -> shortToChar(shortExpr, irBuilder, symbols) },
+            LeafType.INT to { intExpr, _ -> intExpr },
+            LeafType.FLOAT to { intExpr, irBuilder -> intToFloat(intExpr, irBuilder, symbols) },
+            LeafType.LONG to { longExpr, _ -> longExpr },
+            LeafType.DOUBLE to { longExpr, irBuilder -> longToDouble(longExpr, irBuilder, symbols) },
+            LeafType.REF to { refExpr, _ -> refExpr }
+        )
+    }
+}
+
+class TwoArraysMapper(mvfcNode: RootMfvcNode, symbols: FlatteningSymbolsHelper) : MfvcVArrayMapper(mvfcNode) {
+
+    private val longsField = symbols.backendContext.ir.symbols.vArrayWrapperTwoArrays.fieldByName(Names.LONGS)
+    private val refsField = symbols.backendContext.ir.symbols.vArrayWrapperTwoArrays.fieldByName(Names.REFS)
+
+    override val indexOfLeafInGroup: IntArray
+    override val wrapperField: Map<LeafType, IrFieldSymbol>
+    override val groupSizeForType: Map<LeafType, Int>
+    override val groupSizes: List<Int>
+    override val arrayConstructors: List<IrFunctionSymbol>
+    override val arrayGetFunctions: Map<LeafType, IrFunctionSymbol>
+    override val arraySetFunctions: Map<LeafType, IrFunctionSymbol>
+    override val encodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+    override val decodingFunctions: Map<LeafType, (IrExpression, IrBuilderWithScope) -> IrExpression>
+
+    init {
+        var longsCount = 0;
+        var refsCount = 0;
+        indexOfLeafInGroup = IntArray(mfvcNode.leavesCount)
+        mfvcNode.leaves.forEachIndexed { leafIndex, leaf ->
+            indexOfLeafInGroup[leafIndex] = if (leaf.type.isPrimitiveType()) longsCount++ else refsCount++
+        }
+
+        groupSizes = listOf(longsCount, refsCount)
+
+        with(symbols) {
+            arrayConstructors = listOf(longArrayConstructor, backendContext.irBuiltIns.arrayOfNulls)
+        }
+
+        wrapperField = LeafType.values().associateWith { if (it == LeafType.REF) refsField else longsField }
+
+        groupSizeForType = LeafType.values().associateWith { if (it == LeafType.REF) refsCount else longsCount }
+
+        arraySetFunctions =
+            LeafType.values().associateWith { if (it == LeafType.REF) symbols.refsSetFunction else symbols.longsSetFunction }
+
+        arrayGetFunctions =
+            LeafType.values().associateWith { if (it == LeafType.REF) symbols.refsGetFunction else symbols.longsGetFunction }
+
+
+        encodingFunctions = mapOf(
+            LeafType.BOOL to { boolExpr, irBuilder -> boolToLong(boolExpr, irBuilder, symbols) },
+            LeafType.BYTE to { byteExpr, irBuilder -> byteToLong(byteExpr, irBuilder, symbols) },
+            LeafType.SHORT to { shortExpr, irBuilder -> shortToLong(shortExpr, irBuilder, symbols) },
+            LeafType.CHAR to { charExpr, irBuilder -> charToLong(charExpr, irBuilder, symbols) },
+            LeafType.INT to { intExpr, irBuilder -> intToLong(intExpr, irBuilder, symbols) },
+            LeafType.FLOAT to { floatExpr, irBuilder -> floatToLong(floatExpr, irBuilder, symbols) },
+            LeafType.LONG to { longExpr, _ -> longExpr },
+            LeafType.DOUBLE to { doubleExpr, irBuilder -> doubleToLong(doubleExpr, irBuilder, symbols) },
+            LeafType.REF to { refExpr, _ -> refExpr }
+        )
+
+        decodingFunctions = mapOf(
+            LeafType.BOOL to { longExpr, irBuilder -> longToBool(longExpr, irBuilder, symbols) },
+            LeafType.BYTE to { longExpr, irBuilder -> longToByte(longExpr, irBuilder, symbols) },
+            LeafType.SHORT to { longExpr, irBuilder -> longToShort(longExpr, irBuilder, symbols) },
+            LeafType.CHAR to { longExpr, irBuilder -> longToChar(longExpr, irBuilder, symbols) },
+            LeafType.INT to { longExpr, irBuilder -> longToInt(longExpr, irBuilder, symbols) },
+            LeafType.FLOAT to { longExpr, irBuilder -> longToFloat(longExpr, irBuilder, symbols) },
+            LeafType.LONG to { longExpr, _ -> longExpr },
+            LeafType.DOUBLE to { longExpr, irBuilder -> longToDouble(longExpr, irBuilder, symbols) },
+            LeafType.REF to { refExpr, _ -> refExpr }
+        )
+    }
+}
\ No newline at end of file
diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt
index f04553a..bf2b6af 100644
--- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt
+++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/descriptors/IrBuiltInsOverDescriptors.kt
@@ -478,6 +478,8 @@
                 it.descriptor.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.descriptor.valueParameters[0].type)
     }
 
+    override val vArrayIteratorFunction: IrSimpleFunctionSymbol? = null // not implemented in old frontend
+
     override val linkageErrorSymbol: IrSimpleFunctionSymbol = defineOperator("linkageError", nothingType, listOf(stringType))
 
     override val enumClass = builtIns.enum.toIrSymbol()
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
index e75439d..dd4c447 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrBuiltIns.kt
@@ -152,6 +152,7 @@
     abstract val arrayOfNulls: IrSimpleFunctionSymbol
 
     abstract val vArrayOfNulls: IrSimpleFunctionSymbol?
+    abstract val vArrayIteratorFunction: IrSimpleFunctionSymbol?
 
     abstract val linkageErrorSymbol: IrSimpleFunctionSymbol
 
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
index 39febc3..5e32c79 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/builders/ExpressionHelpers.kt
@@ -340,6 +340,9 @@
 fun IrBuilderWithScope.irSamConversion(argument: IrExpression, type: IrType) =
     typeOperator(type, argument, IrTypeOperator.SAM_CONVERSION, type)
 
+fun IrBuilderWithScope.irByte(value: Byte, type: IrType = context.irBuiltIns.byteType) =
+    IrConstImpl.byte(startOffset, endOffset, type, value)
+
 fun IrBuilderWithScope.irInt(value: Int, type: IrType = context.irBuiltIns.intType) =
     IrConstImpl.int(startOffset, endOffset, type, value)
 
diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt
index f2bb85f..4d5d039 100644
--- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt
+++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypePredicates.kt
@@ -39,6 +39,7 @@
     @JvmField val string = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "String")
     @JvmField val array = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Array")
     @JvmField val vArray = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "VArray")
+    @JvmField val vArrayIterator = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "VArrayIterator")
     @JvmField val collection = getPublicSignature(StandardNames.COLLECTIONS_PACKAGE_FQ_NAME, "Collection")
     @JvmField val kClass = getPublicSignature(StandardNames.KOTLIN_REFLECT_FQ_NAME, "KClass")
     @JvmField val comparable = getPublicSignature(StandardNames.BUILT_INS_PACKAGE_FQ_NAME, "Comparable")
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt b/compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt
new file mode 100644
index 0000000..d53973c
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt
@@ -0,0 +1,35 @@
+import java.lang.StringBuilder
+
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+class PointIterator(val array: VArray<Point>) : VArrayIterator<Point> {
+    private var index: Int = 0
+
+    override fun hasNext() = index < array.size
+
+    override fun next() = array[index++]
+}
+
+fun box(): String {
+
+    val arr = VArray(2) { Point(it, it + 1) }
+
+    val it = PointIterator(arr)
+
+    val builder = StringBuilder()
+
+    while (it.hasNext()) {
+        builder.append(it.next())
+    }
+
+    if (builder.toString() != "Point(x=0, y=1)Point(x=1, y=2)") return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt b/compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt
new file mode 100644
index 0000000..00bbd9a
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt
@@ -0,0 +1,54 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(
+    val bool: Boolean,
+    val byte: Byte,
+    val short: Short,
+    val char: Char,
+    val int: Int,
+    val float: Float,
+    val long: Long,
+    val double: Double,
+    val string: String
+)
+
+@JvmInline
+value class X(val z: String, val x: VArray<Point>)
+
+fun box(): String {
+
+    val vArray = VArray(9) {
+        Point(
+            it > 0,
+            it.toByte(),
+            it.toShort(),
+            '0' + it,
+            it,
+            it.toFloat(),
+            it.toLong(),
+            it.toDouble(),
+            it.toString()
+        )
+    }
+
+    val bool = vArray[0].bool
+    val byte = vArray[1].byte
+    val short = vArray[2].short
+    val char = vArray[3].char
+    val int = vArray[4].int
+    val float = vArray[5].float
+    val long = vArray[6].long
+    val double = vArray[7].double
+    val string = vArray[8].string
+
+    val str = "$bool $byte $short $char $int $float $long $double $string"
+
+    if (str != "false 1 2 3 4 5.0 6 7.0 8") return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt
new file mode 100644
index 0000000..09a863d
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt
@@ -0,0 +1,17 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun box(): String {
+
+    val vArray2D = VArray(2) { i -> VArray(2) { j -> Point(i + j, i + j + 1) } }
+
+    if (vArray2D[1][1].y != 3) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt
new file mode 100644
index 0000000..795c2c9
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt
@@ -0,0 +1,17 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(arr: VArray<Point>) = arr[1].y
+
+fun box(): String {
+
+    if (foo(VArray(2) { Point(it, it + 1) }) != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt
new file mode 100644
index 0000000..268a984
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt
@@ -0,0 +1,17 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(arr: VArray<Point>, func: (VArray<Point>) -> Int) = func(arr)
+
+fun box(): String {
+
+    if (foo(VArray(2) { Point(it, it + 1) }) { it[1].y } != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt
new file mode 100644
index 0000000..e9c7745
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt
@@ -0,0 +1,17 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(x: Int, func: (Int) -> VArray<Point>) = func(x)[1].y
+
+fun box(): String {
+
+    if (foo(1, { x -> VArray(2) { i -> Point(i + x, i + x + 1) } }) != 3) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt
new file mode 100644
index 0000000..9c3981e
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt
@@ -0,0 +1,20 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+@JvmInline
+value class Poly(val s: Point, val points: VArray<Point>)
+
+fun box(): String {
+
+    val poly = Poly(s = Point(1, 2), points = VArray(3) { Point(it, it + 1) })
+
+    if (poly.points[2].y != 3) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt
new file mode 100644
index 0000000..82e9bd1
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt
@@ -0,0 +1,18 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+class A(val arr: VArray<Point>)
+
+fun box(): String {
+
+    val a = A(VArray(2) { Point(it, it + 1) })
+
+    if (a.arr[1].y != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt
new file mode 100644
index 0000000..8618f67
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt
@@ -0,0 +1,21 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+class A() {
+    val arr: VArray<Point> get() = VArray(2) { Point(it, it + 1) }
+}
+
+fun box(): String {
+
+    val a = A()
+
+    if (a.arr[1].y != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt
new file mode 100644
index 0000000..ddf09d4
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt
@@ -0,0 +1,18 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo() = VArray(2) { Point(it, it + 1) }
+
+
+fun box(): String {
+
+    if (foo()[1].y != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt
new file mode 100644
index 0000000..9db316d
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt
@@ -0,0 +1,25 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+@JvmInline
+value class Poly(val points: VArray<Point>)
+
+@JvmInline
+value class PolyWrapper(val poly: Poly)
+
+fun box(): String {
+
+    val poly = Poly(VArray(3) { Point(it, it + 1) })
+
+    if (poly.points[2].y != 3) return "Fail 1"
+
+    val polyWrapper = PolyWrapper(poly)
+    if (polyWrapper.poly.points[2].y != 3) return "Fail 2"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt
new file mode 100644
index 0000000..69409f7
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt
@@ -0,0 +1,20 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+
+fun box(): String {
+
+    val a = VArray(2) { Point(it, it + 1) }
+    val b = a
+    val c = b
+
+    if (c[1].y != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt
new file mode 100644
index 0000000..f42a663
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt
@@ -0,0 +1,19 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun box(): String {
+
+    VArray(2) { Point(it, it + 1) }[0] = Point(10, 20)
+
+    val a = VArray(2) { Point(it, it + 1) }[1].y
+
+    if (a != 2) return "Fail"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt
new file mode 100644
index 0000000..f8f7d7f
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt
@@ -0,0 +1,27 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(b: Boolean, x: Int): Int {
+    val vArray = if (b) {
+        val y = x + 1;
+        VArray(2) { Point(it + y, it + y + 1) }
+    } else {
+        val z = x * 2;
+        VArray(2) { Point(it + z, it + z + 1) }
+    }
+    return vArray[1].y
+}
+
+fun box(): String {
+
+    if (foo(false, 2) != 6) return "Fail 1"
+    if (foo(true, 1) != 4) return "Fail 2"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt
new file mode 100644
index 0000000..4be8a76
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt
@@ -0,0 +1,23 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(x: Int) = try {
+    1 / x
+    VArray(2) { Point(it + x, it + x + 1) }
+} catch (t: Throwable) {
+    VArray(2) { Point(it + x + 2, it + x + 3) }
+}
+
+fun box(): String {
+
+    if (foo(0)[1].y != 4) return "Fail 1"
+    if (foo(1)[1].y != 3) return "Fail 2"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt
new file mode 100644
index 0000000..5fb60eb
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt
@@ -0,0 +1,35 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun foo(c: Int, x: Int): Int {
+    val vArray = when (c) {
+        0 -> {
+            val a = x + 1
+            VArray(2) { Point(it + a, it + a + 1) }
+        }
+        1 -> {
+            val b = x + 2
+            VArray(2) { Point(it + b, it + b + 1) }
+        }
+        else -> {
+            val c = x + 3
+            VArray(2) { Point(it + c, it + c + 1) }
+        }
+    }
+    return vArray[1].y
+}
+
+fun box(): String {
+
+    if (foo(0, 1) != 4) return "Fail 1"
+    if (foo(1, 2) != 6) return "Fail 2"
+    if (foo(2, 3) != 8) return "Fail 3"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt
new file mode 100644
index 0000000..83d59af
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt
@@ -0,0 +1,36 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+inline fun <reified T> throws(block: () -> Unit): Boolean {
+    try {
+        block.invoke()
+    } catch (t: Throwable) {
+        return t is T
+    }
+    return false
+}
+
+fun box(): String {
+
+    val arr = VArray(2) { Point(it, it + 1) }
+    val it = arr.iterator()
+
+    if (!it.hasNext()) return "Fail 1"
+    if (it.next().toString() != "Point(x=0, y=1)") return "Fail 2"
+    if (!it.hasNext()) return "Fail 3"
+    if (it.next().toString() != "Point(x=1, y=2)") return "Fail 4"
+    if (it.hasNext()) return "Fail 5"
+    if (!throws<NoSuchElementException> { it.next() }) return "Fail 6"
+    if (it.hasNext()) return "Fail 6"
+    if (!throws<NoSuchElementException> { it.next() }) return "Fail 7"
+
+    // TODO: fix and check exception messages
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt b/compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt
new file mode 100644
index 0000000..2823ad0
--- /dev/null
+++ b/compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt
@@ -0,0 +1,20 @@
+// WITH_STDLIB
+// TARGET_BACKEND: JVM_IR
+// ENABLE_JVM_IR_INLINER
+// TARGET_FRONTEND: FIR
+// LANGUAGE: +ValueClasses
+
+@JvmInline
+value class Point(val x: Int, val y: Int)
+
+fun box(): String {
+
+    if (VArray(2) { Point(-1, 1) }.size != 2) return "Fail 1"
+
+    val vArray2D = VArray(2) { VArray(3) { Point(-1, 1) } }
+
+    if (vArray2D.size != 2) return "Fail 2"
+    if (vArray2D[1].size != 3) return "Fail 3"
+
+    return "OK"
+}
\ No newline at end of file
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
index 836e627..022cc27 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java
@@ -49534,6 +49534,16 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+            }
+        }
     }
 
     @Nested
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
index 2ecea47..fc779c4 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java
@@ -52198,6 +52198,124 @@
         public void testVarargParameterOfInlineType() throws Exception {
             runTest("compiler/testData/codegen/box/vArrays/varargParameterOfInlineType.kt");
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+            }
+
+            @Test
+            @TestMetadata("customIterator.kt")
+            public void testCustomIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("typesEncodings.kt")
+            public void testTypesEncodings() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt");
+            }
+
+            @Test
+            @TestMetadata("vArray2D.kt")
+            public void testVArray2D() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsFunctionParameter.kt")
+            public void testVArrayAsFunctionParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaParameter.kt")
+            public void testVArrayAsLambdaParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaReturnType.kt")
+            public void testVArrayAsLambdaReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsMfvcProperty.kt")
+            public void testVArrayAsMfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsProperty.kt")
+            public void testVArrayAsProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsPropertyNoBackingField.kt")
+            public void testVArrayAsPropertyNoBackingField() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsReturnType.kt")
+            public void testVArrayAsReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsSfvcProperty.kt")
+            public void testVArrayAsSfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayChainAssignment.kt")
+            public void testVArrayChainAssignment() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayExpression.kt")
+            public void testVArrayExpression() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInIfElseBlock.kt")
+            public void testVArrayInIfElseBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInTryBlock.kt")
+            public void testVArrayInTryBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInWhenExpr.kt")
+            public void testVArrayInWhenExpr() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayIterator.kt")
+            public void testVArrayIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("vArraySize.kt")
+            public void testVArraySize() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt");
+            }
+        }
     }
 
     @Nested
diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java
index 1b85007..88d0800 100644
--- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java
+++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java
@@ -52198,6 +52198,124 @@
         public void testVarargParameterOfInlineType() throws Exception {
             runTest("compiler/testData/codegen/box/vArrays/varargParameterOfInlineType.kt");
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
+            }
+
+            @Test
+            @TestMetadata("customIterator.kt")
+            public void testCustomIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/customIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("typesEncodings.kt")
+            public void testTypesEncodings() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/typesEncodings.kt");
+            }
+
+            @Test
+            @TestMetadata("vArray2D.kt")
+            public void testVArray2D() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArray2D.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsFunctionParameter.kt")
+            public void testVArrayAsFunctionParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsFunctionParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaParameter.kt")
+            public void testVArrayAsLambdaParameter() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaParameter.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsLambdaReturnType.kt")
+            public void testVArrayAsLambdaReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsLambdaReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsMfvcProperty.kt")
+            public void testVArrayAsMfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsMfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsProperty.kt")
+            public void testVArrayAsProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsPropertyNoBackingField.kt")
+            public void testVArrayAsPropertyNoBackingField() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsPropertyNoBackingField.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsReturnType.kt")
+            public void testVArrayAsReturnType() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsReturnType.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayAsSfvcProperty.kt")
+            public void testVArrayAsSfvcProperty() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayAsSfvcProperty.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayChainAssignment.kt")
+            public void testVArrayChainAssignment() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayChainAssignment.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayExpression.kt")
+            public void testVArrayExpression() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayExpression.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInIfElseBlock.kt")
+            public void testVArrayInIfElseBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInIfElseBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInTryBlock.kt")
+            public void testVArrayInTryBlock() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInTryBlock.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayInWhenExpr.kt")
+            public void testVArrayInWhenExpr() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayInWhenExpr.kt");
+            }
+
+            @Test
+            @TestMetadata("vArrayIterator.kt")
+            public void testVArrayIterator() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArrayIterator.kt");
+            }
+
+            @Test
+            @TestMetadata("vArraySize.kt")
+            public void testVArraySize() throws Exception {
+                runTest("compiler/testData/codegen/box/vArrays/mfvc/vArraySize.kt");
+            }
+        }
     }
 
     @Nested
diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
index 830e3fa..197d866 100644
--- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
+++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java
@@ -40321,6 +40321,19 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
         }
+
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class Mfvc extends AbstractLightAnalysisModeTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
+            }
+        }
     }
 
     @TestMetadata("compiler/testData/codegen/box/valueClasses")
diff --git a/core/builtins/native/kotlin/VArray.kt b/core/builtins/native/kotlin/VArray.kt
index ef67a65..30d6af6 100644
--- a/core/builtins/native/kotlin/VArray.kt
+++ b/core/builtins/native/kotlin/VArray.kt
@@ -5,6 +5,7 @@
 
 package kotlin
 
+// TODO: add 'reified' to T
 class VArray<T> {
     public operator fun get(index: Int): T
     public operator fun set(index: Int, value: T): Unit
diff --git a/core/builtins/src/kotlin/VArrayIterator.kt b/core/builtins/src/kotlin/VArrayIterator.kt
index d695344..6d2486e 100644
--- a/core/builtins/src/kotlin/VArrayIterator.kt
+++ b/core/builtins/src/kotlin/VArrayIterator.kt
@@ -7,4 +7,5 @@
 
 interface VArrayIterator<T> : Iterator<T> {
     override fun next(): T
+    override fun hasNext(): Boolean
 }
\ No newline at end of file
diff --git a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt
index 6ea3445..cbec8eb 100644
--- a/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt
+++ b/core/compiler.common/src/org/jetbrains/kotlin/name/StandardClassIds.kt
@@ -37,6 +37,7 @@
     val Annotation = "Annotation".baseId()
     val Array = "Array".baseId()
     val VArray = "VArray".baseId()
+    val vArrayIterator = "VArrayIterator".baseId()
 
     val Boolean = "Boolean".baseId()
     val Char = "Char".baseId()
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
index a2b6193d..96a5753 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/JsCodegenBoxTestGenerated.java
@@ -36906,6 +36906,16 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
+            }
+        }
     }
 
     @Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
index 1746282..9d02b8e 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsCodegenBoxTestGenerated.java
@@ -37248,6 +37248,16 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+            }
+        }
     }
 
     @Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
index 8d4db39..03cf91f70 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsCodegenBoxTestGenerated.java
@@ -37248,6 +37248,16 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
+            }
+        }
     }
 
     @Nested
diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
index 78975f5..02c0bba 100644
--- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
+++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.java
@@ -37248,6 +37248,16 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
         }
+
+        @Nested
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        public class Mfvc {
+            @Test
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
+            }
+        }
     }
 
     @Nested
diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ArrayIterator.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ArrayIterator.kt
index 1cf47a7..4972e41 100644
--- a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ArrayIterator.kt
+++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/ArrayIterator.kt
@@ -11,6 +11,7 @@
     override fun next() = try { array[index++] } catch (e: ArrayIndexOutOfBoundsException) { index -= 1; throw NoSuchElementException(e.message) }
 }
 
+// TODO: add 'reified' to T
 public class VArrayIteratorImpl<T>(val array: VArray<T>) : VArrayIterator<T> {
     private var index = 0
     override fun hasNext() = index < array.size
diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayIteratorStateHolders.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayIteratorStateHolders.kt
new file mode 100644
index 0000000..93034e0
--- /dev/null
+++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayIteratorStateHolders.kt
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package kotlin.jvm.internal
+
+class VArrayPerSizeIteratorStateHolder(@JvmField val array: VArrayWrapperPerSize, @JvmField var index: Int)
+
+class VArrayTwoArraysIteratorStateHolder(@JvmField val array: VArrayWrapperTwoArrays, @JvmField var index: Int)
\ No newline at end of file
diff --git a/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayWrappers.kt b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayWrappers.kt
new file mode 100644
index 0000000..a08c07a
--- /dev/null
+++ b/libraries/stdlib/jvm/runtime/kotlin/jvm/internal/VArrayWrappers.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package kotlin.jvm.internal
+
+import kotlin.jvm.JvmField
+
+class VArrayWrapperPerSize(
+    @JvmField val ones: ByteArray?,
+    @JvmField val twos: ShortArray?,
+    @JvmField val fours: IntArray?,
+    @JvmField val eights: LongArray?,
+    @JvmField val refs: Array<Any?>?,
+    @JvmField val size: Int
+)
+
+class VArrayWrapperTwoArrays(
+    @JvmField val longs: LongArray?,
+    @JvmField val refs: Array<Any?>?,
+    @JvmField val size: Int
+)
\ No newline at end of file
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java
index fb79699..386a8db 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestGenerated.java
@@ -41446,6 +41446,20 @@
             public void testAllFilesPresentInVArrays() throws Exception {
                 KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
             }
+
+            @Nested
+            @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+            @TestDataPath("$PROJECT_ROOT")
+            @Tag("codegenK2")
+            @Tag("firCodegen")
+            @UseExtTestCaseGroupProvider()
+            @FirPipeline()
+            public class Mfvc {
+                @Test
+                public void testAllFilesPresentInMfvc() throws Exception {
+                    KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+                }
+            }
         }
 
         @Nested
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java
index b48d779..6b8551f 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/FirNativeCodegenBoxTestNoPLGenerated.java
@@ -42472,6 +42472,22 @@
             public void testAllFilesPresentInVArrays() throws Exception {
                 KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
             }
+
+            @Nested
+            @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+            @TestDataPath("$PROJECT_ROOT")
+            @Tag("codegenK2")
+            @Tag("firCodegen")
+            @UseExtTestCaseGroupProvider()
+            @FirPipeline()
+            @UsePartialLinkage(mode = Mode.DISABLED)
+            @Tag("no-partial-linkage-may-be-skipped")
+            public class Mfvc {
+                @Test
+                public void testAllFilesPresentInMfvc() throws Exception {
+                    KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+                }
+            }
         }
 
         @Nested
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
index feb7967..56f1f91 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestGenerated.java
@@ -40933,6 +40933,19 @@
             public void testAllFilesPresentInVArrays() throws Exception {
                 KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
             }
+
+            @Nested
+            @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+            @TestDataPath("$PROJECT_ROOT")
+            @Tag("codegen")
+            @Tag("k1Codegen")
+            @UseExtTestCaseGroupProvider()
+            public class Mfvc {
+                @Test
+                public void testAllFilesPresentInMfvc() throws Exception {
+                    KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+                }
+            }
         }
 
         @Nested
diff --git a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java
index 4c1b9dc..8f00d69 100644
--- a/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java
+++ b/native/native.tests/tests-gen/org/jetbrains/kotlin/konan/blackboxtest/NativeCodegenBoxTestNoPLGenerated.java
@@ -41959,6 +41959,21 @@
             public void testAllFilesPresentInVArrays() throws Exception {
                 KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
             }
+
+            @Nested
+            @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+            @TestDataPath("$PROJECT_ROOT")
+            @Tag("codegen")
+            @Tag("k1Codegen")
+            @UseExtTestCaseGroupProvider()
+            @UsePartialLinkage(mode = Mode.DISABLED)
+            @Tag("no-partial-linkage-may-be-skipped")
+            public class Mfvc {
+                @Test
+                public void testAllFilesPresentInMfvc() throws Exception {
+                    KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
+                }
+            }
         }
 
         @Nested
diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
index a59da49..817f6c1 100644
--- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
+++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/IrCodegenBoxWasmTestGenerated.java
@@ -33271,6 +33271,19 @@
         public void testAllFilesPresentInVArrays() throws Exception {
             KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
         }
+
+        @TestMetadata("compiler/testData/codegen/box/vArrays/mfvc")
+        @TestDataPath("$PROJECT_ROOT")
+        @RunWith(JUnit3RunnerWithInners.class)
+        public static class Mfvc extends AbstractIrCodegenBoxWasmTest {
+            private void runTest(String testDataFilePath) throws Exception {
+                KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
+            }
+
+            public void testAllFilesPresentInMfvc() throws Exception {
+                KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/vArrays/mfvc"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
+            }
+        }
     }
 
     @TestMetadata("compiler/testData/codegen/box/valueClasses")