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