mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-02 12:50:55 +00:00
implement a new native call bytecode mechanism that can be optimized by the vm
This commit is contained in:
parent
10308eae5c
commit
d2eaffafcc
@ -11,6 +11,25 @@ data class Constant(val id: UInt, val tag: ConstantTag, val value: ByteArray) {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
fun readAsNativeDefinition(): List<String> {
|
||||
val defs = mutableListOf<String>()
|
||||
val buffer = mutableListOf<Byte>()
|
||||
for (b in value) {
|
||||
if (b == 0.toByte()) {
|
||||
defs.add(String(buffer.toByteArray()))
|
||||
buffer.clear()
|
||||
continue
|
||||
}
|
||||
buffer.add(b)
|
||||
}
|
||||
|
||||
if (buffer.isNotEmpty()) {
|
||||
defs.add(String(buffer.toByteArray()))
|
||||
}
|
||||
|
||||
return defs
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
other as Constant
|
||||
|
@ -4,5 +4,6 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
enum class ConstantTag {
|
||||
String
|
||||
String,
|
||||
NativeDefinition,
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I
|
||||
code.emit(Opcode.CompareEqual)
|
||||
code.emit(Opcode.Not)
|
||||
}
|
||||
|
||||
IrInfixOp.EuclideanModulo -> code.emit(Opcode.EuclideanModulo)
|
||||
IrInfixOp.Remainder -> code.emit(Opcode.Remainder)
|
||||
IrInfixOp.Lesser -> code.emit(Opcode.CompareLesser)
|
||||
@ -207,7 +208,8 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I
|
||||
code.emit(Opcode.Integer, listOf(1u))
|
||||
code.emit(Opcode.Add, emptyList())
|
||||
}
|
||||
IrSuffixOp.Decrement-> {
|
||||
|
||||
IrSuffixOp.Decrement -> {
|
||||
code.emit(Opcode.Integer, listOf(1u))
|
||||
code.emit(Opcode.Subtract, emptyList())
|
||||
}
|
||||
@ -216,18 +218,22 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I
|
||||
}
|
||||
|
||||
override fun visitIrNativeDefinition(ir: IrNativeDefinition) {
|
||||
for (def in ir.definitions.reversed()) {
|
||||
val defConstant = symbol.compilableSlab.compiler.constantPool.assign(
|
||||
ConstantTag.String,
|
||||
def.encodeToByteArray()
|
||||
)
|
||||
code.emit(Opcode.Constant, listOf(defConstant))
|
||||
val encodedDefinitions = ir.definitions.map { def -> def.encodeToByteArray() }.toMutableList()
|
||||
encodedDefinitions.add(0, ir.form.encodeToByteArray())
|
||||
val buffer = ByteArray(encodedDefinitions.sumOf { it.size } + encodedDefinitions.size - 1) { 0 }
|
||||
var i = 0
|
||||
for ((index, encoded) in encodedDefinitions.withIndex()) {
|
||||
encoded.copyInto(buffer, i, 0)
|
||||
i += encoded.size
|
||||
if (index != encodedDefinitions.lastIndex) {
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
val formConstant = symbol.compilableSlab.compiler.constantPool.assign(
|
||||
ConstantTag.String,
|
||||
ir.form.encodeToByteArray()
|
||||
val nativeDefinitionConstant = symbol.compilableSlab.compiler.constantPool.assign(
|
||||
ConstantTag.NativeDefinition,
|
||||
buffer,
|
||||
)
|
||||
code.emit(Opcode.Native, listOf(formConstant, ir.definitions.size.toUInt(), functionArgumentCount.toUInt()))
|
||||
code.emit(Opcode.Native, listOf(nativeDefinitionConstant, functionArgumentCount.toUInt()))
|
||||
}
|
||||
|
||||
override fun visitIrIndex(ir: IrIndex) {
|
||||
|
@ -22,9 +22,11 @@ class CompileCommand : CliktCommand(help = "Compile Pork", name = "compile") {
|
||||
|
||||
val path by argument("file")
|
||||
|
||||
private val yaml = Yaml(configuration = Yaml.default.configuration.copy(
|
||||
polymorphismStyle = PolymorphismStyle.Property
|
||||
))
|
||||
private val yaml = Yaml(
|
||||
configuration = Yaml.default.configuration.copy(
|
||||
polymorphismStyle = PolymorphismStyle.Property
|
||||
)
|
||||
)
|
||||
|
||||
override fun run() {
|
||||
val tool = FileTool(PlatformFsProvider.resolve(path))
|
||||
@ -61,13 +63,14 @@ class CompileCommand : CliktCommand(help = "Compile Pork", name = "compile") {
|
||||
var annotation = ""
|
||||
val annotations = compiledWorld.annotations.filter { it.inst == (symbol.offset + index.toUInt()) }
|
||||
if (annotations.isNotEmpty()) {
|
||||
annotation = " ; ${annotations.joinToString(", ") { it.text}}"
|
||||
annotation = " ; ${annotations.joinToString(", ") { it.text }}"
|
||||
}
|
||||
print(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
||||
if (op.code == Opcode.Constant) {
|
||||
if (op.code == Opcode.Constant || op.code == Opcode.Native) {
|
||||
val constant = compiledWorld.constantPool.constants[op.args[0].toInt()]
|
||||
val constantString = when (constant.tag) {
|
||||
ConstantTag.String -> "\"" + constant.readAsString() + "\""
|
||||
ConstantTag.String -> "string = \"" + constant.readAsString() + "\""
|
||||
ConstantTag.NativeDefinition -> "native definition = " + constant.readAsNativeDefinition().joinToString(" ") { def -> "\"${def}\"" }
|
||||
}
|
||||
print(" ; constant: $constantString")
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import gay.pizza.pork.execution.NativeRegistry
|
||||
|
||||
class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegistry, val handlers: List<OpHandler>) {
|
||||
private val inlined = world.code.map { op ->
|
||||
val handler = handlers.firstOrNull { it.code == op.code } ?:
|
||||
throw VirtualMachineException("Opcode ${op.code.name} does not have a handler.")
|
||||
op to handler
|
||||
val handler = handlers.firstOrNull { it.code == op.code }
|
||||
?: throw VirtualMachineException("Opcode ${op.code.name} does not have a handler.")
|
||||
op to (handler.optimize(machine = this, op) ?: handler)
|
||||
}
|
||||
|
||||
private var inst: UInt = 0u
|
||||
|
@ -5,4 +5,6 @@ import gay.pizza.pork.bytecode.Opcode
|
||||
|
||||
abstract class OpHandler(val code: Opcode) {
|
||||
abstract fun handle(machine: InternalMachine, op: Op)
|
||||
|
||||
open fun optimize(machine: InternalMachine, op: Op): OpHandler? = null
|
||||
}
|
||||
|
@ -8,23 +8,15 @@ import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
object NativeOpHandler : OpHandler(Opcode.Native) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val argumentCount = op.args[2]
|
||||
val arguments = mutableListOf<Any>()
|
||||
var x = argumentCount
|
||||
while (x > 0u) {
|
||||
x--
|
||||
arguments.add(machine.localAt(x))
|
||||
}
|
||||
val formConstant = machine.world.constantPool.read(op.args[0])
|
||||
val form = formConstant.readAsString()
|
||||
val handler = optimize(machine, op)
|
||||
handler.handle(machine, op)
|
||||
}
|
||||
|
||||
override fun optimize(machine: InternalMachine, op: Op): OpHandler {
|
||||
val nativeDefinition = machine.world.constantPool.read(op.args[0]).readAsNativeDefinition()
|
||||
val form = nativeDefinition[0]
|
||||
val provider = machine.nativeRegistry.of(form)
|
||||
val countOfNativeDefs = op.args[1].toInt()
|
||||
val defs = mutableListOf<String>()
|
||||
for (i in 0 until countOfNativeDefs) {
|
||||
defs.add(machine.pop())
|
||||
}
|
||||
val function = provider.provideNativeFunction(defs)
|
||||
val result = function.invoke(arguments)
|
||||
machine.push(if (result == Unit) None else result)
|
||||
val function = provider.provideNativeFunction(nativeDefinition.subList(1, nativeDefinition.size))
|
||||
return OptimizedNativeOpHandler(function)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
package gay.pizza.pork.vm.ops
|
||||
|
||||
import gay.pizza.pork.bytecode.Op
|
||||
import gay.pizza.pork.bytecode.Opcode
|
||||
import gay.pizza.pork.execution.NativeFunction
|
||||
import gay.pizza.pork.execution.None
|
||||
import gay.pizza.pork.vm.InternalMachine
|
||||
import gay.pizza.pork.vm.OpHandler
|
||||
|
||||
class OptimizedNativeOpHandler(val function: NativeFunction) : OpHandler(Opcode.Native) {
|
||||
override fun handle(machine: InternalMachine, op: Op) {
|
||||
val argumentCount = op.args[1]
|
||||
val arguments = mutableListOf<Any>()
|
||||
var x = argumentCount
|
||||
while (x > 0u) {
|
||||
x--
|
||||
arguments.add(machine.localAt(x))
|
||||
}
|
||||
val result = function.invoke(arguments)
|
||||
machine.push(if (result == Unit) None else result)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user