From 9731d5d3140414e2da7816840f0f8cb05502b8dd Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Fri, 13 May 2016 19:58:05 +0200 Subject: [PATCH] painless: Rename the dynamic call site factory to DefBootstrap and make the inner class very short (PIC = Polymorphic Inline Cache) --- .../java/org/elasticsearch/painless/Def.java | 2 +- ...DynamicCallSite.java => DefBootstrap.java} | 35 ++++++++++--------- .../painless/WriterConstants.java | 2 +- .../painless/node/LDefArray.java | 6 ++-- .../elasticsearch/painless/node/LDefCall.java | 4 +-- .../painless/node/LDefField.java | 6 ++-- ...lSiteTests.java => DefBootstrapTests.java} | 18 +++++----- 7 files changed, 38 insertions(+), 35 deletions(-) rename modules/lang-painless/src/main/java/org/elasticsearch/painless/{DynamicCallSite.java => DefBootstrap.java} (85%) rename modules/lang-painless/src/test/java/org/elasticsearch/painless/{DynamicCallSiteTests.java => DefBootstrapTests.java} (83%) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java index 580363bc574..f82f04d801a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java @@ -43,7 +43,7 @@ import java.util.stream.Stream; * or method depending on the receiver's class. For these, we emit an {@code invokedynamic} instruction that, * for each new type encountered will query a corresponding {@code lookupXXX} method to retrieve the appropriate * method. In most cases, the {@code lookupXXX} methods here will only be called once for a given call site, because - * caching ({@link DynamicCallSite}) generally works: usually all objects at any call site will be consistently + * caching ({@link DefBootstrap}) generally works: usually all objects at any call site will be consistently * the same type (or just a few types). In extreme cases, if there is type explosion, they may be called every * single time, but simplicity is still more valuable than performance in this code. */ diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DynamicCallSite.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java similarity index 85% rename from modules/lang-painless/src/main/java/org/elasticsearch/painless/DynamicCallSite.java rename to modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java index 330a64e2a99..d9e96302eec 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DynamicCallSite.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java @@ -27,7 +27,7 @@ import java.lang.invoke.MethodType; import java.lang.invoke.MutableCallSite; /** - * Painless invokedynamic call site. + * Painless invokedynamic bootstrap for the call site. *

