Skip to content

Commit

Permalink
decode shared status of memory types
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlieTap committed Nov 19, 2024
1 parent fdf95f8 commit 7641c78
Show file tree
Hide file tree
Showing 14 changed files with 112 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package io.github.charlietap.chasm.ast.type

data class MemoryType(
val limits: Limits,
val shared: Boolean,
val shared: SharedStatus,
) : Type
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package io.github.charlietap.chasm.ast.type

enum class SharedStatus {
Shared,
Unshared,
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.charlietap.chasm.embedding.transform

import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.embedding.shapes.Limits
import io.github.charlietap.chasm.embedding.shapes.MemoryType
import io.github.charlietap.chasm.ast.type.Limits as InternalLimits
Expand All @@ -9,11 +10,12 @@ internal class MemoryTypeMapper(
private val limitsMapper: BidirectionalMapper<Limits, InternalLimits> = LimitsMapper,
) : BidirectionalMapper<MemoryType, InternalMemoryType> {
override fun map(input: MemoryType): InternalMemoryType {
return InternalMemoryType(limitsMapper.map(input.limits), input.shared)
val status = if (input.shared) SharedStatus.Shared else SharedStatus.Unshared
return InternalMemoryType(limitsMapper.map(input.limits), status)
}

override fun bimap(input: InternalMemoryType): MemoryType {
return MemoryType(limitsMapper.bimap(input.limits), input.shared)
return MemoryType(limitsMapper.bimap(input.limits), input.shared == SharedStatus.Shared)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,33 @@ import com.github.michaelbull.result.Result
import com.github.michaelbull.result.binding
import com.github.michaelbull.result.flatMap
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.decoder.context.DecoderContext
import io.github.charlietap.chasm.decoder.error.TypeDecodeError
import io.github.charlietap.chasm.decoder.error.WasmDecodeError

internal fun LimitsDecoder(
context: DecoderContext,
): Result<Limits, WasmDecodeError> = binding {
): Result<Pair<Limits, SharedStatus>, WasmDecodeError> = binding {

val hasMaximum = context.reader.ubyte().flatMap { byte ->
val (hasMaximum, sharedStatus) = context.reader.ubyte().flatMap { byte ->
when (byte) {
0.toUByte() -> Ok(false)
1.toUByte() -> Ok(true)
LIMIT_NO_MAX -> Ok(false to SharedStatus.Unshared)
LIMIT_MAX_UNSHARED -> Ok(true to SharedStatus.Unshared)
LIMIT_MAX_SHARED -> Ok(true to SharedStatus.Shared)
else -> Err(TypeDecodeError.UnknownLimitsFlag(byte))
}
}.bind()

val minimum = context.reader.uint().bind()

if (hasMaximum) {
Limits(minimum, context.reader.uint().bind())
Limits(minimum, context.reader.uint().bind()) to sharedStatus
} else {
Limits(minimum)
Limits(minimum) to sharedStatus
}
}

internal const val LIMIT_NO_MAX: UByte = 0u
internal const val LIMIT_MAX_UNSHARED: UByte = 1u
internal const val LIMIT_MAX_SHARED: UByte = 3u
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.michaelbull.result.Result
import com.github.michaelbull.result.binding
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.MemoryType
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.decoder.context.DecoderContext
import io.github.charlietap.chasm.decoder.decoder.Decoder
import io.github.charlietap.chasm.decoder.decoder.type.limits.LimitsDecoder
Expand All @@ -18,8 +19,8 @@ internal fun MemoryTypeDecoder(

internal inline fun MemoryTypeDecoder(
context: DecoderContext,
crossinline limitsDecoder: Decoder<Limits>,
crossinline limitsDecoder: Decoder<Pair<Limits, SharedStatus>>,
): Result<MemoryType, WasmDecodeError> = binding {
val limits = limitsDecoder(context).bind()
MemoryType(limits, false)
val (limits, shared) = limitsDecoder(context).bind()
MemoryType(limits, shared)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.michaelbull.result.Result
import com.github.michaelbull.result.binding
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.ReferenceType
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.ast.type.TableType
import io.github.charlietap.chasm.decoder.context.DecoderContext
import io.github.charlietap.chasm.decoder.decoder.Decoder
Expand All @@ -22,9 +23,9 @@ internal fun TableTypeDecoder(
internal inline fun TableTypeDecoder(
context: DecoderContext,
crossinline referenceTypeDecoder: Decoder<ReferenceType>,
crossinline limitsDecoder: Decoder<Limits>,
crossinline limitsDecoder: Decoder<Pair<Limits, SharedStatus>>,
): Result<TableType, WasmDecodeError> = binding {
val referenceType = referenceTypeDecoder(context).bind()
val limits = limitsDecoder(context).bind()
val (limits, _) = limitsDecoder(context).bind()
TableType(referenceType, limits)
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
package io.github.charlietap.chasm.decoder.decoder.section.import

import com.github.michaelbull.result.Ok
import io.github.charlietap.chasm.ast.module.Import
import io.github.charlietap.chasm.ast.module.Index
import io.github.charlietap.chasm.ast.type.AbstractHeapType
import io.github.charlietap.chasm.ast.type.GlobalType
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.MemoryType
import io.github.charlietap.chasm.ast.type.ReferenceType
import io.github.charlietap.chasm.ast.type.TableType
import io.github.charlietap.chasm.ast.type.TagType
import io.github.charlietap.chasm.decoder.decoder.Decoder
import io.github.charlietap.chasm.decoder.fixture.decoderContext
import io.github.charlietap.chasm.decoder.fixture.ioError
import io.github.charlietap.chasm.decoder.reader.FakeUByteReader
import io.github.charlietap.chasm.decoder.reader.IOErrorWasmFileReader
import io.github.charlietap.chasm.fixture.module.functionImportDescriptor
import io.github.charlietap.chasm.fixture.module.globalImportDescriptor
import io.github.charlietap.chasm.fixture.module.memoryImportDescriptor
import io.github.charlietap.chasm.fixture.module.tableImportDescriptor
import io.github.charlietap.chasm.fixture.module.tagImportDescriptor
import io.github.charlietap.chasm.fixture.module.type
import io.github.charlietap.chasm.fixture.module.typeIndex
import io.github.charlietap.chasm.fixture.type.functionRecursiveType
import io.github.charlietap.chasm.fixture.type.globalType
import io.github.charlietap.chasm.fixture.type.limits
import io.github.charlietap.chasm.fixture.type.memoryType
import io.github.charlietap.chasm.fixture.type.refNullReferenceType
import io.github.charlietap.chasm.fixture.type.tableType
import io.github.charlietap.chasm.fixture.type.tagType
import io.github.charlietap.chasm.type.factory.DefinedTypeFactory
import kotlin.test.Test
Expand All @@ -35,7 +41,7 @@ class ImportDescriptorDecoderTest {

val recursiveType = functionRecursiveType()
val functionType = DefinedTypeFactory(listOf(recursiveType))
val expected = Ok(Import.Descriptor.Function(functionType.first()))
val expected = Ok(functionImportDescriptor(functionType.first()))

val reader = FakeUByteReader {
Ok(descriptor)
Expand Down Expand Up @@ -71,8 +77,8 @@ class ImportDescriptorDecoderTest {

val descriptor = IMPORT_DESCRIPTOR_TYPE_TABLE

val tableType = TableType(ReferenceType.RefNull(AbstractHeapType.Func), Limits(117u))
val expected = Ok(Import.Descriptor.Table(tableType))
val tableType = tableType(refNullReferenceType(AbstractHeapType.Func), Limits(117u))
val expected = Ok(tableImportDescriptor(tableType))

val reader = FakeUByteReader {
Ok(descriptor)
Expand Down Expand Up @@ -100,8 +106,8 @@ class ImportDescriptorDecoderTest {

val descriptor = IMPORT_DESCRIPTOR_TYPE_MEMORY

val memoryType = memoryType(Limits(117u), false)
val expected = Ok(Import.Descriptor.Memory(memoryType))
val memoryType = memoryType(limits(117u))
val expected = Ok(memoryImportDescriptor(memoryType))

val reader = FakeUByteReader {
Ok(descriptor)
Expand Down Expand Up @@ -130,7 +136,7 @@ class ImportDescriptorDecoderTest {
val descriptor = IMPORT_DESCRIPTOR_TYPE_GLOBAL

val globalType = globalType()
val expected = Ok(Import.Descriptor.Global(globalType))
val expected = Ok(globalImportDescriptor(globalType))

val reader = FakeUByteReader {
Ok(descriptor)
Expand Down Expand Up @@ -159,7 +165,7 @@ class ImportDescriptorDecoderTest {
val descriptor = IMPORT_DESCRIPTOR_TYPE_TAG

val tagType = tagType()
val expected = Ok(Import.Descriptor.Tag(tagType))
val expected = Ok(tagImportDescriptor(tagType))

val reader = FakeUByteReader {
Ok(descriptor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.decoder.error.TypeDecodeError
import io.github.charlietap.chasm.decoder.error.WasmDecodeError
import io.github.charlietap.chasm.decoder.fixture.decoderContext
Expand All @@ -19,7 +20,7 @@ class LimitsDecoderTest {
fun `can decode encoded limits with only minimum`() {

val byteReader: () -> Result<UByte, WasmDecodeError> = {
Ok(0u.toUByte())
Ok(LIMIT_NO_MAX)
}
val intReader: () -> Result<UInt, WasmDecodeError> = {
Ok(117u)
Expand All @@ -30,17 +31,17 @@ class LimitsDecoderTest {
)
val context = decoderContext(reader)

val expected = Ok(Limits(117u))
val expected = Ok(Limits(117u) to SharedStatus.Unshared)

val actual = LimitsDecoder(context)
assertEquals(expected, actual)
}

@Test
fun `can decode encoded limits with maximum`() {
fun `can decode encoded limits with maximum which is not shared`() {

val byteReader: () -> Result<UByte, WasmDecodeError> = {
Ok(1u.toUByte())
Ok(LIMIT_MAX_UNSHARED)
}
val minMax = sequenceOf(117u, 121u).iterator()
val intReader: () -> Result<UInt, WasmDecodeError> = {
Expand All @@ -52,7 +53,29 @@ class LimitsDecoderTest {
)
val context = decoderContext(reader)

val expected = Ok(Limits(117u, 121u))
val expected = Ok(Limits(117u, 121u) to SharedStatus.Unshared)

val actual = LimitsDecoder(context)
assertEquals(expected, actual)
}

@Test
fun `can decode encoded limits with maximum which is shared`() {

val byteReader: () -> Result<UByte, WasmDecodeError> = {
Ok(LIMIT_MAX_SHARED)
}
val minMax = sequenceOf(117u, 121u).iterator()
val intReader: () -> Result<UInt, WasmDecodeError> = {
Ok(minMax.next())
}
val reader = FakeWasmBinaryReader(
fakeUByteReader = byteReader,
fakeUIntReader = intReader,
)
val context = decoderContext(reader)

val expected = Ok(Limits(117u, 121u) to SharedStatus.Shared)

val actual = LimitsDecoder(context)
assertEquals(expected, actual)
Expand All @@ -62,14 +85,14 @@ class LimitsDecoderTest {
fun `returns an unknown flag error when flag doesn't match`() {

val byteReader: () -> Result<UByte, WasmDecodeError> = {
Ok(3u.toUByte())
Ok(117u.toUByte())
}
val reader = FakeWasmBinaryReader(
fakeUByteReader = byteReader,
)
val context = decoderContext(reader)

val expected = Err(TypeDecodeError.UnknownLimitsFlag(3u.toUByte()))
val expected = Err(TypeDecodeError.UnknownLimitsFlag(117u.toUByte()))

val actual = LimitsDecoder(context)
assertEquals(expected, actual)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ package io.github.charlietap.chasm.decoder.decoder.type.memory

import com.github.michaelbull.result.Ok
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.decoder.decoder.Decoder
import io.github.charlietap.chasm.decoder.fixture.decoderContext
import io.github.charlietap.chasm.decoder.fixture.ioError
import io.github.charlietap.chasm.decoder.reader.IOErrorWasmFileReader
import io.github.charlietap.chasm.fixture.type.limits
import io.github.charlietap.chasm.fixture.type.memoryType
import io.github.charlietap.chasm.fixture.type.sharedStatus
import kotlin.test.Test
import kotlin.test.assertEquals

Expand All @@ -15,11 +18,12 @@ class MemoryTypeDecoderTest {
@Test
fun `can decode an encoded memory type`() {

val limits = Limits(117u, 121u)
val limitsDecoder: Decoder<Limits> = {
Ok(limits)
val status = sharedStatus()
val limits = limits(117u, 121u)
val limitsDecoder: Decoder<Pair<Limits, SharedStatus>> = {
Ok(limits to status)
}
val expected = Ok(memoryType(limits))
val expected = Ok(memoryType(limits, status))

val actual = MemoryTypeDecoder(decoderContext(), limitsDecoder)
assertEquals(expected, actual)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import com.github.michaelbull.result.Ok
import io.github.charlietap.chasm.ast.type.AbstractHeapType
import io.github.charlietap.chasm.ast.type.Limits
import io.github.charlietap.chasm.ast.type.ReferenceType
import io.github.charlietap.chasm.ast.type.TableType
import io.github.charlietap.chasm.ast.type.SharedStatus
import io.github.charlietap.chasm.decoder.decoder.Decoder
import io.github.charlietap.chasm.decoder.fixture.decoderContext
import io.github.charlietap.chasm.decoder.fixture.ioError
import io.github.charlietap.chasm.decoder.reader.FakeUByteReader
import io.github.charlietap.chasm.decoder.reader.IOErrorWasmFileReader
import io.github.charlietap.chasm.fixture.type.limits
import io.github.charlietap.chasm.fixture.type.refNullReferenceType
import io.github.charlietap.chasm.fixture.type.sharedStatus
import io.github.charlietap.chasm.fixture.type.tableType
import kotlin.test.Test
import kotlin.test.assertEquals

Expand All @@ -24,18 +28,19 @@ class TableTypeDecoderTest {
}
val context = decoderContext(reader)

val refType = ReferenceType.RefNull(AbstractHeapType.Func)
val refType = refNullReferenceType(AbstractHeapType.Func)
val referenceTypeDecoder: Decoder<ReferenceType> = { _context ->
assertEquals(context, _context)
Ok(refType)
}

val limits = Limits(117u, 121u)
val limitsDecoder: Decoder<Limits> = {
Ok(limits)
val limits = limits(117u, 121u)
val status = sharedStatus()
val limitsDecoder: Decoder<Pair<Limits, SharedStatus>> = {
Ok(limits to status)
}

val expected = Ok(TableType(refType, limits))
val expected = Ok(tableType(refType, limits))

val actual = TableTypeDecoder(
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fun MemoryGrowerImpl(
val newLimits = memoryInstance.type.limits.copy(
min = memoryInstance.type.limits.min + pagesToAdd.toUInt(),
)
val newType = MemoryType(newLimits, false)
val newType = MemoryType(newLimits, memoryInstance.type.shared)

MemoryInstance(newType, newData)
}
Loading

0 comments on commit 7641c78

Please sign in to comment.