Skip to content

Commit

Permalink
refactor: removed unneeded machinery
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mie6 committed Jan 4, 2025
1 parent 2d9e1c6 commit 2495825
Show file tree
Hide file tree
Showing 7 changed files with 11 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ private [deepembedding] final class >>=[A, B](val p: StrictParsley[A], private [
suspend(p.codeGen[M, R](producesResults = true)) |> {
instrs += instructions.DynCall[A] { (x, refsSz) =>
val q = f(x)
q.demandCalleeSave(state.numRegs)
q.setMinReferenceAllocation(refsSz)
if (implicitly[ContOps[M]].isStackSafe) q.overflows()
q.instrs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ private [deepembedding] trait StrictParsley[+A] {
* @param state the code generator state
* @return the final array of instructions for this parser
*/
final private [deepembedding] def generateInstructions[M[_, +_]: ContOps](numRegsUsedByParent: Int, minRef: Int, usedRefs: Set[Ref[_]],
bodyMap: Map[Let[_], StrictParsley[_]])
final private [deepembedding] def generateInstructions[M[_, +_]: ContOps](minRef: Int, usedRefs: Set[Ref[_]], bodyMap: Map[Let[_], StrictParsley[_]])
(implicit state: CodeGenState): Array[Instr] = {
implicit val instrs: InstrBuffer = newInstrBuffer
perform {
generateCalleeSave[M, Array[Instr]](numRegsUsedByParent, minRef, this.codeGen(producesResults = true), usedRefs) |> {
// When `numRegsUsedByParent` is -1 this is top level, otherwise it is a flatMap
instrs += (if (numRegsUsedByParent >= 0) instructions.Return else instructions.Halt)
generateCalleeSave[M, Array[Instr]](minRef, this.codeGen(producesResults = true), usedRefs) |> {
// When `minRef` is -1 this is top level, otherwise it is a flatMap
instrs += (if (minRef >= 0) instructions.Return else instructions.Halt)
val letRets = finaliseLets(bodyMap)
generateHandlers(state.handlers)
finaliseInstrs(instrs, state.nlabels, letRets)
Expand Down Expand Up @@ -132,26 +131,14 @@ private [deepembedding] object StrictParsley {
* @param instrs the instruction buffer
* @param state the code generation state, for label generation
*/
private def generateCalleeSave[M[_, +_], R](@scala.annotation.unused numRegsUsedByParent: Int, minRef: Int, bodyGen: =>M[R, Unit], usedRefs: Set[Ref[_]])
(implicit instrs: InstrBuffer, @scala.annotation.unused state: CodeGenState): M[R, Unit] = {
//val reqRegs = usedRefs.size
private def generateCalleeSave[M[_, +_], R](minRef: Int, bodyGen: =>M[R, Unit], usedRefs: Set[Ref[_]])(implicit instrs: InstrBuffer): M[R, Unit] = {
// TODO: check for reference conflict
val localRegs = usedRefs.filterNot(_.allocated)
val totalSlotsRequired = allocateRegisters(minRef, localRegs)
//val calleeSaveRequired = numRegsUsedByParent >= 0 // if this is -1, then we are the top level and have no parent, otherwise it needs to be done
val refExpandRequired = minRef >= 0 // if this is -1, then we are the top level and have no parent, otherwise it needs to be done
if (refExpandRequired && localRegs.nonEmpty) {
//val end = state.freshLabel()
//val calleeSave = state.freshLabel()
//instrs += new instructions.Push(false) // callee-save is not active
//instrs += new instructions.Label(calleeSave)
//instrs += new instructions.CalleeSave(end, localRegs, reqRegs, allocatedRegs, numRegsUsedByParent)
//bodyGen
//instrs += new instructions.Push(true) // callee-save is active
//instrs += new instructions.Jump(calleeSave)
//instrs += new instructions.Label(end)
// if this is -1, then we are the top level and have no parent, otherwise it needs to be done
if (minRef >= 0 && localRegs.nonEmpty) {
instrs += new instructions.ExpandRefs(totalSlotsRequired)
}
//else bodyGen
bodyGen
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] {
// The instructions used to execute this parser along with the number of registers it uses
final private [parsley] lazy val (instrs: Array[Instr], numRegs: Int) = computeInstrs

/** This parser is the result of a `flatMap` operation, and as such must perform
* callee-save on `numRegs` registers (which belong to its parent)
*
* @param numRegs the number of registers the parent uses (these must be saved)
*/
private [deepembedding] def demandCalleeSave(numRegs: Int): Unit = numRegsUsedByParent = numRegs

/** This parser is the result of a `flatMap` operation, and as such may need to expand
* the refs set. If so, it needs to know what the minimum free slot is according to
* the context.
Expand Down Expand Up @@ -90,7 +83,6 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] {
final private var cps = false
final private [deepembedding] def isCps: Boolean = cps
/** how many registers are used by the ''parent'' of this combinator (this combinator is part of a `flatMap` when this is not -1) */
/*@deprecated("this is no longer needed", "5.0.0-M10")*/ final private var numRegsUsedByParent = -1
final private var minRef = -1

/** Computes the instructions associated with this parser as well as the number of
Expand Down Expand Up @@ -124,7 +116,7 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] {
implicit val letMap: LetMap = LetMap(letFinderState.lets, letFinderState.recs)
for { sp <- this.optimised } yield {
implicit val state: backend.CodeGenState = new backend.CodeGenState(letFinderState.numRegs)
sp.generateInstructions(numRegsUsedByParent, minRef, usedRefs, letMap.bodies)
sp.generateInstructions(minRef, usedRefs, letMap.bodies)
}
}
}, letFinderState.numRegs)
Expand Down
18 changes: 1 addition & 17 deletions parsley/shared/src/main/scala/parsley/internal/diagnostics.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
package parsley.internal.diagnostics

import parsley.exceptions.{BadLazinessException, CorruptedReferenceException, ParsleyException}
import parsley.exceptions.{BadLazinessException, ParsleyException}

private [parsley] object UserException {
def unapply(e: Throwable): Option[Throwable] = e match {
Expand All @@ -25,22 +25,6 @@ private [parsley] object UserException {
}
}

private [parsley] object RegisterOutOfBoundsException {
def unapply(e: Throwable): Option[Throwable] = e match {
case e: ArrayIndexOutOfBoundsException => e.getStackTrace.headOption.collect {
// this exception was thrown plainly during the execution of an instruction
// only register arrays are accessed raw like this: therefore it must be an
// out of bounds register.
case ste if ste.getMethodName == "apply"
&& ste.getClassName.startsWith("parsley.internal.machine.instructions") =>
val err = new CorruptedReferenceException
err.addSuppressed(e)
err
}
case _ => None
}
}

private [parsley] object NullParserException {
def unapply(e: Throwable): Option[Throwable] = e match {
// this should only be true when the null was tripped from within the parsley namespace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import parsley.Success
import parsley.XAssert._
import parsley.errors.ErrorBuilder

import parsley.internal.diagnostics.RegisterOutOfBoundsException
import parsley.internal.errors.{CaretWidth, ExpectItem, LineBuilder, UnexpectDesc}
import parsley.internal.machine.errors.{ClassicFancyError, DefuncError, DefuncHints, EmptyHints,
ErrorItemBuilder, ExpectedError, ExpectedErrorWithReason, UnexpectedError}
Expand Down Expand Up @@ -125,15 +124,7 @@ private [parsley] final class Context(private [machine] var instrs: Array[Instr]
}
// $COVERAGE-ON$

private [parsley] def run[Err: ErrorBuilder, A](): Result[Err, A] = {
try go[Err, A]()
catch {
// additional diagnostic checks
// $COVERAGE-OFF$
case RegisterOutOfBoundsException(err) => throw err // scalastyle:ignore throw
// $COVERAGE-ON$
}
}
private [parsley] def run[Err: ErrorBuilder, A](): Result[Err, A] = go[Err, A]()
@tailrec private def go[Err: ErrorBuilder, A](): Result[Err, A] = {
//println(pretty)
if (running) { // this is the likeliest branch, so should be executed with fewest comparisons
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
*/
package parsley.internal.machine.instructions

//import parsley.state.Ref
import parsley.token.errors.LabelConfig

import parsley.internal.errors.ExpectDesc
Expand Down Expand Up @@ -154,76 +153,6 @@ private [internal] object Span extends Instr {
// $COVERAGE-ON$
}

// FIXME: this isn't re-entrant, the stack allows us to tell, but the persisted
// references are shared across nested visits. Is the reference deallocation idea also screwy?
// perhaps deallocation only occurs when we have an empty restore stack (I think this is true,
// because deallocation allows for the reference to be remapped later, but we always want the
// same mapping for a let-bound parser)
// TODO: unit test to demonstrate the above issue!
// This instruction holds mutable state, but it is safe to do so, because it's always the first instruction of a DynCall.
/*private [parsley] final class CalleeSave(var label: Int, localRefs: Set[Ref[_]], reqSize: Int, slots: List[(Int, Int)], saveArray: Array[AnyRef])
extends InstrWithLabel {
private def this(label: Int, localRefs: Set[Ref[_]], reqSize: Int, slots: List[Int]) =
this(label, localRefs, reqSize, slots.zipWithIndex, new Array[AnyRef](slots.length))
// this filters out the slots to ensure we only do callee-save on registers that might exist in the parent
def this(label: Int, localRefs: Set[Ref[_]], reqSize: Int, slots: List[Int], numRegsInContext: Int) =
this(label, localRefs, reqSize, slots.takeWhile(_ < numRegsInContext))
private var oldRegs: Array[AnyRef] = null
private def save(ctx: Context): Unit = {
for ((slot, idx) <- slots) {
saveArray(idx) = ctx.regs(slot)
ctx.regs(slot) = null
}
// If this is known to increase the size of the register pool, then we need to keep the old array to the side
if (reqSize > ctx.regs.size) {
oldRegs = ctx.regs
ctx.regs = java.util.Arrays.copyOf(oldRegs, reqSize)
}
}
private def restore(ctx: Context): Unit = {
if (oldRegs != null) {
java.lang.System.arraycopy(ctx.regs, 0, oldRegs, 0, oldRegs.size)
ctx.regs = oldRegs
oldRegs = null
}
for ((slot, idx) <- slots) {
ctx.regs(slot) = saveArray(idx)
saveArray(idx) = null
}
// This is the only way to get them reallocated on the next invocation
// FIXME: I think this isn't thread-safe, because two flatMaps can simulataneously reallocate?
localRefs.foreach(_.deallocate())
}
private def continue(ctx: Context): Unit = {
ctx.handlers = ctx.handlers.tail
if (ctx.good) ctx.pc = label
else ctx.fail()
}
override def apply(ctx: Context): Unit = {
val inUse = !ctx.good || ctx.stack.pop[Boolean]()
// Second-entry, callee-restore and either jump or fail
if (inUse) {
restore(ctx)
continue(ctx)
}
// Entry for the first time, register as a handle, callee-save and inc
else {
ensureRegularInstruction(ctx)
save(ctx)
ctx.pushHandler(ctx.pc)
ctx.inc()
}
}
// $COVERAGE-OFF$
override def toString: String = s"CalleeSave($label, newSz = $reqSize, slotsToSave = $slots)"
// $COVERAGE-ON$
}*/

private [parsley] final class ExpandRefs(newSz: Int) extends Instr {
override def apply(ctx: Context): Unit = {
if (newSz > ctx.regs.size) {
Expand Down
4 changes: 0 additions & 4 deletions parsley/shared/src/main/scala/parsley/state.scala
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,6 @@ object state {
assert(!allocated)
this._v = v
}
private [parsley] def deallocate(): Unit = {
assert((new Throwable).getStackTrace.exists(_.getClassName == "parsley.internal.machine.instructions.CalleeSave"))
_v = -1
}
//override def toString: String = s"Reg(${if (allocated) addr else "unallocated"})"
}

Expand Down

0 comments on commit 2495825

Please sign in to comment.