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
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,28 @@ final class Compiler {
*/
static final class Loader extends SecureClassLoader {
private final AtomicInteger lambdaCounter = new AtomicInteger(0);
private final Definition definition;

/**
* @param parent The parent ClassLoader.
*/
Loader(ClassLoader parent) {
Loader(ClassLoader parent, Definition definition) {
super(parent);

this.definition = definition;
}

/**
* Will check to see if the {@link Class} has already been loaded when
* the {@link Definition} was initially created. Allows for {@link Whitelist}ed
* classes to be loaded from other modules/plugins without a direct relationship
* to the module's/plugin's {@link ClassLoader}.
*/
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> found = definition.getClassFromBinaryName(name);

return found != null ? found : super.findClass(name);
}

/**
Expand Down Expand Up @@ -116,6 +132,14 @@ int newLambdaIdentifier() {
}
}

/**
* Return a new {@link Loader} for a script using the
* {@link Compiler}'s specified {@link Definition}.
*/
public Loader createLoader(ClassLoader parent) {
return new Loader(parent, definition);
}

/**
* The class/interface the script is guaranteed to derive/implement.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public final class Definition {

private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$");

private static final String[] DEFINITION_FILES = new String[] {
public static final String[] DEFINITION_FILES = new String[] {
"org.elasticsearch.txt",
"java.lang.txt",
"java.math.txt",
Expand Down Expand Up @@ -522,6 +522,12 @@ public RuntimeClass getRuntimeClass(Class<?> clazz) {
return runtimeMap.get(clazz);
}

public Class<?> getClassFromBinaryName(String name) {
Struct struct = structsMap.get(name.replace('$', '.'));

return struct == null ? null : struct.clazz;
}

/** Collection of all simple types. Used by {@code PainlessDocGenerator} to generate an API reference. */
Collection<Type> allSimpleTypes() {
return simpleTypesMap.values();
Expand All @@ -535,7 +541,7 @@ Collection<Type> allSimpleTypes() {

public AnalyzerCaster caster;

private Definition(List<Whitelist> whitelists) {
public Definition(List<Whitelist> whitelists) {
structsMap = new HashMap<>();
simpleTypesMap = new HashMap<>();
runtimeMap = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@
*/
public final class PainlessPlugin extends Plugin implements ScriptPlugin, ExtensiblePlugin {

// force to parse our definition at startup (not on the user's first script)
static {
Definition.DEFINITION.hashCode();
}

@Override
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
return new PainlessScriptEngine(settings, contexts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,16 @@ public PainlessScriptEngine(Settings settings, Collection<ScriptContext<?>> cont

Map<ScriptContext<?>, Compiler> contextsToCompilers = new HashMap<>();

// Placeholder definition used for all contexts until SPI is fully integrated. Reduces memory foot print
// by re-using the same definition since caching isn't implemented at this time.
Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));

for (ScriptContext<?> context : contexts) {
if (context.instanceClazz.equals(SearchScript.class) || context.instanceClazz.equals(ExecutableScript.class)) {
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, Definition.DEFINITION));
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, definition));
} else {
contextsToCompilers.put(context, new Compiler(context.instanceClazz, Definition.DEFINITION));
contextsToCompilers.put(context, new Compiler(context.instanceClazz, definition));
}
}

Expand All @@ -126,9 +131,11 @@ public String getType() {

@Override
public <T> T compile(String scriptName, String scriptSource, ScriptContext<T> context, Map<String, String> params) {
Compiler compiler = contextsToCompilers.get(context);

if (context.instanceClazz.equals(SearchScript.class)) {
GenericElasticsearchScript painlessScript =
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);

SearchScript.Factory factory = (p, lookup) -> new SearchScript.LeafFactory() {
@Override
Expand All @@ -143,7 +150,7 @@ public boolean needs_score() {
return context.factoryClazz.cast(factory);
} else if (context.instanceClazz.equals(ExecutableScript.class)) {
GenericElasticsearchScript painlessScript =
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);

ExecutableScript.Factory factory = (p) -> new ScriptImpl(painlessScript, p, null, null);
return context.factoryClazz.cast(factory);
Expand All @@ -155,7 +162,7 @@ public boolean needs_score() {
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
@Override
public Loader run() {
return new Loader(getClass().getClassLoader());
return compiler.createLoader(getClass().getClassLoader());
}
});

Expand Down Expand Up @@ -414,7 +421,7 @@ Object compile(Compiler compiler, String scriptName, String source, Map<String,
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
@Override
public Loader run() {
return new Loader(getClass().getClassLoader());
return compiler.createLoader(getClass().getClassLoader());
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,75 +23,82 @@
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.test.ESTestCase;

import java.util.Collections;

import static org.elasticsearch.painless.Definition.DEFINITION_FILES;

public class AnalyzerCasterTests extends ESTestCase {

private static final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, DEFINITION_FILES)));

private static void assertCast(Type actual, Type expected, boolean mustBeExplicit) {
Location location = new Location("dummy", 0);

if (actual.equals(expected)) {
assertFalse(mustBeExplicit);
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false));
assertNull(definition.caster.getLegalCast(location, actual, expected, false, false));
assertNull(definition.caster.getLegalCast(location, actual, expected, true, false));
return;
}

Cast cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false);
Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false);
assertEquals(actual, cast.from);
assertEquals(expected, cast.to);

if (mustBeExplicit) {
ClassCastException error = expectThrows(ClassCastException.class,
() -> Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
() -> definition.caster.getLegalCast(location, actual, expected, false, false));
assertTrue(error.getMessage().startsWith("Cannot cast"));
} else {
cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false);
cast = definition.caster.getLegalCast(location, actual, expected, false, false);
assertEquals(actual, cast.from);
assertEquals(expected, cast.to);
}
}

