Kotlin/Wasm Array
code:kotlin
fun main() {
box()
}
fun box() {
var riversArray = arrayOf("Nile", "Amazon", "Yangtze")
println(riversArray.joinToString())
}
code:lisp
(type $kotlin.Array___type_79 (sub $kotlin.Any___type_32 (struct
(field (ref $kotlin.Array.vtable___type_52))
(field (ref null struct))
(field (mut i32))
(field (mut i32))
(field (mut (ref null $kotlin.wasm.internal.WasmAnyArray___type_33))))))
(type $kotlin.wasm.internal.WasmAnyArray___type_33 (array (mut (ref null $kotlin.Any___type_32))))
kotlin.Array は Wasm用の builtin があって
code:kotlin
public class Array<T> @PublishedApi internal constructor(size: Int) {
internal val storage: WasmAnyArray
// ...
WasmAnyArray はこれ
code:kotlin
@Suppress("UNUSED_PARAMETER")
@WasmArrayOf(Any::class, isNullable = true)
internal class WasmAnyArray(size: Int) {
@WasmOp(WasmOp.ARRAY_GET)
fun get(index: Int): Any? =
implementedAsIntrinsic
@WasmOp(WasmOp.ARRAY_SET)
fun set(index: Int, value: Any?): Unit =
implementedAsIntrinsic
@WasmOp(WasmOp.ARRAY_LEN)
fun len(): Int =
implementedAsIntrinsic
}
WasmArrayOf とか WasmOp アノテーションなんだろう
code:kotlin
fun IrAnnotationContainer.getWasmOpAnnotation(): String? =
getAnnotation(FqName("kotlin.wasm.internal.WasmOp"))?.getSingleConstStringArgument()
fun IrAnnotationContainer.getWasmArrayAnnotation(): WasmArrayInfo? =
getAnnotation(FqName("kotlin.wasm.internal.WasmArrayOf"))?.let {
WasmArrayInfo(
(it.getValueArgument(0) as IrClassReference).symbol.owner as IrClass,
(it.getValueArgument(1) as IrConst<*>).value as Boolean,
)
}
これで取得して
code:kotlin
declaration.getWasmArrayAnnotation()?.let { wasmArrayAnnotation ->
val nameStr = declaration.fqNameWhenAvailable.toString()
val wasmArrayDeclaration = WasmArrayDeclaration(
nameStr,
WasmStructFieldDeclaration(
name = "field",
type = context.transformFieldType(wasmArrayAnnotation.type),
isMutable = true
)
)
context.defineGcType(symbol, wasmArrayDeclaration)
return
}
これで (type $kotlin.wasm.internal.WasmAnyArray___type_33 (array (mut (ref null $kotlin.Any___type_32)))) こういうのできるのね
例えば constructor call
code:kotlin
if (klass.getWasmArrayAnnotation() != null) {
require(expression.valueArgumentsCount == 1) { "@WasmArrayOf constructs must have exactly one argument" }
generateExpression(expression.getValueArgument(0)!!)
body.buildInstr(
WasmOp.ARRAY_NEW_DEFAULT,
location,
WasmImmediate.GcType(wasmGcType)
)
body.commentPreviousInstr { "@WasmArrayOf ctor call: ${klass.fqNameWhenAvailable}" }
return
}
下の例では array.new_fixed なんだよな
hr.icon
@WasmOp は?
Function apply 時に変換するのか
code:kotlin
if (tryToGenerateIntrinsicCall(call, function)) {
if (function.returnType.isUnit())
body.buildGetUnit()
return
}
tryToGenerateIntrinsicCall の先頭で
code:kotlin
if (tryToGenerateWasmOpIntrinsicCall(call, function)) {
return true
}
code:kotlin
private fun tryToGenerateWasmOpIntrinsicCall(call: IrFunctionAccessExpression, function: IrFunction): Boolean {
//...
val opString = function.getWasmOpAnnotation()
if (opString != null) {
val location = call.getSourceLocation()
val op = WasmOp.valueOf(opString)
when (op.immediates.size) {
0 -> {
body.buildInstr(op, location)
}
1 -> {
fun getReferenceGcType(): WasmSymbol<WasmTypeDeclaration> {
val type = function.dispatchReceiverParameter?.type ?: call.getTypeArgument(0)!!
return context.referenceGcType(type.classOrNull!!)
}
val immediates = arrayOf(
when (val imm = op.immediates0) { // ...
WasmImmediateKind.STRUCT_TYPE_IDX ->
WasmImmediate.GcType(getReferenceGcType())
WasmImmediateKind.HEAP_TYPE ->
WasmImmediate.HeapType(WasmHeapType.Type(getReferenceGcType()))
WasmImmediateKind.TYPE_IDX ->
WasmImmediate.TypeIdx(getReferenceGcType())
// ...
else ->
error("Immediate $imm is unsupported")
}
)
body.buildInstr(op, location, *immediates)
}
code:kotlin
// visitFunction, @WasmOp 画ある場合は intrinsic ってことでスキップ
val isIntrinsic = declaration.hasWasmNoOpCastAnnotation() || declaration.getWasmOpAnnotation() != null
if (isIntrinsic) {
return
}
code:lisp
(func $box___fun_257 (type $____type_10)
(local $0_riversArray (ref null $kotlin.Array___type_79))
;; Inlined call of kotlin.arrayOf
block (result (ref null $kotlin.Array___type_79))
;; Any parameters
global.get $kotlin.Array.vtable___g_44
ref.null struct
i32.const 564
i32.const 0
;; const string: "Nile"
i32.const 94
i32.const 2742
i32.const 4
call $kotlin.stringLiteral___fun_161
;; const string: "Amazon"
i32.const 95
i32.const 2750
i32.const 6
call $kotlin.stringLiteral___fun_161
;; const string: "Yangtze"
i32.const 96
i32.const 2762
i32.const 7
call $kotlin.stringLiteral___fun_161
array.new_fixed $kotlin.wasm.internal.WasmAnyArray___type_33 3
struct.new $kotlin.Array___type_79
br 0
end
local.tee $0_riversArray ;; type: kotlin.Array<kotlin.String>
ref.null none
ref.null none
ref.null none
ref.null none
ref.null none
ref.null none
i32.const 63
ref.null none
call $kotlin.collections.joinToString$default___fun_12
call $kotlin.io.println___fun_253)