aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java')
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java228
1 files changed, 0 insertions, 228 deletions
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java
deleted file mode 100644
index fd1b48d8..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/rete/RefineryReteRecipeCompiler.java
+++ /dev/null
@@ -1,228 +0,0 @@
1/*******************************************************************************
2 * Copyright (c) 2010-2014, Bergmann Gabor, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v. 2.0 which is available at
6 * http://www.eclipse.org/legal/epl-v20.html.
7 * SPDX-License-Identifier: EPL-2.0
8 *******************************************************************************/
9package tools.refinery.store.query.viatra.internal.rete;
10
11import org.apache.log4j.Logger;
12import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendHintProvider;
13import org.eclipse.viatra.query.runtime.matchers.context.IQueryCacheContext;
14import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext;
15import org.eclipse.viatra.query.runtime.matchers.planning.IQueryPlannerStrategy;
16import org.eclipse.viatra.query.runtime.matchers.planning.SubPlan;
17import org.eclipse.viatra.query.runtime.matchers.planning.operations.PApply;
18import org.eclipse.viatra.query.runtime.matchers.planning.operations.PEnumerate;
19import org.eclipse.viatra.query.runtime.matchers.psystem.EnumerablePConstraint;
20import org.eclipse.viatra.query.runtime.matchers.psystem.analysis.QueryAnalyzer;
21import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery;
22import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.PDisjunctionRewriterCacher;
23import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
24import org.eclipse.viatra.query.runtime.rete.construction.plancompiler.CompilerHelper;
25import org.eclipse.viatra.query.runtime.rete.construction.plancompiler.ReteRecipeCompiler;
26import org.eclipse.viatra.query.runtime.rete.matcher.TimelyConfiguration;
27import org.eclipse.viatra.query.runtime.rete.recipes.ReteNodeRecipe;
28import org.eclipse.viatra.query.runtime.rete.traceability.CompiledSubPlan;
29import org.eclipse.viatra.query.runtime.rete.traceability.PlanningTrace;
30import org.eclipse.viatra.query.runtime.rete.util.ReteHintOptions;
31import org.jetbrains.annotations.Nullable;
32import tools.refinery.store.query.viatra.internal.pquery.RepresentativeElectionConstraint;
33import tools.refinery.store.query.viatra.internal.rete.recipe.RefineryRecipesFactory;
34import tools.refinery.store.query.viatra.internal.pquery.rewriter.RefineryPBodyNormalizer;
35import tools.refinery.store.query.viatra.internal.pquery.rewriter.RefinerySurrogateQueryRewriter;
36
37import java.lang.invoke.MethodHandle;
38import java.lang.invoke.MethodHandles;
39import java.lang.invoke.MethodType;
40import java.lang.reflect.Field;
41import java.util.Map;
42
43// Since we don't modify VIATRA code, this is our last resort.
44@SuppressWarnings("squid:S3011")
45public class RefineryReteRecipeCompiler extends ReteRecipeCompiler {
46 private static final MethodHandle GET_SUB_PLAN_COMPILER_CACHE;
47 private static final MethodHandle GET_COMPILER_BACK_TRACE;
48 private static final Field NORMALIZER_FIELD;
49 private static final MethodHandle DO_COMPILE_DISPATCH;
50 private static final MethodHandle COMPILE_TO_NATURAL_JOIN;
51 private static final MethodHandle REFER_QUERY;
52
53 static {
54 MethodHandles.Lookup lookup;
55 try {
56 lookup = MethodHandles.privateLookupIn(ReteRecipeCompiler.class, MethodHandles.lookup());
57 } catch (IllegalAccessException e) {
58 throw new IllegalStateException("Failed to create lookup", e);
59 }
60 try {
61 GET_SUB_PLAN_COMPILER_CACHE = lookup.findGetter(ReteRecipeCompiler.class, "subPlanCompilerCache",
62 Map.class);
63 GET_COMPILER_BACK_TRACE = lookup.findGetter(ReteRecipeCompiler.class, "compilerBackTrace", Map.class);
64 } catch (NoSuchFieldException | IllegalAccessException e) {
65 throw new IllegalStateException("Failed to find getter", e);
66 }
67
68 try {
69 NORMALIZER_FIELD = ReteRecipeCompiler.class.getDeclaredField("normalizer");
70 } catch (NoSuchFieldException e) {
71 throw new IllegalStateException("Failed to find field", e);
72 }
73 NORMALIZER_FIELD.setAccessible(true);
74
75 try {
76 DO_COMPILE_DISPATCH = lookup.findVirtual(ReteRecipeCompiler.class, "doCompileDispatch",
77 MethodType.methodType(CompiledSubPlan.class, SubPlan.class));
78 COMPILE_TO_NATURAL_JOIN = lookup.findVirtual(ReteRecipeCompiler.class, "compileToNaturalJoin",
79 MethodType.methodType(CompiledSubPlan.class, SubPlan.class, PlanningTrace.class,
80 PlanningTrace.class));
81 REFER_QUERY = lookup.findVirtual(ReteRecipeCompiler.class, "referQuery",
82 MethodType.methodType(PlanningTrace.class, PQuery.class, SubPlan.class, Tuple.class));
83 } catch (NoSuchMethodException | IllegalAccessException e) {
84 throw new IllegalStateException("Failed to find method", e);
85 }
86 }
87
88 private final Map<SubPlan, CompiledSubPlan> subPlanCompilerCache;
89 private final Map<ReteNodeRecipe, SubPlan> compilerBackTrace;
90
91 public RefineryReteRecipeCompiler(IQueryPlannerStrategy plannerStrategy, Logger logger,
92 IQueryMetaContext metaContext, IQueryCacheContext queryCacheContext,
93 IQueryBackendHintProvider hintProvider, QueryAnalyzer queryAnalyzer,
94 boolean deleteAndReDeriveEvaluation, TimelyConfiguration timelyEvaluation) {
95 super(plannerStrategy, logger, metaContext, queryCacheContext, hintProvider, queryAnalyzer,
96 deleteAndReDeriveEvaluation, timelyEvaluation);
97
98 var normalizer = new PDisjunctionRewriterCacher(new RefinerySurrogateQueryRewriter(),
99 new RefineryPBodyNormalizer(metaContext) {
100
101 @Override
102 protected boolean shouldExpandWeakenedAlternatives(PQuery query) {
103 var hint = hintProvider.getQueryEvaluationHint(query);
104 return ReteHintOptions.expandWeakenedAlternativeConstraints.getValueOrDefault(hint);
105 }
106
107 });
108 try {
109 // https://docs.oracle.com/javase/specs/jls/se17/html/jls-17.html#jls-17.5.3
110 // "The object should not be made visible to other threads, nor should the final fields be read,
111 // until all updates to the final fields of the object are complete."
112 // The {@code super} constructor only sets but doesn't read the {@code normalizer} field,
113 // therefore this is fine.
114 NORMALIZER_FIELD.set(this, normalizer);
115 } catch (IllegalAccessException e) {
116 throw new IllegalStateException("Failed to set private final field", e);
117 }
118
119 try {
120 @SuppressWarnings("unchecked")
121 var cache = (Map<SubPlan, CompiledSubPlan>) GET_SUB_PLAN_COMPILER_CACHE.invokeExact(
122 (ReteRecipeCompiler) this);
123 subPlanCompilerCache = cache;
124 @SuppressWarnings("unchecked")
125 var backTrace = (Map<ReteNodeRecipe, SubPlan>) GET_COMPILER_BACK_TRACE.invokeExact(
126 (ReteRecipeCompiler) this);
127 compilerBackTrace = backTrace;
128 } catch (Error e) {
129 // Fatal JVM errors should not be wrapped.
130 throw e;
131 } catch (Throwable e) {
132 throw new IllegalStateException("Failed to access private fields", e);
133 }
134 }
135
136 @Override
137 public CompiledSubPlan getCompiledForm(SubPlan plan) {
138 CompiledSubPlan compiled = subPlanCompilerCache.get(plan);
139 if (compiled == null) {
140 compiled = doCompileDispatchExtension(plan);
141 if (compiled == null) {
142 compiled = superDoCompileDispatch(plan);
143 }
144 subPlanCompilerCache.put(plan, compiled);
145 compilerBackTrace.put(compiled.getRecipe(), plan);
146 }
147 return compiled;
148 }
149
150 @Nullable
151 private CompiledSubPlan doCompileDispatchExtension(SubPlan plan) {
152 var operation = plan.getOperation();
153 if (operation instanceof PEnumerate enumerateOperation) {
154 return doCompileEnumerateExtension(enumerateOperation.getEnumerablePConstraint(), plan);
155 } else if (operation instanceof PApply applyOperation &&
156 applyOperation.getPConstraint() instanceof EnumerablePConstraint constraint) {
157 var secondaryParent = doEnumerateDispatchExtension(plan, constraint);
158 if (secondaryParent != null) {
159 var primaryParent = getCompiledForm(plan.getParentPlans().get(0));
160 return superCompileToNaturalJoin(plan, primaryParent, secondaryParent);
161 }
162 }
163 return null;
164 }
165
166 @Nullable
167 private CompiledSubPlan doCompileEnumerateExtension(EnumerablePConstraint constraint, SubPlan plan) {
168 var coreTrace = doEnumerateDispatchExtension(plan, constraint);
169 if (coreTrace == null) {
170 return null;
171 }
172 var trimmedTrace = CompilerHelper.checkAndTrimEqualVariables(plan, coreTrace);
173 return trimmedTrace.cloneFor(plan);
174 }
175
176 @Nullable
177 private PlanningTrace doEnumerateDispatchExtension(SubPlan plan, EnumerablePConstraint constraint) {
178 if (constraint instanceof RepresentativeElectionConstraint representativeElectionConstraint) {
179 return compileEnumerableExtension(plan, representativeElectionConstraint);
180 }
181 return null;
182 }
183
184 private PlanningTrace compileEnumerableExtension(SubPlan plan, RepresentativeElectionConstraint constraint) {
185 var referredQuery = constraint.getSupplierKey();
186 var callTrace = superReferQuery(referredQuery, plan, constraint.getVariablesTuple());
187 var recipe = RefineryRecipesFactory.eINSTANCE.createRepresentativeElectionRecipe();
188 recipe.setParent(callTrace.getRecipe());
189 recipe.setConnectivity(constraint.getConnectivity());
190 return new PlanningTrace(plan, CompilerHelper.convertVariablesTuple(constraint), recipe, callTrace);
191 }
192
193 private CompiledSubPlan superDoCompileDispatch(SubPlan plan) {
194 try {
195 return (CompiledSubPlan) DO_COMPILE_DISPATCH.invokeExact((ReteRecipeCompiler) this, plan);
196 } catch (Error | RuntimeException e) {
197 // Fatal JVM errors and runtime exceptions should not be wrapped.
198 throw e;
199 } catch (Throwable e) {
200 throw new IllegalStateException("Failed to call doCompileDispatch", e);
201 }
202 }
203
204 private CompiledSubPlan superCompileToNaturalJoin(SubPlan plan, PlanningTrace leftCompiled,
205 PlanningTrace rightCompiled) {
206 try {
207 return (CompiledSubPlan) COMPILE_TO_NATURAL_JOIN.invokeExact((ReteRecipeCompiler) this, plan,
208 leftCompiled, rightCompiled);
209 } catch (Error | RuntimeException e) {
210 // Fatal JVM errors and runtime exceptions should not be wrapped.
211 throw e;
212 } catch (Throwable e) {
213 throw new IllegalStateException("Failed to call compileToNaturalJoin", e);
214 }
215 }
216
217 private PlanningTrace superReferQuery(PQuery query, SubPlan plan, Tuple actualParametersTuple) {
218 try {
219 return (PlanningTrace) REFER_QUERY.invokeExact((ReteRecipeCompiler) this, query, plan,
220 actualParametersTuple);
221 } catch (Error | RuntimeException e) {
222 // Fatal JVM errors and runtime exceptions should not be wrapped.
223 throw e;
224 } catch (Throwable e) {
225 throw new IllegalStateException("Failed to call referQuery", e);
226 }
227 }
228}