public void testNumericCasts() {
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.byteType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.shortType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.doubleType, false);

assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.shortType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.doubleType, false);

assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.doubleType, false);

assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.doubleType, false);

assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.longType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.doubleType, false);

assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.longType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.floatType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.doubleType, false);
assertCast(definition.byteType, definition.byteType, false);
assertCast(definition.byteType, definition.shortType, false);
assertCast(definition.byteType, definition.intType, false);
assertCast(definition.byteType, definition.longType, false);
assertCast(definition.byteType, definition.floatType, false);
assertCast(definition.byteType, definition.doubleType, false);

assertCast(definition.shortType, definition.byteType, true);
assertCast(definition.shortType, definition.shortType, false);
assertCast(definition.shortType, definition.intType, false);
assertCast(definition.shortType, definition.longType, false);
assertCast(definition.shortType, definition.floatType, false);
assertCast(definition.shortType, definition.doubleType, false);

assertCast(definition.intType, definition.byteType, true);
assertCast(definition.intType, definition.shortType, true);
assertCast(definition.intType, definition.intType, false);
assertCast(definition.intType, definition.longType, false);
assertCast(definition.intType, definition.floatType, false);
assertCast(definition.intType, definition.doubleType, false);

assertCast(definition.longType, definition.byteType, true);
assertCast(definition.longType, definition.shortType, true);
assertCast(definition.longType, definition.intType, true);
assertCast(definition.longType, definition.longType, false);
assertCast(definition.longType, definition.floatType, false);
assertCast(definition.longType, definition.doubleType, false);

assertCast(definition.floatType, definition.byteType, true);
assertCast(definition.floatType, definition.shortType, true);
assertCast(definition.floatType, definition.intType, true);
assertCast(definition.floatType, definition.longType, true);
assertCast(definition.floatType, definition.floatType, false);
assertCast(definition.floatType, definition.doubleType, false);

assertCast(definition.doubleType, definition.byteType, true);
assertCast(definition.doubleType, definition.shortType, true);
assertCast(definition.doubleType, definition.intType, true);
assertCast(definition.doubleType, definition.longType, true);
assertCast(definition.doubleType, definition.floatType, true);
assertCast(definition.doubleType, definition.doubleType, false);
}

}
Loading