mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 15:21:48 +03:00
Emit value updates only on change (#1051)
This commit is contained in:
parent
359a768d2b
commit
ef165e4f23
@ -75,7 +75,6 @@ class ContextEventsListenerSpec
|
||||
Api.ExpressionValueUpdate(
|
||||
Suggestions.method.externalId.get,
|
||||
None,
|
||||
None,
|
||||
None
|
||||
)
|
||||
)
|
||||
@ -117,7 +116,6 @@ class ContextEventsListenerSpec
|
||||
Api.ExpressionValueUpdate(
|
||||
Suggestions.method.externalId.get,
|
||||
None,
|
||||
None,
|
||||
None
|
||||
)
|
||||
)
|
||||
@ -129,7 +127,6 @@ class ContextEventsListenerSpec
|
||||
Api.ExpressionValueUpdate(
|
||||
Suggestions.local.externalId.get,
|
||||
None,
|
||||
None,
|
||||
None
|
||||
)
|
||||
)
|
||||
|
@ -240,13 +240,11 @@ object Runtime {
|
||||
*
|
||||
* @param expressionId expression id.
|
||||
* @param expressionType the type of expression.
|
||||
* @param shortValue the value of expression.
|
||||
* @param methodCall the pointer to a method definition.
|
||||
*/
|
||||
case class ExpressionValueUpdate(
|
||||
expressionId: ExpressionId,
|
||||
expressionType: Option[String],
|
||||
shortValue: Option[String],
|
||||
methodCall: Option[MethodPointer]
|
||||
)
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.enso.interpreter.instrument;
|
||||
|
||||
import com.oracle.truffle.api.CallTarget;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.Truffle;
|
||||
import com.oracle.truffle.api.frame.FrameInstance;
|
||||
import com.oracle.truffle.api.frame.FrameInstanceVisitor;
|
||||
@ -19,7 +18,7 @@ import org.enso.pkg.QualifiedName;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -73,24 +72,46 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
/** A class for notifications about identified expressions' values being computed. */
|
||||
public static class ExpressionValue {
|
||||
private final UUID expressionId;
|
||||
private final String type;
|
||||
private final Object value;
|
||||
private final String type;
|
||||
private final String cachedType;
|
||||
private final FunctionCallInfo callInfo;
|
||||
private final FunctionCallInfo cachedCallInfo;
|
||||
|
||||
/**
|
||||
* Creates a new instance of this class.
|
||||
*
|
||||
* @param expressionId the id of the expression being computed.
|
||||
* @param type of the computed expression.
|
||||
* @param value the value returned by computing the expression.
|
||||
* @param type the type of the returned value.
|
||||
* @param cachedType the cached type of the value.
|
||||
* @param callInfo the function call data.
|
||||
*/
|
||||
public ExpressionValue(
|
||||
UUID expressionId, String type, Object value, FunctionCallInfo callInfo) {
|
||||
UUID expressionId,
|
||||
Object value,
|
||||
String type,
|
||||
String cachedType,
|
||||
FunctionCallInfo callInfo,
|
||||
FunctionCallInfo cachedCallInfo) {
|
||||
this.expressionId = expressionId;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
this.cachedType = cachedType;
|
||||
this.callInfo = callInfo;
|
||||
this.cachedCallInfo = cachedCallInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ExpressionValue{" +
|
||||
"expressionId=" + expressionId +
|
||||
", value=" + value +
|
||||
", type='" + type + '\'' +
|
||||
", cachedType='" + cachedType + '\'' +
|
||||
", callInfo=" + callInfo +
|
||||
", cachedCallInfo=" + cachedCallInfo +
|
||||
'}';
|
||||
}
|
||||
|
||||
/** @return the id of the expression computed. */
|
||||
@ -98,10 +119,14 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
return expressionId;
|
||||
}
|
||||
|
||||
/** @return the computed type of the expression. */
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public Optional<String> getType() {
|
||||
return Optional.ofNullable(type);
|
||||
/** @return the type of the returned value. */
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @return the cached type of the value. */
|
||||
public String getCachedType() {
|
||||
return cachedType;
|
||||
}
|
||||
|
||||
/** @return the computed value of the expression. */
|
||||
@ -113,6 +138,11 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
public FunctionCallInfo getCallInfo() {
|
||||
return callInfo;
|
||||
}
|
||||
|
||||
/** @return the function call data previously associated with the expression. */
|
||||
public FunctionCallInfo getCachedCallInfo() {
|
||||
return cachedCallInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/** Information about the function call. */
|
||||
@ -145,6 +175,30 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
FunctionCallInfo that = (FunctionCallInfo) o;
|
||||
return Objects.equals(moduleName, that.moduleName) &&
|
||||
Objects.equals(typeName, that.typeName) &&
|
||||
functionName.equals(that.functionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(moduleName, typeName, functionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return moduleName + "::" + typeName + "::" + functionName;
|
||||
}
|
||||
|
||||
/** @return the name of the module this function was defined in, or null if not available. */
|
||||
public QualifiedName getModuleName() {
|
||||
return moduleName;
|
||||
@ -165,8 +219,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
private static class IdExecutionEventListener implements ExecutionEventListener {
|
||||
private final CallTarget entryCallTarget;
|
||||
private final Consumer<ExpressionCall> functionCallCallback;
|
||||
private final Consumer<ExpressionValue> valueCallback;
|
||||
private final Consumer<ExpressionValue> visualisationCallback;
|
||||
private final Consumer<ExpressionValue> onComputedCallback;
|
||||
private final Consumer<ExpressionValue> onCachedCallback;
|
||||
private final RuntimeCache cache;
|
||||
private final UUID nextExecutionItem;
|
||||
private final Map<UUID, FunctionCallInfo> calls = new HashMap<>();
|
||||
@ -178,22 +232,22 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
* @param cache the precomputed expression values.
|
||||
* @param nextExecutionItem the next item scheduled for execution.
|
||||
* @param functionCallCallback the consumer of function call events.
|
||||
* @param valueCallback the consumer of the node value events.
|
||||
* @param visualisationCallback the consumer of the node visualisation events.
|
||||
* @param onComputedCallback the consumer of the computed value events.
|
||||
* @param onCachedCallback the consumer of the cached value events.
|
||||
*/
|
||||
public IdExecutionEventListener(
|
||||
CallTarget entryCallTarget,
|
||||
RuntimeCache cache,
|
||||
UUID nextExecutionItem,
|
||||
Consumer<ExpressionCall> functionCallCallback,
|
||||
Consumer<ExpressionValue> valueCallback,
|
||||
Consumer<ExpressionValue> visualisationCallback) {
|
||||
Consumer<ExpressionValue> onComputedCallback,
|
||||
Consumer<ExpressionValue> onCachedCallback) {
|
||||
this.entryCallTarget = entryCallTarget;
|
||||
this.cache = cache;
|
||||
this.nextExecutionItem = nextExecutionItem;
|
||||
this.functionCallCallback = functionCallCallback;
|
||||
this.valueCallback = valueCallback;
|
||||
this.visualisationCallback = visualisationCallback;
|
||||
this.onComputedCallback = onComputedCallback;
|
||||
this.onCachedCallback = onCachedCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -221,9 +275,14 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
// item in the `functionCallCallback`. We allow to execute the cached `stackTop` value to be
|
||||
// able to continue the stack execution, and unwind later from the `onReturnValue` callback.
|
||||
if (result != null && !nodeId.equals(nextExecutionItem)) {
|
||||
visualisationCallback.accept(
|
||||
onCachedCallback.accept(
|
||||
new ExpressionValue(
|
||||
nodeId, Types.getName(result).orElse(null), result, calls.get(nodeId)));
|
||||
nodeId,
|
||||
result,
|
||||
cache.getType(nodeId),
|
||||
Types.getName(result),
|
||||
calls.get(nodeId),
|
||||
cache.getCall(nodeId)));
|
||||
throw context.createUnwind(result);
|
||||
}
|
||||
}
|
||||
@ -257,10 +316,13 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
}
|
||||
} else if (node instanceof ExpressionNode) {
|
||||
UUID nodeId = ((ExpressionNode) node).getId();
|
||||
String resultType = Types.getName(result);
|
||||
cache.offer(nodeId, result);
|
||||
valueCallback.accept(
|
||||
new ExpressionValue(
|
||||
nodeId, Types.getName(result).orElse(null), result, calls.get(nodeId)));
|
||||
String cachedType = cache.putType(nodeId, resultType);
|
||||
FunctionCallInfo call = calls.get(nodeId);
|
||||
FunctionCallInfo cachedCall = cache.putCall(nodeId, call);
|
||||
onComputedCallback.accept(
|
||||
new ExpressionValue(nodeId, result, resultType, cachedType, call, cachedCall));
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,8 +369,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
* @param funSourceLength the length of the observed source range.
|
||||
* @param cache the precomputed expression values.
|
||||
* @param nextExecutionItem the next item scheduled for execution.
|
||||
* @param valueCallback the consumer of the node value events.
|
||||
* @param visualisationCallback the consumer of the node visualisation events.
|
||||
* @param onComputedCallback the consumer of the computed value events.
|
||||
* @param onCachedCallback the consumer of the cached value events.
|
||||
* @param functionCallCallback the consumer of function call events.
|
||||
* @return a reference to the attached event listener.
|
||||
*/
|
||||
@ -318,8 +380,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
int funSourceLength,
|
||||
RuntimeCache cache,
|
||||
UUID nextExecutionItem,
|
||||
Consumer<ExpressionValue> valueCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> visualisationCallback,
|
||||
Consumer<ExpressionValue> onComputedCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> onCachedCallback,
|
||||
Consumer<ExpressionCall> functionCallCallback) {
|
||||
SourceSectionFilter filter =
|
||||
SourceSectionFilter.newBuilder()
|
||||
@ -337,8 +399,8 @@ public class IdExecutionInstrument extends TruffleInstrument {
|
||||
cache,
|
||||
nextExecutionItem,
|
||||
functionCallCallback,
|
||||
valueCallback,
|
||||
visualisationCallback));
|
||||
onComputedCallback,
|
||||
onCachedCallback));
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import java.util.UUID;
|
||||
public class RuntimeCache {
|
||||
|
||||
private final Map<UUID, SoftReference<Object>> cache = new HashMap<>();
|
||||
private final Map<UUID, String> types = new HashMap<>();
|
||||
private final Map<UUID, IdExecutionInstrument.FunctionCallInfo> calls = new HashMap<>();
|
||||
private Map<UUID, Double> weights = new HashMap<>();
|
||||
|
||||
/**
|
||||
@ -50,6 +52,52 @@ public class RuntimeCache {
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the type of expression.
|
||||
*
|
||||
* @return the previously cached type.
|
||||
*/
|
||||
public String putType(UUID key, String typeName) {
|
||||
return types.put(key, typeName);
|
||||
}
|
||||
|
||||
/** @return the cached type of the expression */
|
||||
public String getType(UUID key) {
|
||||
return types.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache the function call
|
||||
*
|
||||
* @param key the expression associated with the function call.
|
||||
* @param call the function call.
|
||||
* @return the function call that was previously associated with this expression.
|
||||
*/
|
||||
public IdExecutionInstrument.FunctionCallInfo putCall(
|
||||
UUID key, IdExecutionInstrument.FunctionCallInfo call) {
|
||||
return calls.put(key, call);
|
||||
}
|
||||
|
||||
/** @return the cached function call associated with the expression. */
|
||||
public IdExecutionInstrument.FunctionCallInfo getCall(UUID key) {
|
||||
return calls.get(key);
|
||||
}
|
||||
|
||||
/** Clear the cached calls. */
|
||||
public void clearCalls() {
|
||||
calls.clear();
|
||||
}
|
||||
|
||||
/** Remove the type associated with the provided key. */
|
||||
public void removeType(UUID key) {
|
||||
types.remove(key);
|
||||
}
|
||||
|
||||
/** Clear the cached types. */
|
||||
public void clearTypes() {
|
||||
types.clear();
|
||||
}
|
||||
|
||||
/** @return the weights of this cache. */
|
||||
public Map<UUID, Double> getWeights() {
|
||||
return weights;
|
||||
|
@ -101,23 +101,27 @@ public class Types {
|
||||
* @param value an object of interest.
|
||||
* @return the string representation of object's type.
|
||||
*/
|
||||
public static Optional<String> getName(Object value) {
|
||||
if (TypesGen.isLong(value)) {
|
||||
return Optional.of("Number");
|
||||
public static String getName(Object value) {
|
||||
if (TypesGen.isLong(value) || TypesGen.isImplicitLong(value)) {
|
||||
return "Number";
|
||||
} else if (TypesGen.isBoolean(value)) {
|
||||
return "Boolean";
|
||||
} else if (TypesGen.isString(value)) {
|
||||
return Optional.of("Text");
|
||||
return "Text";
|
||||
} else if (TypesGen.isFunction(value)) {
|
||||
return Optional.of("Function");
|
||||
return "Function";
|
||||
} else if (TypesGen.isAtom(value)) {
|
||||
return Optional.of(TypesGen.asAtom(value).getConstructor().getName());
|
||||
return TypesGen.asAtom(value).getConstructor().getName();
|
||||
} else if (TypesGen.isAtomConstructor(value)) {
|
||||
return Optional.of(TypesGen.asAtomConstructor(value).getName());
|
||||
return TypesGen.asAtomConstructor(value).getName();
|
||||
} else if (TypesGen.isThunk(value)) {
|
||||
return Optional.of("Thunk");
|
||||
return "Thunk";
|
||||
} else if (TypesGen.isRuntimeError(value)) {
|
||||
return Optional.of("Error " + TypesGen.asRuntimeError(value).getPayload().toString());
|
||||
return "Error " + TypesGen.asRuntimeError(value).getPayload().toString();
|
||||
} else if (TypesGen.isVector(value)) {
|
||||
return "Vector";
|
||||
} else {
|
||||
return Optional.empty();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,16 +84,16 @@ public class ExecutionService {
|
||||
* @param call the call metadata.
|
||||
* @param cache the precomputed expression values.
|
||||
* @param nextExecutionItem the next item scheduled for execution.
|
||||
* @param valueCallback the consumer for expression value events.
|
||||
* @param visualisationCallback the consumer of the node visualisation events.
|
||||
* @param onComputedCallback the consumer of the computed value events.
|
||||
* @param onCachedCallback the consumer of the cached value events.
|
||||
* @param funCallCallback the consumer for function call events.
|
||||
*/
|
||||
public void execute(
|
||||
FunctionCallInstrumentationNode.FunctionCall call,
|
||||
RuntimeCache cache,
|
||||
UUID nextExecutionItem,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> valueCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> visualisationCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> onComputedCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> onCachedCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionCall> funCallCallback)
|
||||
throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
|
||||
|
||||
@ -108,8 +108,8 @@ public class ExecutionService {
|
||||
src.getCharLength(),
|
||||
cache,
|
||||
nextExecutionItem,
|
||||
valueCallback,
|
||||
visualisationCallback,
|
||||
onComputedCallback,
|
||||
onCachedCallback,
|
||||
funCallCallback);
|
||||
interopLibrary.execute(call);
|
||||
listener.dispose();
|
||||
@ -124,8 +124,8 @@ public class ExecutionService {
|
||||
* @param methodName the method name.
|
||||
* @param cache the precomputed expression values.
|
||||
* @param nextExecutionItem the next item scheduled for execution.
|
||||
* @param valueCallback the consumer for expression value events.
|
||||
* @param visualisationCallback the consumer of the node visualisation events.
|
||||
* @param onComputedCallback the consumer of the computed value events.
|
||||
* @param onCachedCallback the consumer of the cached value events.
|
||||
* @param funCallCallback the consumer for function call events.
|
||||
*/
|
||||
public void execute(
|
||||
@ -134,8 +134,8 @@ public class ExecutionService {
|
||||
String methodName,
|
||||
RuntimeCache cache,
|
||||
UUID nextExecutionItem,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> valueCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> visualisationCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> onComputedCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionValue> onCachedCallback,
|
||||
Consumer<IdExecutionInstrument.ExpressionCall> funCallCallback)
|
||||
throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
|
||||
Optional<FunctionCallInstrumentationNode.FunctionCall> callMay =
|
||||
@ -149,8 +149,8 @@ public class ExecutionService {
|
||||
callMay.get(),
|
||||
cache,
|
||||
nextExecutionItem,
|
||||
valueCallback,
|
||||
visualisationCallback,
|
||||
onComputedCallback,
|
||||
onCachedCallback,
|
||||
funCallCallback);
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,12 @@ final class Changeset[A: TextEditor: IndexedSource](val source: A, val ir: IR) {
|
||||
DataflowAnalysis,
|
||||
"Empty dataflow analysis metadata during changeset calculation."
|
||||
)
|
||||
invalidated(edits)
|
||||
val direct = invalidated(edits)
|
||||
val transitive = direct
|
||||
.map(Changeset.toDataflowDependencyType)
|
||||
.flatMap(metadata.getExternal)
|
||||
.flatten
|
||||
direct.flatMap(_.externalId) ++ transitive
|
||||
}
|
||||
|
||||
/** Traverses the IR and returns a list of the most specific (the innermost)
|
||||
|
@ -31,6 +31,15 @@ object CacheInvalidation {
|
||||
|
||||
/** Invalidate value from indexes. */
|
||||
case object All extends IndexSelector
|
||||
|
||||
/** Invalidate the types index. */
|
||||
case object Types extends IndexSelector
|
||||
|
||||
/** Invalidate the calls index. */
|
||||
case object Calls extends IndexSelector
|
||||
|
||||
/** Invalidate the weights index. */
|
||||
case object Weights extends IndexSelector
|
||||
}
|
||||
|
||||
/** Base trait for cache invalidation commands. Commands describe how the
|
||||
@ -89,10 +98,13 @@ object CacheInvalidation {
|
||||
/** Create an invalidation instruction using a stack selector and an
|
||||
* invalidation command.
|
||||
*
|
||||
* @param elements the stack elements selector.
|
||||
* @param command the invalidation command.
|
||||
* @param elements the stack elements selector
|
||||
* @param command the invalidation command
|
||||
*/
|
||||
def apply(elements: StackSelector, command: Command): CacheInvalidation =
|
||||
def apply(
|
||||
elements: StackSelector,
|
||||
command: Command
|
||||
): CacheInvalidation =
|
||||
new CacheInvalidation(elements, command, Set())
|
||||
|
||||
/** Run a sequence of invalidation instructions on an execution stack.
|
||||
@ -150,19 +162,38 @@ object CacheInvalidation {
|
||||
command match {
|
||||
case Command.InvalidateAll =>
|
||||
cache.clear()
|
||||
if (indexes.contains(IndexSelector.All)) cache.clearWeights()
|
||||
indexes.foreach(clearIndex(_, cache))
|
||||
case Command.InvalidateKeys(keys) =>
|
||||
keys.foreach { key =>
|
||||
cache.remove(key)
|
||||
if (indexes.contains(IndexSelector.All)) cache.removeWeight(key)
|
||||
indexes.foreach(clearIndex(_, cache))
|
||||
}
|
||||
case Command.InvalidateStale(scope) =>
|
||||
val staleKeys = cache.getKeys.asScala.diff(scope.toSet)
|
||||
staleKeys.foreach { key =>
|
||||
cache.remove(key)
|
||||
if (indexes.contains(IndexSelector.All)) cache.removeWeight(key)
|
||||
indexes.foreach(clearIndex(_, cache))
|
||||
}
|
||||
case Command.SetMetadata(metadata) =>
|
||||
cache.setWeights(metadata.asJavaWeights)
|
||||
}
|
||||
|
||||
/** Clear the selected index.
|
||||
*
|
||||
* @param selector the selected index
|
||||
* @param cache the cache to invalidate
|
||||
*/
|
||||
private def clearIndex(selector: IndexSelector, cache: RuntimeCache): Unit =
|
||||
selector match {
|
||||
case IndexSelector.All =>
|
||||
cache.clearTypes()
|
||||
cache.clearWeights()
|
||||
cache.clearCalls()
|
||||
case IndexSelector.Weights =>
|
||||
cache.clearWeights()
|
||||
case IndexSelector.Types =>
|
||||
cache.clearTypes()
|
||||
case IndexSelector.Calls =>
|
||||
cache.clearCalls()
|
||||
}
|
||||
}
|
||||
|
@ -155,10 +155,15 @@ class EnsureCompiledJob(protected val files: List[File])
|
||||
.map(_._2)
|
||||
val invalidateStaleCommand =
|
||||
CacheInvalidation.Command.InvalidateStale(scopeIds)
|
||||
Seq(invalidateExpressionsCommand, invalidateStaleCommand).map(
|
||||
Seq(
|
||||
CacheInvalidation(
|
||||
CacheInvalidation.StackSelector.All,
|
||||
_,
|
||||
invalidateExpressionsCommand,
|
||||
Set(CacheInvalidation.IndexSelector.Weights)
|
||||
),
|
||||
CacheInvalidation(
|
||||
CacheInvalidation.StackSelector.All,
|
||||
invalidateStaleCommand,
|
||||
Set(CacheInvalidation.IndexSelector.All)
|
||||
)
|
||||
)
|
||||
@ -173,7 +178,7 @@ class EnsureCompiledJob(protected val files: List[File])
|
||||
private def runInvalidationCommands(
|
||||
invalidationCommands: Iterable[CacheInvalidation]
|
||||
)(implicit ctx: RuntimeContext): Unit = {
|
||||
ctx.contextManager.getAll.valuesIterator
|
||||
ctx.contextManager.getAll.values
|
||||
.collect {
|
||||
case stack if stack.nonEmpty =>
|
||||
CacheInvalidation.runAll(stack, invalidationCommands)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package org.enso.interpreter.instrument.job
|
||||
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import java.util.{Objects, UUID}
|
||||
import java.util.function.Consumer
|
||||
import java.util.logging.Level
|
||||
|
||||
@ -38,19 +38,19 @@ trait ProgramExecutionSupport {
|
||||
*
|
||||
* @param executionFrame an execution frame
|
||||
* @param callStack a call stack
|
||||
* @param valueCallback a listener of computed values
|
||||
* @param visualisationCallback a listener of fired visualisations
|
||||
* @param onComputedCallback a listener of computed values
|
||||
* @param onCachedCallback a listener of cached values
|
||||
*/
|
||||
@scala.annotation.tailrec
|
||||
final private def runProgram(
|
||||
executionFrame: ExecutionFrame,
|
||||
callStack: List[LocalCallFrame],
|
||||
valueCallback: Consumer[ExpressionValue],
|
||||
visualisationCallback: Consumer[ExpressionValue]
|
||||
onComputedCallback: Consumer[ExpressionValue],
|
||||
onCachedCallback: Consumer[ExpressionValue]
|
||||
)(implicit ctx: RuntimeContext): Unit = {
|
||||
var enterables: Map[UUID, FunctionCall] = Map()
|
||||
val valsCallback: Consumer[ExpressionValue] =
|
||||
if (callStack.isEmpty) valueCallback else _ => ()
|
||||
val computedCallback: Consumer[ExpressionValue] =
|
||||
if (callStack.isEmpty) onComputedCallback else _ => ()
|
||||
val callablesCallback: Consumer[ExpressionCall] = fun =>
|
||||
if (callStack.headOption.exists(_.expressionId == fun.getExpressionId)) {
|
||||
enterables += fun.getExpressionId -> fun.getCall
|
||||
@ -63,8 +63,8 @@ trait ProgramExecutionSupport {
|
||||
function,
|
||||
cache,
|
||||
callStack.headOption.map(_.expressionId).orNull,
|
||||
valsCallback,
|
||||
visualisationCallback,
|
||||
computedCallback,
|
||||
onCachedCallback,
|
||||
callablesCallback
|
||||
)
|
||||
case ExecutionFrame(ExecutionItem.CallData(callData), cache) =>
|
||||
@ -72,8 +72,8 @@ trait ProgramExecutionSupport {
|
||||
callData,
|
||||
cache,
|
||||
callStack.headOption.map(_.expressionId).orNull,
|
||||
valsCallback,
|
||||
visualisationCallback,
|
||||
computedCallback,
|
||||
onCachedCallback,
|
||||
callablesCallback
|
||||
)
|
||||
}
|
||||
@ -86,8 +86,8 @@ trait ProgramExecutionSupport {
|
||||
runProgram(
|
||||
ExecutionFrame(ExecutionItem.CallData(call), item.cache),
|
||||
tail,
|
||||
valueCallback,
|
||||
visualisationCallback
|
||||
onComputedCallback,
|
||||
onCachedCallback
|
||||
)
|
||||
case None =>
|
||||
()
|
||||
@ -129,67 +129,66 @@ trait ProgramExecutionSupport {
|
||||
case ExecutionItem.CallData(call) => call.getFunction.getName
|
||||
}
|
||||
|
||||
val visualisationUpdateCallback: Consumer[ExpressionValue] = { value =>
|
||||
if (updatedVisualisations.contains(value.getExpressionId))
|
||||
onVisualisationUpdate(contextId, value)
|
||||
val onCachedValueCallback: Consumer[ExpressionValue] = { value =>
|
||||
if (updatedVisualisations.contains(value.getExpressionId)) {
|
||||
ctx.executionService.getLogger.finer(s"ON_CACHED $value")
|
||||
fireVisualisationUpdates(contextId, value)
|
||||
}
|
||||
}
|
||||
|
||||
val onComputedValueCallback: Consumer[ExpressionValue] = { value =>
|
||||
ctx.executionService.getLogger.finer(s"ON_COMPUTED $value")
|
||||
sendValueUpdate(contextId, value)
|
||||
fireVisualisationUpdates(contextId, value)
|
||||
}
|
||||
|
||||
val (explicitCallOpt, localCalls) = unwind(stack, Nil, Nil)
|
||||
for {
|
||||
stackItem <- Either.fromOption(explicitCallOpt, "stack is empty")
|
||||
_ <- Either
|
||||
.catchNonFatal(
|
||||
runProgram(
|
||||
stackItem,
|
||||
localCalls,
|
||||
onExpressionValueComputed(contextId, _),
|
||||
visualisationUpdateCallback
|
||||
_ <-
|
||||
Either
|
||||
.catchNonFatal(
|
||||
runProgram(
|
||||
stackItem,
|
||||
localCalls,
|
||||
onComputedValueCallback,
|
||||
onCachedValueCallback
|
||||
)
|
||||
)
|
||||
)
|
||||
.leftMap { ex =>
|
||||
ctx.executionService.getLogger.log(
|
||||
Level.FINE,
|
||||
s"Error executing a function '${getName(stackItem.item)}'",
|
||||
ex
|
||||
)
|
||||
s"error in function: ${getName(stackItem.item)}"
|
||||
}
|
||||
.leftMap { ex =>
|
||||
ctx.executionService.getLogger.log(
|
||||
Level.FINE,
|
||||
s"Error executing a function '${getName(stackItem.item)}'",
|
||||
ex
|
||||
)
|
||||
s"error in function: ${getName(stackItem.item)}"
|
||||
}
|
||||
} yield ()
|
||||
}
|
||||
|
||||
private def onVisualisationUpdate(
|
||||
contextId: Api.ContextId,
|
||||
value: ExpressionValue
|
||||
)(implicit ctx: RuntimeContext): Unit =
|
||||
fireVisualisationUpdates(contextId, value)
|
||||
|
||||
private def onExpressionValueComputed(
|
||||
contextId: Api.ContextId,
|
||||
value: ExpressionValue
|
||||
)(implicit ctx: RuntimeContext): Unit = {
|
||||
sendValueUpdate(contextId, value)
|
||||
fireVisualisationUpdates(contextId, value)
|
||||
}
|
||||
|
||||
private def sendValueUpdate(
|
||||
contextId: ContextId,
|
||||
value: ExpressionValue
|
||||
)(implicit ctx: RuntimeContext): Unit = {
|
||||
ctx.endpoint.sendToClient(
|
||||
Api.Response(
|
||||
Api.ExpressionValuesComputed(
|
||||
contextId,
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(
|
||||
value.getExpressionId,
|
||||
OptionConverters.toScala(value.getType),
|
||||
Some(value.getValue.toString),
|
||||
toMethodPointer(value)
|
||||
if (
|
||||
!Objects.equals(value.getType, value.getCachedType) ||
|
||||
!Objects.equals(value.getCallInfo, value.getCachedCallInfo)
|
||||
) {
|
||||
ctx.endpoint.sendToClient(
|
||||
Api.Response(
|
||||
Api.ExpressionValuesComputed(
|
||||
contextId,
|
||||
Vector(
|
||||
Api.ExpressionValueUpdate(
|
||||
value.getExpressionId,
|
||||
Some(value.getType),
|
||||
toMethodPointer(value)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def fireVisualisationUpdates(
|
||||
@ -253,10 +252,10 @@ trait ProgramExecutionSupport {
|
||||
value: ExpressionValue
|
||||
)(implicit ctx: RuntimeContext): Option[Api.MethodPointer] =
|
||||
for {
|
||||
call <- Option(value.getCallInfo)
|
||||
moduleName <- Option(call.getModuleName)
|
||||
functionName = call.getFunctionName
|
||||
typeName <- Option(call.getTypeName).map(_.item)
|
||||
call <- Option(value.getCallInfo)
|
||||
moduleName <- Option(call.getModuleName)
|
||||
functionName = call.getFunctionName
|
||||
typeName <- Option(call.getTypeName).map(_.item)
|
||||
module <- OptionConverters.toScala(
|
||||
ctx.executionService.getContext.getTopScope
|
||||
.getModule(moduleName.toString)
|
||||
|
@ -13,7 +13,7 @@ class RuntimeCacheTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
"RutimeCache" should "cache items" in {
|
||||
val cache = new RuntimeCache
|
||||
val key = UUID.randomUUID
|
||||
val key = UUID.randomUUID()
|
||||
val obj = 42
|
||||
|
||||
cache.offer(key, obj) shouldEqual false
|
||||
@ -28,7 +28,7 @@ class RuntimeCacheTest extends AnyFlatSpec with Matchers {
|
||||
|
||||
it should "remove items" in {
|
||||
val cache = new RuntimeCache
|
||||
val key = UUID.randomUUID
|
||||
val key = UUID.randomUUID()
|
||||
val obj = new Object
|
||||
|
||||
cache.setWeights(
|
||||
@ -38,4 +38,16 @@ class RuntimeCacheTest extends AnyFlatSpec with Matchers {
|
||||
cache.remove(key) shouldEqual obj
|
||||
cache.get(key) shouldEqual null
|
||||
}
|
||||
|
||||
it should "cache types" in {
|
||||
val cache = new RuntimeCache
|
||||
val key = UUID.randomUUID()
|
||||
val obj = "Number"
|
||||
|
||||
cache.putType(key, obj) shouldEqual null
|
||||
cache.putType(key, obj) shouldEqual obj
|
||||
|
||||
cache.removeType(key)
|
||||
cache.putType(key, obj) shouldEqual null
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@ class ProjectRenameActionSpec
|
||||
with MockitoSugar
|
||||
with FlakySpec {
|
||||
|
||||
"A project rename action" should "delegate request to the Language Server" in new TestCtx {
|
||||
"A project rename action" should "delegate request to the Language Server" taggedAs Flaky in new TestCtx {
|
||||
//given
|
||||
val probe = TestProbe()
|
||||
fakeServer.withBehaviour {
|
||||
|
Loading…
Reference in New Issue
Block a user