Merge pull request #18335 from uschindler/painless_bootsrap_renames

painless: Rename the dynamic call site factory to DefBootstrap
This commit is contained in:
Robert Muir 2016-05-13 14:05:14 -04:00
commit f2cc8486af
7 changed files with 38 additions and 35 deletions

View File

@ -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, * 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 * 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 * 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 * 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. * single time, but simplicity is still more valuable than performance in this code.
*/ */

View File

@ -27,7 +27,7 @@ import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite; import java.lang.invoke.MutableCallSite;
/** /**
* Painless invokedynamic call site. * Painless invokedynamic bootstrap for the call site.
* <p> * <p>
* Has 5 flavors (passed as static bootstrap parameters): dynamic method call, * Has 5 flavors (passed as static bootstrap parameters): dynamic method call,
* dynamic field load (getter), and dynamic field store (setter), dynamic array load, * 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, // NOTE: this class must be public, because generated painless classes are in a different classloader,
// and it needs to be accessible by that code. // 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 // 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(...) */ /** 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 */ /** static bootstrap parameter indicating a dynamic array store, e.g. foo[bar] = baz */
public static final int ARRAY_STORE = 4; 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 */ /** maximum number of types before we go megamorphic */
static final int MAX_DEPTH = 5; static final int MAX_DEPTH = 5;
@ -65,14 +68,14 @@ public final class DynamicCallSite {
private final int flavor; private final int flavor;
int depth; // pkg-protected for testing int depth; // pkg-protected for testing
InliningCacheCallSite(String name, MethodType type, int flavor) { PIC(String name, MethodType type, int flavor) {
super(type); super(type);
this.name = name; this.name = name;
this.flavor = flavor; this.flavor = flavor;
MethodHandle fallback = FALLBACK.bindTo(this); final MethodHandle fallback = FALLBACK.bindTo(this)
fallback = fallback.asCollector(Object[].class, type.parameterCount()); .asCollector(Object[].class, type.parameterCount())
fallback = fallback.asType(type); .asType(type);
setTarget(fallback); setTarget(fallback);
} }
@ -109,11 +112,10 @@ public final class DynamicCallSite {
* types at this call site and given up on caching). * types at this call site and given up on caching).
*/ */
Object fallback(Object[] args) throws Throwable { Object fallback(Object[] args) throws Throwable {
MethodType type = type(); final MethodType type = type();
Object receiver = args[0]; final Object receiver = args[0];
Class<?> receiverClass = receiver.getClass(); final Class<?> receiverClass = receiver.getClass();
MethodHandle target = lookup(flavor, receiverClass, name); final MethodHandle target = lookup(flavor, receiverClass, name).asType(type);
target = target.asType(type);
if (depth >= MAX_DEPTH) { if (depth >= MAX_DEPTH) {
// revert to a vtable call // revert to a vtable call
@ -124,7 +126,8 @@ public final class DynamicCallSite {
MethodHandle test = CHECK_CLASS.bindTo(receiverClass); MethodHandle test = CHECK_CLASS.bindTo(receiverClass);
test = test.asType(test.type().changeParameterType(0, type.parameterType(0))); 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++; depth++;
setTarget(guard); setTarget(guard);
@ -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 * 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) { public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor) {
return new InliningCacheCallSite(name, type, flavor); return new PIC(name, type, flavor);
} }
} }

View File

@ -58,7 +58,7 @@ public final class WriterConstants {
public final static MethodType DEF_BOOTSTRAP_TYPE = public final static MethodType DEF_BOOTSTRAP_TYPE =
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class); MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class);
public final static Handle DEF_BOOTSTRAP_HANDLE = 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()); "bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString());
public final static String DEF_DYNAMIC_LOAD_FIELD_DESC = public final static String DEF_DYNAMIC_LOAD_FIELD_DESC =

View File

@ -21,7 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DynamicCallSite; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.GeneratorAdapter;
@ -62,13 +62,13 @@ final class LDefArray extends ALink {
@Override @Override
void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
adapter.visitInvokeDynamicInsn( 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 @Override
void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) {
adapter.visitInvokeDynamicInsn( 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 });
} }
} }

View File

@ -21,7 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DynamicCallSite; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.GeneratorAdapter;
@ -84,7 +84,7 @@ final class LDefCall extends ALink {
// return value // return value
signature.append(definition.defType.type.getDescriptor()); 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 @Override

View File

@ -21,7 +21,7 @@ package org.elasticsearch.painless.node;
import org.elasticsearch.painless.CompilerSettings; import org.elasticsearch.painless.CompilerSettings;
import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.DynamicCallSite; import org.elasticsearch.painless.DefBootstrap;
import org.elasticsearch.painless.Variables; import org.elasticsearch.painless.Variables;
import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.GeneratorAdapter;
@ -57,11 +57,11 @@ final class LDefField extends ALink {
@Override @Override
void load(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { 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 @Override
void store(final CompilerSettings settings, final Definition definition, final GeneratorAdapter adapter) { 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 });
} }
} }

View File

@ -26,14 +26,14 @@ import java.lang.invoke.MethodType;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
public class DynamicCallSiteTests extends ESTestCase { public class DefBootstrapTests extends ESTestCase {
/** calls toString() on integers, twice */ /** calls toString() on integers, twice */
public void testOneType() throws Throwable { public void testOneType() throws Throwable {
CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString", "toString",
MethodType.methodType(String.class, Object.class), MethodType.methodType(String.class, Object.class),
DynamicCallSite.METHOD_CALL); DefBootstrap.METHOD_CALL);
MethodHandle handle = site.dynamicInvoker(); MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0); assertDepthEquals(site, 0);
@ -47,10 +47,10 @@ public class DynamicCallSiteTests extends ESTestCase {
} }
public void testTwoTypes() throws Throwable { public void testTwoTypes() throws Throwable {
CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString", "toString",
MethodType.methodType(String.class, Object.class), MethodType.methodType(String.class, Object.class),
DynamicCallSite.METHOD_CALL); DefBootstrap.METHOD_CALL);
MethodHandle handle = site.dynamicInvoker(); MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0); assertDepthEquals(site, 0);
@ -68,11 +68,11 @@ public class DynamicCallSiteTests extends ESTestCase {
public void testTooManyTypes() throws Throwable { public void testTooManyTypes() throws Throwable {
// if this changes, test must be rewritten // if this changes, test must be rewritten
assertEquals(5, DynamicCallSite.InliningCacheCallSite.MAX_DEPTH); assertEquals(5, DefBootstrap.PIC.MAX_DEPTH);
CallSite site = DynamicCallSite.bootstrap(MethodHandles.publicLookup(), CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString", "toString",
MethodType.methodType(String.class, Object.class), MethodType.methodType(String.class, Object.class),
DynamicCallSite.METHOD_CALL); DefBootstrap.METHOD_CALL);
MethodHandle handle = site.dynamicInvoker(); MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0); assertDepthEquals(site, 0);
@ -91,7 +91,7 @@ public class DynamicCallSiteTests extends ESTestCase {
} }
static void assertDepthEquals(CallSite site, int expected) { static void assertDepthEquals(CallSite site, int expected) {
DynamicCallSite.InliningCacheCallSite dsite = (DynamicCallSite.InliningCacheCallSite) site; DefBootstrap.PIC dsite = (DefBootstrap.PIC) site;
assertEquals(expected, dsite.depth); assertEquals(expected, dsite.depth);
} }
} }