Merge pull request #18335 from uschindler/painless_bootsrap_renames
painless: Rename the dynamic call site factory to DefBootstrap
This commit is contained in:
commit
f2cc8486af
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -139,7 +142,7 @@ public final class DynamicCallSite {
|
||||||
CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass",
|
CHECK_CLASS = lookup.findStatic(lookup.lookupClass(), "checkClass",
|
||||||
MethodType.methodType(boolean.class, Class.class, Object.class));
|
MethodType.methodType(boolean.class, Class.class, Object.class));
|
||||||
FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback",
|
FALLBACK = lookup.findVirtual(lookup.lookupClass(), "fallback",
|
||||||
MethodType.methodType(Object.class, Object[].class));
|
MethodType.methodType(Object.class, Object[].class));
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
throw new AssertionError(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
|
* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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 =
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue