Skip to content

Commit d6658f2

Browse files
author
Felix A. Wolf
committed
added more precise handling of method without body and restricted selection of isolated nodes to nodes of the files provided with -i
1 parent da45602 commit d6658f2

File tree

4 files changed

+76
-46
lines changed

4 files changed

+76
-46
lines changed

GobraChopper.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Example of a chopper config file.
55

66
// merge penalty uses the multiplier "sum of price of shared nodes" / threshold_shared + 1
7-
threshold_shared=50
7+
threshold_shared=200
88

99
// price of method with body
1010
method_body=0

src/main/scala/viper/gobra/frontend/Source.scala

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import java.nio.file.{Files, Path, Paths}
1111

1212
import org.bitbucket.inkytonik.kiama.util.{FileSource, Filenames, IO, Source, StringSource}
1313
import viper.gobra.util.Violation
14+
import viper.silver.ast.SourcePosition
1415

1516
import scala.io.BufferedSource
1617

@@ -39,6 +40,8 @@ object Source {
3940
// style but at least any use fails in an understandable way (as opposed to simply returning `null` here)
4041
???
4142
}
43+
44+
def contains(position: SourcePosition): Boolean = toPath == position.file
4245
}
4346

4447
/**

src/main/scala/viper/gobra/util/ChopperUtil.scala

+16-8
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,28 @@ object ChopperUtil {
4040
def computeIsolateMap(config: Config): Option[vpr.Member => Boolean] = {
4141
import viper.gobra.reporting.Source
4242

43-
def hit(x: SourcePosition, target: SourcePosition): Boolean = {
44-
(target.end match {
45-
case None => x.start.line == target.start.line
46-
case Some(pos) => target.start.line <= x.start.line && x.start.line <= pos.line
47-
}) && x.file.getFileName == target.file.getFileName
43+
val isIsolated = config.isolate match {
44+
case Some(isolatedPositions) =>
45+
def hitPosition(x: SourcePosition, target: SourcePosition): Boolean = {
46+
(target.end match {
47+
case None => x.start.line == target.start.line
48+
case Some(pos) => target.start.line <= x.start.line && x.start.line <= pos.line
49+
}) && x.file.getFileName == target.file.getFileName
50+
}
51+
(memberPosition: SourcePosition) => isolatedPositions.exists(hitPosition(_, memberPosition))
52+
53+
case None =>
54+
import viper.gobra.frontend.Source.TransformableSource
55+
(memberPosition: SourcePosition) => config.inputs.exists(_.contains(memberPosition))
4856
}
4957

50-
config.isolate.map { names => {
58+
Some {
5159
case x@(_: vpr.Method | _: vpr.Function | _: vpr.Predicate) => x match {
52-
case Source(Source.Verifier.Info(_, _, origin, _)) => names.exists(hit(_, origin.pos))
60+
case Source(Source.Verifier.Info(_, _, origin, _)) => isIsolated(origin.pos)
5361
case _ => false
5462
}
5563
case _ => false
56-
}}
64+
}
5765
}
5866

5967
/**

src/main/scala/viper/gobra/util/ViperChopper.scala

+56-37
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,9 @@ object ViperChopper {
386386
case Vertex.Always => 0
387387
}
388388

389-
override def mergePenalty(lhsExclusivePrice: Int, rhsExclusivePrice: Int, sharedPrice: Int): Int =
389+
override def mergePenalty(lhsExclusivePrice: Int, rhsExclusivePrice: Int, sharedPrice: Int): Int = {
390390
(lhsExclusivePrice + rhsExclusivePrice) * ((conf.sharedThreshold + sharedPrice).toFloat / conf.sharedThreshold).toInt
391+
}
391392
}
392393

393394
object Default extends DefaultImpl(defaultPenaltyConfig)
@@ -437,7 +438,7 @@ object ViperChopper {
437438
}
438439
// The isotated nodes are always and all selected nodes
439440
val alwaysId = id(Always)
440-
val isolatedNodes = alwaysId +: members.filter(selector).map(m => id(Vertex.toVertex(m)))
441+
val isolatedNodes = alwaysId +: members.filter(selector).map(m => id(Vertex.toDefVertex(m)))
441442

442443
val vertices = Array.ofDim[Vertex](N)
443444
for ((vertex, idx) <- vertexToId) { vertices(idx) = vertex }
@@ -457,22 +458,49 @@ object ViperChopper {
457458
/** Abstract the smallest parts of a Viper program and provides necessary information to compute merge penalties. */
458459
sealed trait Vertex
459460
object Vertex {
460-
case class Method(methodName: String) extends Vertex
461+
case class Method private[Vertex] (methodName: String) extends Vertex
461462
case class MethodSpec(methodName: String) extends Vertex
462463
case class Function(functionName: String) extends Vertex
463464
case class PredicateSig(predicateName: String) extends Vertex
464-
case class PredicateBody(predicateName: String) extends Vertex
465+
case class PredicateBody private[Vertex] (predicateName: String) extends Vertex
465466
case class Field(fieldName: String) extends Vertex
466467
case class DomainFunction(funcName: String) extends Vertex
467468
case class DomainAxiom(v: vpr.DomainAxiom, d: vpr.Domain) extends Vertex
468469
case class DomainType(v: vpr.DomainType) extends Vertex
469470
case object Always extends Vertex // if something always has to be included, then it is a dependency of Always
470471

471-
def toVertex(m: vpr.Member): Vertex = {
472+
// the creation of the following vertices has special cases and should not happen outside of the Vertex object
473+
object Method { private[Vertex] def apply(methodName: String): Method = new Method(methodName) }
474+
object PredicateBody { private[Vertex] def apply(predicateName: String): PredicateBody = new PredicateBody(predicateName) }
475+
/** This function is only allowed to be called in the following cases:
476+
* 1) applying [[toDefVertex]] to the predicate referenced by `predicateName` returns a [[Vertex.PredicateBody]] instance.
477+
* 2) The result is used as the target of a dependency.
478+
* */
479+
def predicateBody_check_that_call_is_ok(predicateName: String): PredicateBody = Vertex.PredicateBody(predicateName)
480+
481+
def toDefVertex(m: vpr.Member): Vertex = {
482+
483+
m match {
484+
case m: vpr.Method => m.body match {
485+
case Some(_) => Vertex.Method(m.name)
486+
case None => Vertex.MethodSpec(m.name)
487+
}
488+
case m: vpr.Predicate => m.body match {
489+
case Some(_) => Vertex.PredicateBody(m.name)
490+
case None => Vertex.PredicateSig(m.name)
491+
}
492+
case m: vpr.Function => Vertex.Function(m.name)
493+
case m: vpr.Field => Vertex.Field(m.name)
494+
case m: vpr.Domain => Vertex.DomainType(vpr.DomainType(domain = m, (m.typVars zip m.typVars).toMap))
495+
case _: vpr.ExtensionMember => ???
496+
}
497+
}
498+
499+
def toUseVertex(m: vpr.Member): Vertex = {
472500
m match {
473-
case m: vpr.Method => Vertex.Method(m.name)
501+
case m: vpr.Method => Vertex.MethodSpec(m.name)
474502
case m: vpr.Function => Vertex.Function(m.name)
475-
case m: vpr.Predicate => Vertex.PredicateBody(m.name)
503+
case m: vpr.Predicate => Vertex.PredicateSig(m.name)
476504
case m: vpr.Field => Vertex.Field(m.name)
477505
case m: vpr.Domain => Vertex.DomainType(vpr.DomainType(domain = m, (m.typVars zip m.typVars).toMap))
478506
case _: vpr.ExtensionMember => ???
@@ -535,33 +563,20 @@ object ViperChopper {
535563
* The edges are sorted at a later point, after the translation to int nodes (where it is cheaper).
536564
* */
537565
def dependencies(member: vpr.Member): Seq[Edge[Vertex]] = {
566+
val defVertex = Vertex.toDefVertex(member)
567+
val useVertex = Vertex.toUseVertex(member)
568+
538569
member match {
539570
case m: vpr.Method =>
540-
{
541-
val from = Vertex.Method(m.name)
542-
usages(m).map(from -> _)
543-
} ++ {
544-
val from = Vertex.MethodSpec(m.name)
545-
(m.pres ++ m.posts ++ m.formalArgs ++ m.formalReturns).flatMap(exp => usages(exp).map(from -> _))
546-
}
547-
548-
case f: vpr.Function =>
549-
val from = Vertex.Function(f.name)
550-
usages(f).map(from -> _)
571+
dependenciesToChildren(member, defVertex) ++
572+
(m.pres ++ m.posts ++ m.formalArgs ++ m.formalReturns).flatMap(dependenciesToChildren(_, useVertex))
551573

552574
case p: vpr.Predicate =>
553-
{
554-
val from = Vertex.PredicateSig(p.name)
555-
p.formalArgs.flatMap(exp => usages(exp).map(from -> _))
556-
} ++ {
557-
val from = Vertex.PredicateBody(p.name)
558-
usages(p).map(from -> _)
559-
} ++ { Seq(Vertex.PredicateBody(p.name) -> Vertex.PredicateSig(p.name)) }
560-
575+
dependenciesToChildren(member, defVertex) ++
576+
p.formalArgs.flatMap(dependenciesToChildren(_, useVertex)) ++
577+
Seq(defVertex -> useVertex)
561578

562-
case f: vpr.Field =>
563-
val from = Vertex.Field(f.name)
564-
usages(f).map(from -> _)
579+
case _: vpr.Function | _: vpr.Field => dependenciesToChildren(member, defVertex)
565580

566581
case d: vpr.Domain =>
567582
d.axioms.flatMap { ax =>
@@ -573,21 +588,24 @@ object ViperChopper {
573588
* as a conservative choice. We use that dependencies of `Always` are always included.
574589
*/
575590
val mid = Vertex.DomainAxiom(ax, d)
576-
val tos = usages(ax.exp)
591+
val tos = usages(ax.exp) // `tos` can be used as source because axioms do not contain un-/foldings.
577592
val froms = tos
578593
val finalFroms = if (froms.nonEmpty) froms else Vector(Vertex.Always)
579594
finalFroms.map(_ -> mid) ++ tos.map(mid -> _)
580-
} ++ d.functions.flatMap { f =>
581-
val from = Vertex.DomainFunction(f.name)
582-
usages(f).map(from -> _)
583-
}
595+
} ++ d.functions.flatMap { f => dependenciesToChildren(f, Vertex.DomainFunction(f.name)) }
584596

585597
case _ => Vector.empty
586598
}
587599
}
588600

601+
/** Returns edges from `nodeVertex` to all children of `node` that are usages. */
602+
def dependenciesToChildren(node: vpr.Node, nodeVertex: Vertex): Seq[Edge[Vertex]] = {
603+
usages(node) map (nodeVertex -> _)
604+
}
605+
589606
/**
590607
* Returns all entities referenced in the subtree of node `n`.
608+
* May only be used as the target of a dependency.
591609
* The result is an unsorted sequence of vertices.
592610
* The vertices are never sorted, and duplicates are fine.
593611
* Note that they are sorted indirectly when the edges are sorted.
@@ -604,9 +622,10 @@ object ViperChopper {
604622
case n: vpr.FuncApp => Seq(Vertex.Function(n.funcname))
605623
case n: vpr.DomainFuncApp => Seq(Vertex.DomainFunction(n.funcname))
606624
case n: vpr.PredicateAccess => Seq(Vertex.PredicateSig(n.predicateName))
607-
case n: vpr.Unfold => Seq(Vertex.PredicateBody(n.acc.loc.predicateName))
608-
case n: vpr.Fold => Seq(Vertex.PredicateBody(n.acc.loc.predicateName))
609-
case n: vpr.Unfolding => Seq(Vertex.PredicateBody(n.acc.loc.predicateName))
625+
// The call is fine because the result is used as the target of a dependency.
626+
case n: vpr.Unfold => Seq(Vertex.predicateBody_check_that_call_is_ok(n.acc.loc.predicateName))
627+
case n: vpr.Fold => Seq(Vertex.predicateBody_check_that_call_is_ok(n.acc.loc.predicateName))
628+
case n: vpr.Unfolding => Seq(Vertex.predicateBody_check_that_call_is_ok(n.acc.loc.predicateName))
610629
case n: vpr.FieldAccess => Seq(Vertex.Field(n.field.name))
611630
case n: vpr.Type => deepType(n).collect{ case t: vpr.DomainType => Vertex.DomainType(t) }
612631
}.flatten

0 commit comments

Comments
 (0)