* Has 5 flavors (passed as static bootstrap parameters): dynamic method call, * dynamic field load (getter), and dynamic field store (setter), dynamic array load, @@ -41,9 +41,9 @@ import java.lang.invoke.MutableCallSite; */ // NOTE: this class must be public, because generated painless classes are in a different classloader, // and it needs to be accessible by that code. -public final class DynamicCallSite { +public final class DefBootstrap { - private DynamicCallSite() {} // no instance! + private DefBootstrap() {} // no instance! // NOTE: these must be primitive types, see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic /** static bootstrap parameter indicating a dynamic method call, e.g. foo.bar(...) */ @@ -57,7 +57,10 @@ public final class DynamicCallSite { /** static bootstrap parameter indicating a dynamic array store, e.g. foo[bar] = baz */ public static final int ARRAY_STORE = 4; - static final class InliningCacheCallSite extends MutableCallSite { + /** + * CallSite that implements the polymorphic inlining cache (PIC). + */ + static final class PIC extends MutableCallSite { /** maximum number of types before we go megamorphic */ static final int MAX_DEPTH = 5; @@ -65,14 +68,14 @@ public final class DynamicCallSite { private final int flavor; int depth; // pkg-protected for testing - InliningCacheCallSite(String name, MethodType type, int flavor) { + PIC(String name, MethodType type, int flavor) { super(type); this.name = name; this.flavor = flavor; - MethodHandle fallback = FALLBACK.bindTo(this); - fallback = fallback.asCollector(Object[].class, type.parameterCount()); - fallback = fallback.asType(type); + final MethodHandle fallback = FALLBACK.bindTo(this) + .asCollector(Object[].class, type.parameterCount()) + .asType(type); setTarget(fallback); } @@ -109,11 +112,10 @@ public final class DynamicCallSite { * types at this call site and given up on caching). */ Object fallback(Object[] args) throws Throwable { - MethodType type = type(); - Object receiver = args[0]; - Class receiverClass = receiver.getClass(); - MethodHandle target = lookup(flavor, receiverClass, name); - target = target.asType(type); + final MethodType type = type(); + final Object receiver = args[0]; + final Class receiverClass = receiver.getClass(); + final MethodHandle target = lookup(flavor, receiverClass, name).asType(type); if (depth >= MAX_DEPTH) { // revert to a vtable call @@ -124,7 +126,8 @@ public final class DynamicCallSite { MethodHandle test = CHECK_CLASS.bindTo(receiverClass); test = test.asType(test.type().changeParameterType(0, type.parameterType(0))); - MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget()); + final MethodHandle guard = MethodHandles.guardWithTest(test, target, getTarget()); + depth++; setTarget(guard); @@ -139,7 +142,7 @@ public final class DynamicCallSite { CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass", MethodType.methodType(boolean.class, Class.class, Object.class)); FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback", - MethodType.methodType(Object.class, Object[].class)); + MethodType.methodType(Object.class, Object[].class)); } catch (ReflectiveOperationException e) { throw new AssertionError(e); } @@ -155,7 +158,7 @@ public final class DynamicCallSite { * see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic */ public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor) { - return new InliningCacheCallSite(name, type, flavor); + return new PIC(name, type, flavor); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java index b13787cece5..3386fff9c58 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java @@ -58,7 +58,7 @@ public final class WriterConstants { public final static MethodType DEF_BOOTSTRAP_TYPE = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class); public final static Handle DEF_BOOTSTRAP_HANDLE = - new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DynamicCallSite.class), + new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DefBootstrap.class), "bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString()); public final static String DEF_DYNAMIC_LOAD_FIELD_DESC = diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java index 0fa2207bc9d..6b701a77728 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java @@ -21,7 +21,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Definition; -import org.elasticsearch.painless.DynamicCallSite; +import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Variables; import org.objectweb.asm.commons.GeneratorAdapter; @@ -62,13 +62,13 @@ final class LDefArray extends ALink { @Override void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { adapter.visitInvokeDynamicInsn( - "arrayLoad", DEF_DYNAMIC_ARRAY_LOAD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DynamicCallSite.ARRAY_LOAD }); + "arrayLoad", DEF_DYNAMIC_ARRAY_LOAD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DefBootstrap.ARRAY_LOAD }); } @Override void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { adapter.visitInvokeDynamicInsn( - "arrayStore", DEF_DYNAMIC_ARRAY_STORE_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DynamicCallSite.ARRAY_STORE }); + "arrayStore", DEF_DYNAMIC_ARRAY_STORE_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DefBootstrap.ARRAY_STORE }); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java index dc3e3abdcc8..dae2b74160a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java @@ -21,7 +21,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Definition; -import org.elasticsearch.painless.DynamicCallSite; +import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Variables; import org.objectweb.asm.commons.GeneratorAdapter; @@ -84,7 +84,7 @@ final class LDefCall extends ALink { // return value signature.append(definition.defType.type.getDescriptor()); - adapter.visitInvokeDynamicInsn(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, new Object[] { DynamicCallSite.METHOD_CALL }); + adapter.visitInvokeDynamicInsn(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, new Object[] { DefBootstrap.METHOD_CALL }); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java index 851c1e3f631..f8b2f3be83a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java @@ -21,7 +21,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.Definition; -import org.elasticsearch.painless.DynamicCallSite; +import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Variables; import org.objectweb.asm.commons.GeneratorAdapter; @@ -57,11 +57,11 @@ final class LDefField extends ALink { @Override void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { - adapter.visitInvokeDynamicInsn(value, DEF_DYNAMIC_LOAD_FIELD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DynamicCallSite.LOAD }); + adapter.visitInvokeDynamicInsn(value, DEF_DYNAMIC_LOAD_FIELD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DefBootstrap.LOAD }); } @Override void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { - adapter.visitInvokeDynamicInsn(value, DEF_DYNAMIC_STORE_FIELD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DynamicCallSite.STORE }); + adapter.visitInvokeDynamicInsn(value, DEF_DYNAMIC_STORE_FIELD_DESC, DEF_BOOTSTRAP_HANDLE, new Object[] { DefBootstrap.STORE }); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DynamicCallSiteTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java similarity index 83% rename from modules/lang-painless/src/test/java/org/elasticsearch/painless/DynamicCallSiteTests.java rename to modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java index de5202236db..4469279c8be 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DynamicCallSiteTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java @@ -26,14 +26,14 @@ import java.lang.invoke.MethodType; import org.elasticsearch.test.ESTestCase; -public class DynamicCallSiteTests extends ESTestCase { +public class DefBootstrapTests extends ESTestCase { /** calls toString() on integers, twice */ public void testOneType() throws Throwable { - CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), + CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(), "toString", MethodType.methodType(String.class, Object.class), - DynamicCallSite.METHOD_CALL); + DefBootstrap.METHOD_CALL); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -47,10 +47,10 @@ public class DynamicCallSiteTests extends ESTestCase { } public void testTwoTypes() throws Throwable { - CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), + CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(), "toString", MethodType.methodType(String.class, Object.class), - DynamicCallSite.METHOD_CALL); + DefBootstrap.METHOD_CALL); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -68,11 +68,11 @@ public class DynamicCallSiteTests extends ESTestCase { public void testTooManyTypes() throws Throwable { // if this changes, test must be rewritten - assertEquals(5, DynamicCallSite.InliningCacheCallSite.MAX_DEPTH); - CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), + assertEquals(5, DefBootstrap.PIC.MAX_DEPTH); + CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(), "toString", MethodType.methodType(String.class, Object.class), - DynamicCallSite.METHOD_CALL); + DefBootstrap.METHOD_CALL); MethodHandle handle = site.dynamicInvoker(); assertDepthEquals(site, 0); @@ -91,7 +91,7 @@ public class DynamicCallSiteTests extends ESTestCase { } static void assertDepthEquals(CallSite site, int expected) { - DynamicCallSite.InliningCacheCallSite dsite = (DynamicCallSite.InliningCacheCallSite) site; + DefBootstrap.PIC dsite = (DefBootstrap.PIC) site; assertEquals(expected, dsite.depth); } }