mirror of
https://github.com/apache/lucene.git
synced 2025-02-09 19:45:22 +00:00
LUCENE-6417: Make JavascriptCompiler completely stateless (thanks to visitor pattern)
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1694876 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1e82854532
commit
4b3268aaf4
@ -19,7 +19,6 @@ package org.apache.lucene.expressions.js;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -37,6 +36,7 @@ import org.antlr.v4.runtime.ANTLRInputStream;
|
|||||||
import org.antlr.v4.runtime.CommonTokenStream;
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
import org.antlr.v4.runtime.tree.ParseTree;
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.apache.lucene.expressions.Expression;
|
import org.apache.lucene.expressions.Expression;
|
||||||
|
import org.apache.lucene.expressions.js.JavascriptParser.ExpressionContext;
|
||||||
import org.apache.lucene.queries.function.FunctionValues;
|
import org.apache.lucene.queries.function.FunctionValues;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
@ -45,8 +45,6 @@ import org.objectweb.asm.Opcodes;
|
|||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
import org.objectweb.asm.commons.GeneratorAdapter;
|
import org.objectweb.asm.commons.GeneratorAdapter;
|
||||||
|
|
||||||
import static org.apache.lucene.expressions.js.JavascriptParser.ExpressionContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An expression compiler for javascript expressions.
|
* An expression compiler for javascript expressions.
|
||||||
* <p>
|
* <p>
|
||||||
@ -74,7 +72,7 @@ import static org.apache.lucene.expressions.js.JavascriptParser.ExpressionContex
|
|||||||
*
|
*
|
||||||
* @lucene.experimental
|
* @lucene.experimental
|
||||||
*/
|
*/
|
||||||
public class JavascriptCompiler {
|
public final class JavascriptCompiler {
|
||||||
static final class Loader extends ClassLoader {
|
static final class Loader extends ClassLoader {
|
||||||
Loader(ClassLoader parent) {
|
Loader(ClassLoader parent) {
|
||||||
super(parent);
|
super(parent);
|
||||||
@ -111,10 +109,6 @@ public class JavascriptCompiler {
|
|||||||
private static final int MAX_SOURCE_LENGTH = 16384;
|
private static final int MAX_SOURCE_LENGTH = 16384;
|
||||||
|
|
||||||
final String sourceText;
|
final String sourceText;
|
||||||
final Map<String, Integer> externalsMap = new LinkedHashMap<>();
|
|
||||||
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
|
||||||
GeneratorAdapter gen;
|
|
||||||
|
|
||||||
final Map<String,Method> functions;
|
final Map<String,Method> functions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,19 +183,18 @@ public class JavascriptCompiler {
|
|||||||
* @throws ParseException on failure to compile
|
* @throws ParseException on failure to compile
|
||||||
*/
|
*/
|
||||||
private Expression compileExpression(ClassLoader parent) throws ParseException {
|
private Expression compileExpression(ClassLoader parent) throws ParseException {
|
||||||
|
final Map<String, Integer> externalsMap = new LinkedHashMap<>();
|
||||||
|
final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||||
|
|
||||||
|
generateClass(getAntlrParseTree(), classWriter, externalsMap);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ParseTree parseTree = getAntlrParseTree();
|
|
||||||
|
|
||||||
beginCompile();
|
|
||||||
internalCompile(parseTree);
|
|
||||||
endCompile();
|
|
||||||
|
|
||||||
final Class<? extends Expression> evaluatorClass = new Loader(parent)
|
final Class<? extends Expression> evaluatorClass = new Loader(parent)
|
||||||
.define(COMPILED_EXPRESSION_CLASS, classWriter.toByteArray());
|
.define(COMPILED_EXPRESSION_CLASS, classWriter.toByteArray());
|
||||||
final Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
|
final Constructor<? extends Expression> constructor = evaluatorClass.getConstructor(String.class, String[].class);
|
||||||
|
|
||||||
return constructor.newInstance(sourceText, externalsMap.keySet().toArray(new String[externalsMap.size()]));
|
return constructor.newInstance(sourceText, externalsMap.keySet().toArray(new String[externalsMap.size()]));
|
||||||
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) {
|
} catch (ReflectiveOperationException exception) {
|
||||||
throw new IllegalStateException("An internal error occurred attempting to compile the expression (" + sourceText + ").", exception);
|
throw new IllegalStateException("An internal error occurred attempting to compile the expression (" + sourceText + ").", exception);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,16 +222,16 @@ public class JavascriptCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beginCompile() {
|
private void generateClass(ParseTree parseTree, ClassWriter classWriter, Map<String, Integer> externalsMap) {
|
||||||
classWriter.visit(CLASSFILE_VERSION,
|
classWriter.visit(CLASSFILE_VERSION,
|
||||||
Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
|
Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC,
|
||||||
COMPILED_EXPRESSION_INTERNAL,
|
COMPILED_EXPRESSION_INTERNAL,
|
||||||
null, EXPRESSION_TYPE.getInternalName(), null);
|
null, EXPRESSION_TYPE.getInternalName(), null);
|
||||||
String clippedSourceText = (sourceText.length() <= MAX_SOURCE_LENGTH) ?
|
final String clippedSourceText = (sourceText.length() <= MAX_SOURCE_LENGTH) ?
|
||||||
sourceText : (sourceText.substring(0, MAX_SOURCE_LENGTH - 3) + "...");
|
sourceText : (sourceText.substring(0, MAX_SOURCE_LENGTH - 3) + "...");
|
||||||
classWriter.visitSource(clippedSourceText, null);
|
classWriter.visitSource(clippedSourceText, null);
|
||||||
|
|
||||||
GeneratorAdapter constructor = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
|
final GeneratorAdapter constructor = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
|
||||||
EXPRESSION_CTOR, null, null, classWriter);
|
EXPRESSION_CTOR, null, null, classWriter);
|
||||||
constructor.loadThis();
|
constructor.loadThis();
|
||||||
constructor.loadArgs();
|
constructor.loadArgs();
|
||||||
@ -246,13 +239,10 @@ public class JavascriptCompiler {
|
|||||||
constructor.returnValue();
|
constructor.returnValue();
|
||||||
constructor.endMethod();
|
constructor.endMethod();
|
||||||
|
|
||||||
gen = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
|
final GeneratorAdapter gen = new GeneratorAdapter(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC,
|
||||||
EVALUATE_METHOD, null, null, classWriter);
|
EVALUATE_METHOD, null, null, classWriter);
|
||||||
}
|
|
||||||
|
|
||||||
// internalCompile is used to create an anonymous inner class around the ANTLR listener
|
// to completely hide the ANTLR visitor we use an anonymous impl:
|
||||||
// to completely hide the implementation details of expression compilation
|
|
||||||
private void internalCompile(ParseTree parseTree) {
|
|
||||||
new JavascriptBaseVisitor<Void>() {
|
new JavascriptBaseVisitor<Void>() {
|
||||||
private final Deque<Type> typeStack = new ArrayDeque<>();
|
private final Deque<Type> typeStack = new ArrayDeque<>();
|
||||||
|
|
||||||
@ -674,9 +664,7 @@ public class JavascriptCompiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.visit(parseTree);
|
}.visit(parseTree);
|
||||||
}
|
|
||||||
|
|
||||||
private void endCompile() {
|
|
||||||
gen.returnValue();
|
gen.returnValue();
|
||||||
gen.endMethod();
|
gen.endMethod();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user