[WASM] Caching string literals in global pool
This commit is contained in:
+3
-1
@@ -63,7 +63,9 @@ class WasmBackendContext(
|
|||||||
|
|
||||||
override val internalPackageFqn = FqName("kotlin.wasm")
|
override val internalPackageFqn = FqName("kotlin.wasm")
|
||||||
|
|
||||||
private val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.wasm.internal"))
|
val kotlinWasmInternalPackageFqn = internalPackageFqn.child(Name.identifier("internal"))
|
||||||
|
|
||||||
|
private val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, kotlinWasmInternalPackageFqn)
|
||||||
// TODO: Merge with JS IR Backend context lazy file
|
// TODO: Merge with JS IR Backend context lazy file
|
||||||
val internalPackageFragment by lazy {
|
val internalPackageFragment by lazy {
|
||||||
IrFileImpl(object : IrFileEntry {
|
IrFileImpl(object : IrFileEntry {
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ class WasmSymbols(
|
|||||||
val unboxIntrinsic: IrSimpleFunctionSymbol = getInternalFunction("unboxIntrinsic")
|
val unboxIntrinsic: IrSimpleFunctionSymbol = getInternalFunction("unboxIntrinsic")
|
||||||
|
|
||||||
val stringGetLiteral = getFunction("stringLiteral", builtInsPackage)
|
val stringGetLiteral = getFunction("stringLiteral", builtInsPackage)
|
||||||
|
val stringGetPoolSize = getInternalFunction("stringGetPoolSize")
|
||||||
|
|
||||||
val testFun = maybeGetFunction("test", kotlinTestPackage)
|
val testFun = maybeGetFunction("test", kotlinTestPackage)
|
||||||
val suiteFun = maybeGetFunction("suite", kotlinTestPackage)
|
val suiteFun = maybeGetFunction("suite", kotlinTestPackage)
|
||||||
|
|||||||
+38
-26
@@ -44,6 +44,10 @@ class BodyGenerator(
|
|||||||
buildInstr(WasmOp.GET_UNIT, WasmImmediate.FuncIdx(context.referenceFunction(unitGetInstance.symbol)))
|
buildInstr(WasmOp.GET_UNIT, WasmImmediate.FuncIdx(context.referenceFunction(unitGetInstance.symbol)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val anyConstructor by lazy {
|
||||||
|
wasmSymbols.any.constructors.first { it.owner.valueParameters.isEmpty() }
|
||||||
|
}
|
||||||
|
|
||||||
// Generates code for the given IR element. Leaves something on the stack unless expression was of the type Void.
|
// Generates code for the given IR element. Leaves something on the stack unless expression was of the type Void.
|
||||||
internal fun generateExpression(elem: IrElement) {
|
internal fun generateExpression(elem: IrElement) {
|
||||||
assert(elem is IrExpression || elem is IrVariable) { "Unsupported statement kind" }
|
assert(elem is IrExpression || elem is IrVariable) { "Unsupported statement kind" }
|
||||||
@@ -187,12 +191,13 @@ class BodyGenerator(
|
|||||||
|
|
||||||
override fun visitConstructorCall(expression: IrConstructorCall) {
|
override fun visitConstructorCall(expression: IrConstructorCall) {
|
||||||
val klass: IrClass = expression.symbol.owner.parentAsClass
|
val klass: IrClass = expression.symbol.owner.parentAsClass
|
||||||
|
val klassSymbol: IrClassSymbol = klass.symbol
|
||||||
|
|
||||||
require(!backendContext.inlineClassesUtils.isClassInlineLike(klass)) {
|
require(!backendContext.inlineClassesUtils.isClassInlineLike(klass)) {
|
||||||
"All inline class constructor calls must be lowered to static function calls"
|
"All inline class constructor calls must be lowered to static function calls"
|
||||||
}
|
}
|
||||||
|
|
||||||
val wasmGcType: WasmSymbol<WasmTypeDeclaration> = context.referenceGcType(klass.symbol)
|
val wasmGcType: WasmSymbol<WasmTypeDeclaration> = context.referenceGcType(klassSymbol)
|
||||||
|
|
||||||
if (klass.getWasmArrayAnnotation() != null) {
|
if (klass.getWasmArrayAnnotation() != null) {
|
||||||
require(expression.valueArgumentsCount == 1) { "@WasmArrayOf constructs must have exactly one argument" }
|
require(expression.valueArgumentsCount == 1) { "@WasmArrayOf constructs must have exactly one argument" }
|
||||||
@@ -204,29 +209,40 @@ class BodyGenerator(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//ClassITable and VTable load
|
generateAnyParameters(klassSymbol)
|
||||||
body.buildGetGlobal(context.referenceGlobalVTable(klass.symbol))
|
|
||||||
if (klass.hasInterfaceSuperClass()) {
|
if (expression.symbol.owner.hasWasmPrimitiveConstructorAnnotation()) {
|
||||||
body.buildGetGlobal(context.referenceGlobalClassITable(klass.symbol))
|
for (i in 0 until expression.valueArgumentsCount) {
|
||||||
} else {
|
generateExpression(expression.getValueArgument(i)!!)
|
||||||
body.buildRefNull(WasmHeapType.Simple.Data)
|
}
|
||||||
|
body.buildStructNew(wasmGcType)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val wasmClassId = context.referenceClassId(klass.symbol)
|
|
||||||
|
|
||||||
val irFields: List<IrField> = klass.allFields(backendContext.irBuiltIns)
|
val irFields: List<IrField> = klass.allFields(backendContext.irBuiltIns)
|
||||||
|
|
||||||
irFields.forEachIndexed { index, field ->
|
irFields.forEachIndexed { index, field ->
|
||||||
if (index == 0)
|
if (index > 1) {
|
||||||
body.buildConstI32Symbol(wasmClassId)
|
|
||||||
else
|
|
||||||
generateDefaultInitializerForType(context.transformType(field.type), body)
|
generateDefaultInitializerForType(context.transformType(field.type), body)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body.buildStructNew(wasmGcType)
|
body.buildStructNew(wasmGcType)
|
||||||
generateCall(expression)
|
generateCall(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun generateAnyParameters(klassSymbol: IrClassSymbol) {
|
||||||
|
//ClassITable and VTable load
|
||||||
|
body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol))
|
||||||
|
if (klassSymbol.owner.hasInterfaceSuperClass()) {
|
||||||
|
body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol))
|
||||||
|
} else {
|
||||||
|
body.buildRefNull(WasmHeapType.Simple.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
body.buildConstI32Symbol(context.referenceClassId(klassSymbol))
|
||||||
|
body.buildConstI32(0) // Any::_hashCode
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall) {
|
||||||
val klass = context.irFunction.parentAsClass
|
val klass = context.irFunction.parentAsClass
|
||||||
|
|
||||||
@@ -244,19 +260,8 @@ class BodyGenerator(
|
|||||||
// Box intrinsic has an additional klass ID argument.
|
// Box intrinsic has an additional klass ID argument.
|
||||||
// Processing it separately
|
// Processing it separately
|
||||||
if (call.symbol == wasmSymbols.boxIntrinsic) {
|
if (call.symbol == wasmSymbols.boxIntrinsic) {
|
||||||
val klass = call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns)
|
val klassSymbol = call.getTypeArgument(0)!!.getRuntimeClass(irBuiltIns).symbol
|
||||||
val klassSymbol = klass.symbol
|
generateAnyParameters(klassSymbol)
|
||||||
|
|
||||||
//ClassITable and VTable load
|
|
||||||
body.buildGetGlobal(context.referenceGlobalVTable(klassSymbol))
|
|
||||||
if (klass.hasInterfaceSuperClass()) {
|
|
||||||
body.buildGetGlobal(context.referenceGlobalClassITable(klassSymbol))
|
|
||||||
} else {
|
|
||||||
body.buildRefNull(WasmHeapType.Simple.Data)
|
|
||||||
}
|
|
||||||
|
|
||||||
body.buildConstI32Symbol(context.referenceClassId(klassSymbol))
|
|
||||||
body.buildConstI32(0) // Any::_hashCode
|
|
||||||
generateExpression(call.getValueArgument(0)!!)
|
generateExpression(call.getValueArgument(0)!!)
|
||||||
body.buildStructNew(context.referenceGcType(klassSymbol))
|
body.buildStructNew(context.referenceGcType(klassSymbol))
|
||||||
return
|
return
|
||||||
@@ -301,6 +306,9 @@ class BodyGenerator(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We skip now calling any ctor because it is empty
|
||||||
|
if (function.symbol.owner.hasWasmPrimitiveConstructorAnnotation()) return
|
||||||
|
|
||||||
val isSuperCall = call is IrCall && call.superQualifierSymbol != null
|
val isSuperCall = call is IrCall && call.superQualifierSymbol != null
|
||||||
if (function is IrSimpleFunction && function.isOverridable && !isSuperCall) {
|
if (function is IrSimpleFunction && function.isOverridable && !isSuperCall) {
|
||||||
// Generating index for indirect call
|
// Generating index for indirect call
|
||||||
@@ -483,6 +491,10 @@ class BodyGenerator(
|
|||||||
body.buildInstr(WasmOp.ARRAY_COPY, immediate, immediate)
|
body.buildInstr(WasmOp.ARRAY_COPY, immediate, immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasmSymbols.stringGetPoolSize -> {
|
||||||
|
body.buildConstI32Symbol(context.stringPoolSize)
|
||||||
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-6
@@ -372,13 +372,19 @@ class DeclarationGenerator(
|
|||||||
//TODO("FqName for inner classes could be invalid due to topping it out from outer class")
|
//TODO("FqName for inner classes could be invalid due to topping it out from outer class")
|
||||||
val packageName = if (fqnShouldBeEmitted) classMetadata.klass.kotlinFqName.parentOrNull()?.asString() ?: "" else ""
|
val packageName = if (fqnShouldBeEmitted) classMetadata.klass.kotlinFqName.parentOrNull()?.asString() ?: "" else ""
|
||||||
val simpleName = classMetadata.klass.kotlinFqName.shortName().asString()
|
val simpleName = classMetadata.klass.kotlinFqName.shortName().asString()
|
||||||
|
|
||||||
|
val (packageNameAddress, packageNamePoolId) = context.referenceStringLiteralAddressAndId(packageName)
|
||||||
|
val (simpleNameAddress, simpleNamePoolId) = context.referenceStringLiteralAddressAndId(simpleName)
|
||||||
|
|
||||||
val typeInfo = ConstantDataStruct(
|
val typeInfo = ConstantDataStruct(
|
||||||
name = "TypeInfo",
|
name = "TypeInfo",
|
||||||
elements = listOf(
|
elements = listOf(
|
||||||
ConstantDataIntField("TypePackageNameLength", packageName.length),
|
ConstantDataIntField("TypePackageNameLength", packageName.length),
|
||||||
ConstantDataIntField("TypePackageNamePtr", context.referenceStringLiteral(packageName)),
|
ConstantDataIntField("TypePackageNameId", packageNamePoolId),
|
||||||
|
ConstantDataIntField("TypePackageNamePtr", packageNameAddress),
|
||||||
ConstantDataIntField("TypeNameLength", simpleName.length),
|
ConstantDataIntField("TypeNameLength", simpleName.length),
|
||||||
ConstantDataIntField("TypeNamePtr", context.referenceStringLiteral(simpleName))
|
ConstantDataIntField("TypeNameId", simpleNamePoolId),
|
||||||
|
ConstantDataIntField("TypeNamePtr", simpleNameAddress)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -424,8 +430,8 @@ class DeclarationGenerator(
|
|||||||
|
|
||||||
val initValue: IrExpression? = declaration.initializer?.expression
|
val initValue: IrExpression? = declaration.initializer?.expression
|
||||||
if (initValue != null) {
|
if (initValue != null) {
|
||||||
check(initValue is IrConst<*> && initValue.kind !is IrConstKind.String && initValue.kind !is IrConstKind.Null) {
|
check(initValue is IrConst<*> && initValue.kind !is IrConstKind.String) {
|
||||||
"Static field initializer should be non-string const or null"
|
"Static field initializer should be string or const"
|
||||||
}
|
}
|
||||||
generateConstExpression(initValue, wasmExpressionGenerator, context)
|
generateConstExpression(initValue, wasmExpressionGenerator, context)
|
||||||
} else {
|
} else {
|
||||||
@@ -481,8 +487,12 @@ fun generateConstExpression(expression: IrConst<*>, body: WasmExpressionBuilder,
|
|||||||
is IrConstKind.Float -> body.buildConstF32(kind.valueOf(expression))
|
is IrConstKind.Float -> body.buildConstF32(kind.valueOf(expression))
|
||||||
is IrConstKind.Double -> body.buildConstF64(kind.valueOf(expression))
|
is IrConstKind.Double -> body.buildConstF64(kind.valueOf(expression))
|
||||||
is IrConstKind.String -> {
|
is IrConstKind.String -> {
|
||||||
body.buildConstI32Symbol(context.referenceStringLiteral(kind.valueOf(expression)))
|
val stringValue = kind.valueOf(expression)
|
||||||
body.buildConstI32(kind.valueOf(expression).length)
|
val (literalAddress, literalPoolId) = context.referenceStringLiteralAddressAndId(stringValue)
|
||||||
|
body.buildConstI32Symbol(literalPoolId)
|
||||||
|
body.buildConstI32Symbol(literalAddress)
|
||||||
|
body.buildConstI32(stringValue.length)
|
||||||
|
body.buildConstI32(stringValue.hashCode())
|
||||||
body.buildCall(context.referenceFunction(context.backendContext.wasmSymbols.stringGetLiteral))
|
body.buildCall(context.referenceFunction(context.backendContext.wasmSymbols.stringGetLiteral))
|
||||||
}
|
}
|
||||||
else -> error("Unknown constant kind")
|
else -> error("Unknown constant kind")
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,8 @@ interface WasmBaseCodegenContext {
|
|||||||
val scratchMemAddr: WasmSymbol<Int>
|
val scratchMemAddr: WasmSymbol<Int>
|
||||||
val scratchMemSizeInBytes: Int
|
val scratchMemSizeInBytes: Int
|
||||||
|
|
||||||
|
val stringPoolSize: WasmSymbol<Int>
|
||||||
|
|
||||||
fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction>
|
fun referenceFunction(irFunction: IrFunctionSymbol): WasmSymbol<WasmFunction>
|
||||||
fun referenceGlobalField(irField: IrFieldSymbol): WasmSymbol<WasmGlobal>
|
fun referenceGlobalField(irField: IrFieldSymbol): WasmSymbol<WasmGlobal>
|
||||||
fun referenceGlobalVTable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal>
|
fun referenceGlobalVTable(irClass: IrClassSymbol): WasmSymbol<WasmGlobal>
|
||||||
@@ -34,7 +36,7 @@ interface WasmBaseCodegenContext {
|
|||||||
fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int>
|
fun referenceClassId(irClass: IrClassSymbol): WasmSymbol<Int>
|
||||||
fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int>
|
fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int>
|
||||||
|
|
||||||
fun referenceStringLiteral(string: String): WasmSymbol<Int>
|
fun referenceStringLiteralAddressAndId(string: String): Pair<WasmSymbol<Int>, WasmSymbol<Int>>
|
||||||
|
|
||||||
fun transformType(irType: IrType): WasmType
|
fun transformType(irType: IrType): WasmType
|
||||||
fun transformFieldType(irType: IrType): WasmType
|
fun transformFieldType(irType: IrType): WasmType
|
||||||
|
|||||||
+12
-7
@@ -36,7 +36,9 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
|||||||
ReferencableElements<IrClassSymbol, Int>()
|
ReferencableElements<IrClassSymbol, Int>()
|
||||||
val interfaceId =
|
val interfaceId =
|
||||||
ReferencableElements<IrClassSymbol, Int>()
|
ReferencableElements<IrClassSymbol, Int>()
|
||||||
val stringLiteralId =
|
val stringLiteralAddress =
|
||||||
|
ReferencableElements<String, Int>()
|
||||||
|
val stringLiteralPoolId =
|
||||||
ReferencableElements<String, Int>()
|
ReferencableElements<String, Int>()
|
||||||
|
|
||||||
private val tagFuncType = WasmFunctionType(
|
private val tagFuncType = WasmFunctionType(
|
||||||
@@ -62,6 +64,8 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
|||||||
val scratchMemAddr = WasmSymbol<Int>()
|
val scratchMemAddr = WasmSymbol<Int>()
|
||||||
val scratchMemSizeInBytes = 65_536
|
val scratchMemSizeInBytes = 65_536
|
||||||
|
|
||||||
|
val stringPoolSize = WasmSymbol<Int>()
|
||||||
|
|
||||||
open class ReferencableElements<Ir, Wasm : Any> {
|
open class ReferencableElements<Ir, Wasm : Any> {
|
||||||
val unbound = mutableMapOf<Ir, WasmSymbol<Wasm>>()
|
val unbound = mutableMapOf<Ir, WasmSymbol<Wasm>>()
|
||||||
fun reference(ir: Ir): WasmSymbol<Wasm> {
|
fun reference(ir: Ir): WasmSymbol<Wasm> {
|
||||||
@@ -92,7 +96,6 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
|||||||
val wasmToIr = mutableMapOf<Wasm, Ir>()
|
val wasmToIr = mutableMapOf<Wasm, Ir>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalUnsignedTypes::class)
|
|
||||||
fun linkWasmCompiledFragments(): WasmModule {
|
fun linkWasmCompiledFragments(): WasmModule {
|
||||||
bind(functions.unbound, functions.defined)
|
bind(functions.unbound, functions.defined)
|
||||||
bind(globalFields.unbound, globalFields.defined)
|
bind(globalFields.unbound, globalFields.defined)
|
||||||
@@ -123,13 +126,16 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
|||||||
|
|
||||||
val stringDataSectionStart = currentDataSectionAddress
|
val stringDataSectionStart = currentDataSectionAddress
|
||||||
val stringDataSectionBytes = mutableListOf<Byte>()
|
val stringDataSectionBytes = mutableListOf<Byte>()
|
||||||
val stringAddrs = mutableMapOf<String, Int>()
|
var stringLiteralCount = 0
|
||||||
for (str in stringLiteralId.unbound.keys) {
|
for ((string, symbol) in stringLiteralAddress.unbound) {
|
||||||
val constData = ConstantDataCharArray("string_literal", str.toCharArray())
|
val constData = ConstantDataCharArray("string_literal", string.toCharArray())
|
||||||
stringDataSectionBytes += constData.toBytes().toList()
|
stringDataSectionBytes += constData.toBytes().toList()
|
||||||
stringAddrs[str] = currentDataSectionAddress
|
symbol.bind(currentDataSectionAddress)
|
||||||
|
stringLiteralPoolId.reference(string).bind(stringLiteralCount)
|
||||||
currentDataSectionAddress += constData.sizeInBytes
|
currentDataSectionAddress += constData.sizeInBytes
|
||||||
|
stringLiteralCount++
|
||||||
}
|
}
|
||||||
|
stringPoolSize.bind(stringLiteralCount)
|
||||||
|
|
||||||
// Reserve some memory to pass complex exported types (like strings). It's going to be accessible through 'unsafeGetScratchRawMemory'
|
// Reserve some memory to pass complex exported types (like strings). It's going to be accessible through 'unsafeGetScratchRawMemory'
|
||||||
// runtime call from stdlib.
|
// runtime call from stdlib.
|
||||||
@@ -138,7 +144,6 @@ class WasmCompiledModuleFragment(val irBuiltIns: IrBuiltIns) {
|
|||||||
currentDataSectionAddress += scratchMemSizeInBytes
|
currentDataSectionAddress += scratchMemSizeInBytes
|
||||||
|
|
||||||
bind(classIds.unbound, klassIds)
|
bind(classIds.unbound, klassIds)
|
||||||
bind(stringLiteralId.unbound, stringAddrs)
|
|
||||||
interfaceId.unbound.onEachIndexed { index, entry -> entry.value.bind(index) }
|
interfaceId.unbound.onEachIndexed { index, entry -> entry.value.bind(index) }
|
||||||
|
|
||||||
val data = typeInfo.buildData(address = { klassIds.getValue(it) }) +
|
val data = typeInfo.buildData(address = { klassIds.getValue(it) }) +
|
||||||
|
|||||||
+7
-2
@@ -25,6 +25,9 @@ class WasmModuleCodegenContextImpl(
|
|||||||
override val scratchMemAddr: WasmSymbol<Int>
|
override val scratchMemAddr: WasmSymbol<Int>
|
||||||
get() = wasmFragment.scratchMemAddr
|
get() = wasmFragment.scratchMemAddr
|
||||||
|
|
||||||
|
override val stringPoolSize: WasmSymbol<Int>
|
||||||
|
get() = wasmFragment.stringPoolSize
|
||||||
|
|
||||||
override val scratchMemSizeInBytes: Int
|
override val scratchMemSizeInBytes: Int
|
||||||
get() = wasmFragment.scratchMemSizeInBytes
|
get() = wasmFragment.scratchMemSizeInBytes
|
||||||
|
|
||||||
@@ -58,8 +61,10 @@ class WasmModuleCodegenContextImpl(
|
|||||||
return with(typeTransformer) { irType.toWasmBlockResultType() }
|
return with(typeTransformer) { irType.toWasmBlockResultType() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun referenceStringLiteral(string: String): WasmSymbol<Int> {
|
override fun referenceStringLiteralAddressAndId(string: String): Pair<WasmSymbol<Int>, WasmSymbol<Int>> {
|
||||||
return wasmFragment.stringLiteralId.reference(string)
|
val address = wasmFragment.stringLiteralAddress.reference(string)
|
||||||
|
val id = wasmFragment.stringLiteralPoolId.reference(string)
|
||||||
|
return address to id
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement) {
|
override fun generateTypeInfo(irClass: IrClassSymbol, typeInfo: ConstantDataElement) {
|
||||||
|
|||||||
+15
-7
@@ -17,19 +17,20 @@ import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move initialization of global fields to start function.
|
* Move initialization of global fields to start function.
|
||||||
*
|
*
|
||||||
* WebAssembly allows only constant expressions to be used directly in
|
* WebAssembly allows only constant expressions to be used directly in
|
||||||
* field initializers.
|
* field initializers.
|
||||||
*
|
|
||||||
* TODO: Don't move null and nullable constant initializers
|
|
||||||
* TODO: Make field initialization lazy. Needs design.
|
|
||||||
*/
|
*/
|
||||||
class FieldInitializersLowering(val context: WasmBackendContext) : FileLoweringPass {
|
class FieldInitializersLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||||
|
private val stringPoolFqName = context.kotlinWasmInternalPackageFqn.child(Name.identifier("stringPool"))
|
||||||
|
|
||||||
override fun lower(irFile: IrFile) {
|
override fun lower(irFile: IrFile) {
|
||||||
val builder = context.createIrBuilder(context.fieldInitFunction.symbol)
|
val builder = context.createIrBuilder(context.fieldInitFunction.symbol)
|
||||||
val startFunctionBody = context.fieldInitFunction.body as IrBlockBody
|
val startFunctionBody = context.fieldInitFunction.body as IrBlockBody
|
||||||
@@ -48,11 +49,18 @@ class FieldInitializersLowering(val context: WasmBackendContext) : FileLoweringP
|
|||||||
if (!declaration.isStatic) return
|
if (!declaration.isStatic) return
|
||||||
val initValue: IrExpression = declaration.initializer?.expression ?: return
|
val initValue: IrExpression = declaration.initializer?.expression ?: return
|
||||||
// Constant primitive initializers without implicit casting can be processed by native wasm initializers
|
// Constant primitive initializers without implicit casting can be processed by native wasm initializers
|
||||||
if (initValue.type == declaration.type && initValue is IrConst<*> && initValue.kind !is IrConstKind.String && initValue.kind !is IrConstKind.Null) return
|
if (initValue is IrConst<*>) {
|
||||||
|
if (initValue.kind is IrConstKind.Null) return
|
||||||
|
if (initValue.type == declaration.type && initValue.kind !is IrConstKind.String) return
|
||||||
|
}
|
||||||
|
|
||||||
|
val initializerStatement = builder.at(initValue).irSetField(null, declaration, initValue)
|
||||||
|
|
||||||
|
when (declaration.fqNameWhenAvailable) {
|
||||||
|
stringPoolFqName -> startFunctionBody.statements.add(0, initializerStatement)
|
||||||
|
else -> startFunctionBody.statements.add(initializerStatement)
|
||||||
|
}
|
||||||
|
|
||||||
startFunctionBody.statements.add(
|
|
||||||
builder.at(initValue).irSetField(null, declaration, initValue)
|
|
||||||
)
|
|
||||||
// Replace initializer with default one
|
// Replace initializer with default one
|
||||||
declaration.initializer = null
|
declaration.initializer = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ fun IrAnnotationContainer.hasWasmNoOpCastAnnotation(): Boolean =
|
|||||||
fun IrAnnotationContainer.hasWasmAutoboxedAnnotation(): Boolean =
|
fun IrAnnotationContainer.hasWasmAutoboxedAnnotation(): Boolean =
|
||||||
hasAnnotation(FqName("kotlin.wasm.internal.WasmAutoboxed"))
|
hasAnnotation(FqName("kotlin.wasm.internal.WasmAutoboxed"))
|
||||||
|
|
||||||
|
fun IrAnnotationContainer.hasWasmPrimitiveConstructorAnnotation(): Boolean =
|
||||||
|
hasAnnotation(FqName("kotlin.wasm.internal.WasmPrimitiveConstructor"))
|
||||||
|
|
||||||
class WasmArrayInfo(val klass: IrClass, val isNullable: Boolean) {
|
class WasmArrayInfo(val klass: IrClass, val isNullable: Boolean) {
|
||||||
val type = klass.defaultType.let { if (isNullable) it.makeNullable() else it }
|
val type = klass.defaultType.let { if (isNullable) it.makeNullable() else it }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
|
||||||
// WASM_MUTE_REASON: MINOR: CONST_EQUIVALENCE
|
|
||||||
|
|
||||||
object A {
|
object A {
|
||||||
const val a: String = "$"
|
const val a: String = "$"
|
||||||
const val b = "1234$a"
|
const val b = "1234$a"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND: WASM
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import kotlin.random.*
|
|||||||
/**
|
/**
|
||||||
* The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
|
* The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
|
||||||
*/
|
*/
|
||||||
public open class Any {
|
public open class Any @WasmPrimitiveConstructor constructor() {
|
||||||
// Pointer to runtime type info
|
// Pointer to runtime type info
|
||||||
// Initialized by a compiler
|
// Initialized by a compiler
|
||||||
@Suppress("MUST_BE_INITIALIZED_OR_BE_ABSTRACT")
|
@Suppress("MUST_BE_INITIALIZED_OR_BE_ABSTRACT")
|
||||||
|
|||||||
@@ -102,8 +102,11 @@ public class Char private constructor(public val value: Char) : Comparable<Char>
|
|||||||
public inline fun toDouble(): Double =
|
public inline fun toDouble(): Double =
|
||||||
this.toInt().toDouble()
|
this.toInt().toDouble()
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String {
|
||||||
String(WasmCharArray(1).also { it.set(0, this) })
|
val array = WasmCharArray(1)
|
||||||
|
array.set(0, this)
|
||||||
|
return array.createString()
|
||||||
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int =
|
override fun hashCode(): Int =
|
||||||
this.toInt().hashCode()
|
this.toInt().hashCode()
|
||||||
|
|||||||
@@ -12,30 +12,19 @@ import kotlin.math.min
|
|||||||
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
|
* The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
|
||||||
* implemented as instances of this class.
|
* implemented as instances of this class.
|
||||||
*/
|
*/
|
||||||
public class String private constructor(
|
public class String internal @WasmPrimitiveConstructor constructor(
|
||||||
private var leftIfInSum: String?,
|
private var leftIfInSum: String?,
|
||||||
|
public override val length: Int,
|
||||||
private var _chars: WasmCharArray,
|
private var _chars: WasmCharArray,
|
||||||
) : Comparable<String>, CharSequence {
|
) : Comparable<String>, CharSequence {
|
||||||
public companion object {}
|
public companion object {}
|
||||||
|
|
||||||
internal constructor(chars: WasmCharArray) : this(null, chars) { }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
|
* Returns a string obtained by concatenating this string with the string representation of the given [other] object.
|
||||||
*/
|
*/
|
||||||
public operator fun plus(other: Any?): String {
|
public operator fun plus(other: Any?): String {
|
||||||
val right = if (other is String) other else other.toString()
|
val right = other.toString()
|
||||||
return String(this, right.chars)
|
return String(this, this.length + right.length, right.chars)
|
||||||
}
|
|
||||||
|
|
||||||
public override val length: Int get() {
|
|
||||||
var currentLeftString = leftIfInSum
|
|
||||||
var currentLength = _chars.len()
|
|
||||||
while (currentLeftString != null) {
|
|
||||||
currentLength += currentLeftString._chars.len()
|
|
||||||
currentLeftString = currentLeftString.leftIfInSum
|
|
||||||
}
|
|
||||||
return currentLength
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,11 +34,8 @@ public class String private constructor(
|
|||||||
* where the behavior is unspecified.
|
* where the behavior is unspecified.
|
||||||
*/
|
*/
|
||||||
public override fun get(index: Int): Char {
|
public override fun get(index: Int): Char {
|
||||||
if (index < 0) throw IndexOutOfBoundsException()
|
rangeCheck(index, this.length)
|
||||||
val folded = chars
|
return chars.get(index)
|
||||||
val length = folded.len()
|
|
||||||
if (index >= length) throw IndexOutOfBoundsException()
|
|
||||||
return folded.get(index)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun foldChars() {
|
internal fun foldChars() {
|
||||||
@@ -79,59 +65,80 @@ public class String private constructor(
|
|||||||
|
|
||||||
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
||||||
val actualStartIndex = startIndex.coerceAtLeast(0)
|
val actualStartIndex = startIndex.coerceAtLeast(0)
|
||||||
val thisChars = chars
|
val actualEndIndex = endIndex.coerceAtMost(this.length)
|
||||||
val actualEndIndex = endIndex.coerceAtMost(thisChars.len())
|
val newLength = actualEndIndex - actualStartIndex
|
||||||
val newCharsLen = actualEndIndex - actualStartIndex
|
if (newLength <= 0) return ""
|
||||||
val newChars = WasmCharArray(newCharsLen)
|
val newChars = WasmCharArray(newLength)
|
||||||
copyWasmArray(thisChars, newChars, actualStartIndex, 0, newCharsLen)
|
copyWasmArray(chars, newChars, actualStartIndex, 0, newLength)
|
||||||
return String(newChars)
|
return newChars.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun compareTo(other: String): Int {
|
public override fun compareTo(other: String): Int {
|
||||||
|
if (this === other) return 0
|
||||||
val thisChars = this.chars
|
val thisChars = this.chars
|
||||||
val otherChars = other.chars
|
val otherChars = other.chars
|
||||||
|
|
||||||
val thisLength = thisChars.len()
|
val thisLength = thisChars.len()
|
||||||
val otherLength = otherChars.len()
|
val otherLength = otherChars.len()
|
||||||
val len = min(thisLength, otherLength)
|
val minimumLength = if (thisLength < otherLength) thisLength else otherLength
|
||||||
|
|
||||||
for (i in 0 until len) {
|
repeat(minimumLength) {
|
||||||
val l = thisChars.get(i)
|
val l = thisChars.get(it)
|
||||||
val r = otherChars.get(i)
|
val r = otherChars.get(it)
|
||||||
if (l != r)
|
if (l != r) return l - r
|
||||||
return l - r
|
|
||||||
}
|
}
|
||||||
return thisLength - otherLength
|
return thisLength - otherLength
|
||||||
}
|
}
|
||||||
|
|
||||||
public override fun equals(other: Any?): Boolean =
|
public override fun equals(other: Any?): Boolean {
|
||||||
other != null &&
|
if (other == null) return false
|
||||||
other is String &&
|
if (other === this) return true
|
||||||
(this.length == other.length) &&
|
val otherString = other as? String ?: return false
|
||||||
this.compareTo(other) == 0
|
|
||||||
|
val thisLength = this.length
|
||||||
|
val otherLength = otherString.length
|
||||||
|
if (thisLength != otherLength) return false
|
||||||
|
|
||||||
|
val thisHash = this._hashCode
|
||||||
|
val otherHash = other._hashCode
|
||||||
|
if (thisHash != otherHash && thisHash != 0 && otherHash != 0) return false
|
||||||
|
|
||||||
|
val thisChars = this.chars
|
||||||
|
val otherChars = other.chars
|
||||||
|
repeat(thisLength) {
|
||||||
|
if (thisChars.get(it) != otherChars.get(it)) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
public override fun toString(): String = this
|
public override fun toString(): String = this
|
||||||
|
|
||||||
public override fun hashCode(): Int {
|
public override fun hashCode(): Int {
|
||||||
if (_hashCode != 0) return _hashCode
|
if (_hashCode != 0) return _hashCode
|
||||||
val thisChars = chars
|
val thisLength = this.length
|
||||||
val thisLength = thisChars.len()
|
|
||||||
if (thisLength == 0) return 0
|
if (thisLength == 0) return 0
|
||||||
|
|
||||||
|
val thisChars = chars
|
||||||
var hash = 0
|
var hash = 0
|
||||||
var i = 0
|
repeat(thisLength) {
|
||||||
while (i < thisLength) {
|
hash = (hash shl 5) - hash + thisChars.get(it).toInt()
|
||||||
hash = 31 * hash + thisChars.get(i).toInt()
|
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_hashCode = hash
|
_hashCode = hash
|
||||||
return _hashCode
|
return _hashCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun stringLiteral(startAddr: Int, length: Int): String {
|
internal inline fun WasmCharArray.createString(): String =
|
||||||
val array = WasmCharArray(length)
|
String(null, this.len(), this)
|
||||||
unsafeRawMemoryToWasmCharArray(startAddr, 0, length, array)
|
|
||||||
return String(array)
|
internal fun stringLiteral(poolId: Int, startAddress: Int, length: Int, hashCode: Int): String {
|
||||||
|
val cached = stringPool[poolId]
|
||||||
|
if (cached !== null) {
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
val chars = WasmCharArray(length)
|
||||||
|
unsafeRawMemoryToWasmCharArray(startAddress, 0, length, chars)
|
||||||
|
val newString = String(null, length, chars)
|
||||||
|
newString._hashCode = hashCode
|
||||||
|
stringPool[poolId] = newString
|
||||||
|
return newString
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@ import kotlin.wasm.internal.reftypes.anyref
|
|||||||
|
|
||||||
internal external interface ExternalInterfaceType
|
internal external interface ExternalInterfaceType
|
||||||
|
|
||||||
internal class JsExternalBox(val ref: ExternalInterfaceType) {
|
internal class JsExternalBox @WasmPrimitiveConstructor constructor(val ref: ExternalInterfaceType) {
|
||||||
override fun toString(): String =
|
override fun toString(): String =
|
||||||
externrefToString(ref)
|
externrefToString(ref)
|
||||||
|
|
||||||
@@ -20,8 +20,13 @@ internal class JsExternalBox(val ref: ExternalInterfaceType) {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int =
|
override fun hashCode(): Int {
|
||||||
externrefHashCode(ref)
|
var hashCode = _hashCode
|
||||||
|
if (hashCode != 0) return hashCode
|
||||||
|
hashCode = externrefHashCode(ref)
|
||||||
|
_hashCode = hashCode
|
||||||
|
return hashCode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//language=js
|
//language=js
|
||||||
@@ -218,7 +223,7 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
|
|||||||
val stringLength = stringLength(x)
|
val stringLength = stringLength(x)
|
||||||
val dstArray = WasmCharArray(stringLength)
|
val dstArray = WasmCharArray(stringLength)
|
||||||
if (stringLength == 0) {
|
if (stringLength == 0) {
|
||||||
return String(dstArray)
|
return dstArray.createString()
|
||||||
}
|
}
|
||||||
val maxStringLength = unsafeGetScratchRawMemorySize() / CHAR_SIZE_BYTES
|
val maxStringLength = unsafeGetScratchRawMemorySize() / CHAR_SIZE_BYTES
|
||||||
|
|
||||||
@@ -233,7 +238,7 @@ internal fun jsToKotlinStringAdapter(x: ExternalInterfaceType): String {
|
|||||||
|
|
||||||
jsExportStringToWasm(x, srcStartIndex, stringLength - srcStartIndex, memBuffer)
|
jsExportStringToWasm(x, srcStartIndex, stringLength - srcStartIndex, memBuffer)
|
||||||
unsafeRawMemoryToWasmCharArray(memBuffer, srcStartIndex, stringLength - srcStartIndex, dstArray)
|
unsafeRawMemoryToWasmCharArray(memBuffer, srcStartIndex, stringLength - srcStartIndex, dstArray)
|
||||||
return String(dstArray)
|
return dstArray.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ internal fun itoa32(inputValue: Int, radix: Int): String {
|
|||||||
if (sign == 1)
|
if (sign == 1)
|
||||||
buf.set(0, CharCodes.MINUS.code.toChar())
|
buf.set(0, CharCodes.MINUS.code.toChar())
|
||||||
|
|
||||||
return String(buf)
|
return buf.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun utoaDecSimple(buffer: WasmCharArray, numInput: Int, offsetInput: Int) {
|
private fun utoaDecSimple(buffer: WasmCharArray, numInput: Int, offsetInput: Int) {
|
||||||
@@ -144,7 +144,7 @@ internal fun itoa64(inputValue: Long, radix: Int): String {
|
|||||||
if (sign == 1)
|
if (sign == 1)
|
||||||
buf.set(0, CharCodes.MINUS.code.toChar())
|
buf.set(0, CharCodes.MINUS.code.toChar())
|
||||||
|
|
||||||
return String(buf)
|
return buf.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count number of decimals for u64 values
|
// Count number of decimals for u64 values
|
||||||
@@ -178,7 +178,7 @@ internal fun dtoa(value: Double): String {
|
|||||||
val size = dtoaCore(buf, value)
|
val size = dtoaCore(buf, value)
|
||||||
val ret = WasmCharArray(size)
|
val ret = WasmCharArray(size)
|
||||||
buf.copyInto(ret, 0, 0, size)
|
buf.copyInto(ret, 0, 0, size)
|
||||||
return String(ret)
|
return ret.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun dtoaCore(buffer: WasmCharArray, valueInp: Double): Int {
|
private fun dtoaCore(buffer: WasmCharArray, valueInp: Double): Int {
|
||||||
|
|||||||
@@ -81,3 +81,11 @@ internal class Void private constructor()
|
|||||||
@WasmOp(WasmOp.DROP)
|
@WasmOp(WasmOp.DROP)
|
||||||
internal fun consumeAnyIntoVoid(a: Any?): Void =
|
internal fun consumeAnyIntoVoid(a: Any?): Void =
|
||||||
implementedAsIntrinsic
|
implementedAsIntrinsic
|
||||||
|
|
||||||
|
@ExcludedFromCodegen
|
||||||
|
internal fun stringGetPoolSize(): Int =
|
||||||
|
implementedAsIntrinsic
|
||||||
|
|
||||||
|
// This initializer is a special case in FieldInitializersLowering
|
||||||
|
@EagerInitialization
|
||||||
|
internal val stringPool: Array<String?> = arrayOfNulls(stringGetPoolSize())
|
||||||
@@ -10,9 +10,11 @@ package kotlin.wasm.internal
|
|||||||
internal const val TYPE_INFO_ELEMENT_SIZE = 4
|
internal const val TYPE_INFO_ELEMENT_SIZE = 4
|
||||||
|
|
||||||
internal const val TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET = 0
|
internal const val TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET = 0
|
||||||
internal const val TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_TYPE_PACKAGE_NAME_ID_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
|
internal const val TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_ID_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET = TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_ID_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
|
internal const val TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_ID_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
internal const val TYPE_INFO_SUPER_TYPE_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_SUPER_TYPE_OFFSET = TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
internal const val TYPE_INFO_ITABLE_SIZE_OFFSET = TYPE_INFO_SUPER_TYPE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_ITABLE_SIZE_OFFSET = TYPE_INFO_SUPER_TYPE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
internal const val TYPE_INFO_ITABLE_OFFSET = TYPE_INFO_ITABLE_SIZE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
internal const val TYPE_INFO_ITABLE_OFFSET = TYPE_INFO_ITABLE_SIZE_OFFSET + TYPE_INFO_ELEMENT_SIZE
|
||||||
@@ -21,11 +23,13 @@ internal class TypeInfoData(val typeId: Int, val isInterface: Boolean, val packa
|
|||||||
|
|
||||||
internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData {
|
internal fun getTypeInfoTypeDataByPtr(typeInfoPtr: Int): TypeInfoData {
|
||||||
val fqNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET)
|
val fqNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_LENGTH_OFFSET)
|
||||||
val fqNameLengthPtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET)
|
val fqNameId = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_ID_OFFSET)
|
||||||
|
val fqNamePtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_PACKAGE_NAME_PRT_OFFSET)
|
||||||
val simpleNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET)
|
val simpleNameLength = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_LENGTH_OFFSET)
|
||||||
|
val simpleNameId = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_ID_OFFSET)
|
||||||
val simpleNamePtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET)
|
val simpleNamePtr = wasm_i32_load(typeInfoPtr + TYPE_INFO_TYPE_SIMPLE_NAME_PRT_OFFSET)
|
||||||
val packageName = stringLiteral(fqNameLengthPtr, fqNameLength)
|
val packageName = stringLiteral(fqNameId, fqNamePtr, fqNameLength, 0)
|
||||||
val simpleName = stringLiteral(simpleNamePtr, simpleNameLength)
|
val simpleName = stringLiteral(simpleNameId, simpleNamePtr, simpleNameLength, 0)
|
||||||
return TypeInfoData(typeInfoPtr, isInterface = false, packageName, simpleName)
|
return TypeInfoData(typeInfoPtr, isInterface = false, packageName, simpleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,3 +49,12 @@ internal annotation class WasmAutoboxed
|
|||||||
@ExcludedFromCodegen
|
@ExcludedFromCodegen
|
||||||
internal val implementedAsIntrinsic: Nothing
|
internal val implementedAsIntrinsic: Nothing
|
||||||
get() = null!!
|
get() = null!!
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that annotated constructor is primitive
|
||||||
|
* i.e. has direct layout from it's parameters to object fields (except any's fields) and has no code
|
||||||
|
* In this case no need to call it during an object creation.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||||
|
@Retention(AnnotationRetention.BINARY)
|
||||||
|
internal annotation class WasmPrimitiveConstructor
|
||||||
@@ -15,7 +15,7 @@ internal fun insertString(array: CharArray, destinationIndex: Int, value: String
|
|||||||
internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String {
|
internal fun unsafeStringFromCharArray(array: CharArray, start: Int, size: Int): String {
|
||||||
val copy = WasmCharArray(size)
|
val copy = WasmCharArray(size)
|
||||||
copyWasmArray(array.storage, copy, start, 0, size)
|
copyWasmArray(array.storage, copy, start, 0, size)
|
||||||
return String(copy)
|
return copy.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun insertInt(array: CharArray, start: Int, value: Int): Int {
|
internal fun insertInt(array: CharArray, start: Int, value: Int): Int {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ public actual fun String(chars: CharArray, offset: Int, length: Int): String {
|
|||||||
|
|
||||||
val copy = WasmCharArray(length)
|
val copy = WasmCharArray(length)
|
||||||
copyWasmArray(chars.storage, copy, offset, 0, length)
|
copyWasmArray(chars.storage, copy, offset, 0, length)
|
||||||
return String(copy)
|
return copy.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +88,7 @@ public actual fun CharArray.concatToString(): String {
|
|||||||
val thisLength = thisStorage.len()
|
val thisLength = thisStorage.len()
|
||||||
val copy = WasmCharArray(thisLength)
|
val copy = WasmCharArray(thisLength)
|
||||||
copyWasmArray(this.storage, copy, 0, 0, thisLength)
|
copyWasmArray(this.storage, copy, 0, 0, thisLength)
|
||||||
return String(copy)
|
return copy.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +109,7 @@ public actual fun CharArray.concatToString(startIndex: Int = 0, endIndex: Int =
|
|||||||
val length = endIndex - startIndex
|
val length = endIndex - startIndex
|
||||||
val copy = WasmCharArray(length)
|
val copy = WasmCharArray(length)
|
||||||
copyWasmArray(this.storage, copy, startIndex, 0, length)
|
copyWasmArray(this.storage, copy, startIndex, 0, length)
|
||||||
return String(copy)
|
return copy.createString()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user