diff options
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.java | 228 |
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 | *******************************************************************************/ | ||
9 | package tools.refinery.store.query.viatra.internal.rete; | ||
10 | |||
11 | import org.apache.log4j.Logger; | ||
12 | import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendHintProvider; | ||
13 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryCacheContext; | ||
14 | import org.eclipse.viatra.query.runtime.matchers.context.IQueryMetaContext; | ||
15 | import org.eclipse.viatra.query.runtime.matchers.planning.IQueryPlannerStrategy; | ||
16 | import org.eclipse.viatra.query.runtime.matchers.planning.SubPlan; | ||
17 | import org.eclipse.viatra.query.runtime.matchers.planning.operations.PApply; | ||
18 | import org.eclipse.viatra.query.runtime.matchers.planning.operations.PEnumerate; | ||
19 | import org.eclipse.viatra.query.runtime.matchers.psystem.EnumerablePConstraint; | ||
20 | import org.eclipse.viatra.query.runtime.matchers.psystem.analysis.QueryAnalyzer; | ||
21 | import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; | ||
22 | import org.eclipse.viatra.query.runtime.matchers.psystem.rewriters.PDisjunctionRewriterCacher; | ||
23 | import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; | ||
24 | import org.eclipse.viatra.query.runtime.rete.construction.plancompiler.CompilerHelper; | ||
25 | import org.eclipse.viatra.query.runtime.rete.construction.plancompiler.ReteRecipeCompiler; | ||
26 | import org.eclipse.viatra.query.runtime.rete.matcher.TimelyConfiguration; | ||
27 | import org.eclipse.viatra.query.runtime.rete.recipes.ReteNodeRecipe; | ||
28 | import org.eclipse.viatra.query.runtime.rete.traceability.CompiledSubPlan; | ||
29 | import org.eclipse.viatra.query.runtime.rete.traceability.PlanningTrace; | ||
30 | import org.eclipse.viatra.query.runtime.rete.util.ReteHintOptions; | ||
31 | import org.jetbrains.annotations.Nullable; | ||
32 | import tools.refinery.store.query.viatra.internal.pquery.RepresentativeElectionConstraint; | ||
33 | import tools.refinery.store.query.viatra.internal.rete.recipe.RefineryRecipesFactory; | ||
34 | import tools.refinery.store.query.viatra.internal.pquery.rewriter.RefineryPBodyNormalizer; | ||
35 | import tools.refinery.store.query.viatra.internal.pquery.rewriter.RefinerySurrogateQueryRewriter; | ||
36 | |||
37 | import java.lang.invoke.MethodHandle; | ||
38 | import java.lang.invoke.MethodHandles; | ||
39 | import java.lang.invoke.MethodType; | ||
40 | import java.lang.reflect.Field; | ||
41 | import java.util.Map; | ||
42 | |||
43 | // Since we don't modify VIATRA code, this is our last resort. | ||
44 | @SuppressWarnings("squid:S3011") | ||
45 | public 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 | } | ||