Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions sjsonnet/src/sjsonnet/Val.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,20 @@ import scala.reflect.ClassTag
/**
* [[Lazy]] models lazy evaluation within a Jsonnet program. Lazily evaluated dictionary values,
* array contents, or function parameters are all wrapped in [[Lazy]] and only truly evaluated
* on-demand
* on-demand. [[Val]] also extends [[Lazy]] so that already-evaluated values can be stored directly
* in [[Array[Lazy]]] without wrapper overhead.
*/
abstract class Lazy {
protected var cached: Val = _
def compute(): Val
final def force: Val = {
if (cached == null) cached = compute()
cached
}
trait Lazy {
def force: Val
}

/**
* Thread-safe implementation that discards the compute function after initialization.
*/
final class LazyWithComputeFunc(@volatile private var computeFunc: () => Val) extends Lazy {
def compute(): Val = {
private var cached: Val = _
def force: Val = {
if (cached != null) return cached
val f = computeFunc
if (f != null) { // we won the race to initialize
val result = f()
Expand All @@ -47,8 +45,7 @@ final class LazyWithComputeFunc(@volatile private var computeFunc: () => Val) ex
* array contents are lazy, and the tree can contain functions.
*/
sealed abstract class Val extends Lazy {
cached = this // avoid a megamorphic call to compute() when forcing
final def compute(): Val = this
final def force: Val = this

def pos: Position
def prettyName: String
Expand Down
19 changes: 14 additions & 5 deletions sjsonnet/src/sjsonnet/stdlib/ArrayModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,9 @@ object ArrayModule extends AbstractFunctionModule {
pos: Position): Val.Arr = {
Val.Arr(
pos,
arg.map(v => (() => _func.apply1(v, pos.noOffset)(ev, TailstrictModeDisabled)): Lazy)
arg.map(v =>
new LazyWithComputeFunc(() => _func.apply1(v, pos.noOffset)(ev, TailstrictModeDisabled))
)
)
}

Expand All @@ -184,7 +186,9 @@ object ArrayModule extends AbstractFunctionModule {
while (i < a.length) {
val x = arr(i)
val idx = Val.Num(pos, i)
a(i) = () => func.apply2(idx, x, pos.noOffset)(ev, TailstrictModeDisabled)
a(i) = new LazyWithComputeFunc(() =>
func.apply2(idx, x, pos.noOffset)(ev, TailstrictModeDisabled)
)
i += 1
}
Val.Arr(pos, a)
Expand Down Expand Up @@ -414,7 +418,11 @@ object ArrayModule extends AbstractFunctionModule {
if (!filter_func.apply1(i, pos.noOffset)(ev, TailstrictModeDisabled).asBoolean) {
None
} else {
Some[Lazy](() => map_func.apply1(i, pos.noOffset)(ev, TailstrictModeDisabled))
Some[Lazy](
new LazyWithComputeFunc(() =>
map_func.apply1(i, pos.noOffset)(ev, TailstrictModeDisabled)
)
)
}
}
)
Expand Down Expand Up @@ -451,8 +459,9 @@ object ArrayModule extends AbstractFunctionModule {
var i = 0
while (i < sz) {
val forcedI = i
a(i) =
() => func.apply1(Val.Num(pos, forcedI), pos.noOffset)(ev, TailstrictModeDisabled)
a(i) = new LazyWithComputeFunc(() =>
func.apply1(Val.Num(pos, forcedI), pos.noOffset)(ev, TailstrictModeDisabled)
)
i += 1
}
a
Expand Down
8 changes: 6 additions & 2 deletions sjsonnet/src/sjsonnet/stdlib/ObjectModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ object ObjectModule extends AbstractFunctionModule {
val k = allKeys(i)
val v = new Val.Obj.Member(false, Visibility.Normal, deprecatedSkipAsserts = true) {
def invoke(self: Val.Obj, sup: Val.Obj, fs: FileScope, ev: EvalScope): Val =
func.apply2(Val.Str(pos, k), () => obj.value(k, pos.noOffset)(ev), pos.noOffset)(
func.apply2(
Val.Str(pos, k),
new LazyWithComputeFunc(() => obj.value(k, pos.noOffset)(ev)),
pos.noOffset
)(
ev,
TailstrictModeDisabled
)
Expand Down Expand Up @@ -135,7 +139,7 @@ object ObjectModule extends AbstractFunctionModule {
Val.Arr(
pos,
keys.map { k =>
(() => v1.value(k, pos.noOffset)(ev)): Lazy
new LazyWithComputeFunc(() => v1.value(k, pos.noOffset)(ev))
}
)

Expand Down