org.codehaus.groovy.vmplugin.v7.IndyGuardsFiltersAndSignatures Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy-all Show documentation
Show all versions of groovy-all Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.vmplugin.v7;
import groovy.lang.Closure;
import groovy.lang.GroovyObject;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.MetaClass;
import groovy.lang.MetaMethod;
import groovy.lang.MetaObjectProtocol;
import groovy.lang.MetaProperty;
import groovy.lang.MissingMethodException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
import org.codehaus.groovy.runtime.GroovyCategorySupport;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
import org.codehaus.groovy.runtime.wrappers.Wrapper;
import static org.codehaus.groovy.vmplugin.v7.IndyInterface.*;
/**
* This class contains guards, runtime filters and
* MethodType signatures used by indy.
* @author Jochen "blackdrag" Theodorou
*/
public class IndyGuardsFiltersAndSignatures {
private static final MethodType
ZERO_GUARD = MethodType.methodType(boolean.class),
OBJECT_GUARD = MethodType.methodType(boolean.class, Object.class),
CLASS1_GUARD = MethodType.methodType(boolean.class, Class.class, Object.class),
METACLASS1_GUARD = MethodType.methodType(boolean.class, MetaClass.class, Object.class),
GRE_GUARD = MethodType.methodType(Object.class, GroovyRuntimeException.class),
OBJECT_FILTER = MethodType.methodType(Object.class, Object.class),
BOUND_INVOKER = MethodType.methodType(Object.class, Object[].class),
ANO_INVOKER = MethodType.methodType(Object.class, Object.class, Object[].class),
INVOKER = MethodType.methodType(Object.class, Object.class, String.class, Object[].class),
GET_INVOKER = MethodType.methodType(Object.class, String.class)
;
protected static final MethodHandle
SAME_CLASS, UNWRAP_METHOD,
SAME_MC, IS_NULL,
UNWRAP_EXCEPTION, META_METHOD_INVOKER,
GROOVY_OBJECT_INVOKER, GROOVY_OBJECT_GET_PROPERTY,
HAS_CATEGORY_IN_CURRENT_THREAD_GUARD,
BEAN_CONSTRUCTOR_PROPERTY_SETTER,
META_PROPERTY_GETTER,
SLOW_META_CLASS_FIND, META_CLASS_INVOKE_STATIC_METHOD,
MOP_GET, MOP_INVOKE_CONSTRUCTOR, MOP_INVOKE_METHOD,
INTERCEPTABLE_INVOKER,
CLASS_FOR_NAME, BOOLEAN_IDENTITY,
DTT_CAST_TO_TYPE, SAM_CONVERSION,
HASHSET_CONSTRUCTOR, ARRAYLIST_CONSTRUCTOR, GROOVY_CAST_EXCEPTION,
EQUALS
;
static {
try {
SAME_CLASS = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "sameClass", CLASS1_GUARD);
UNWRAP_METHOD = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", OBJECT_FILTER);
SAME_MC = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "isSameMetaClass", METACLASS1_GUARD);
IS_NULL = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "isNull", OBJECT_GUARD);
UNWRAP_EXCEPTION = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "unwrap", GRE_GUARD);
GROOVY_OBJECT_INVOKER = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "invokeGroovyObjectInvoker", INVOKER.insertParameterTypes(0, MissingMethodException.class));
META_METHOD_INVOKER = LOOKUP.findVirtual(MetaMethod.class, "doMethodInvoke", ANO_INVOKER);
HAS_CATEGORY_IN_CURRENT_THREAD_GUARD = LOOKUP.findStatic(GroovyCategorySupport.class, "hasCategoryInCurrentThread", ZERO_GUARD);
GROOVY_OBJECT_GET_PROPERTY = LOOKUP.findVirtual(GroovyObject.class, "getProperty", GET_INVOKER);
META_CLASS_INVOKE_STATIC_METHOD = LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeStaticMethod", INVOKER);
BEAN_CONSTRUCTOR_PROPERTY_SETTER = LOOKUP.findStatic(IndyGuardsFiltersAndSignatures.class, "setBeanProperties", MethodType.methodType(Object.class, MetaClass.class, Object.class, Map.class));
META_PROPERTY_GETTER = LOOKUP.findVirtual(MetaProperty.class, "getProperty", OBJECT_FILTER);
MOP_GET = LOOKUP.findVirtual(MetaObjectProtocol.class, "getProperty", MethodType.methodType(Object.class, Object.class, String.class));
MOP_INVOKE_CONSTRUCTOR = LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeConstructor", BOUND_INVOKER);
MOP_INVOKE_METHOD = LOOKUP.findVirtual(MetaObjectProtocol.class, "invokeMethod", INVOKER);
SLOW_META_CLASS_FIND = LOOKUP.findStatic(InvokerHelper.class, "getMetaClass", MethodType.methodType(MetaClass.class, Object.class));
INTERCEPTABLE_INVOKER = LOOKUP.findVirtual(GroovyObject.class, "invokeMethod", MethodType.methodType(Object.class, String.class, Object.class));
CLASS_FOR_NAME = LOOKUP.findStatic(Class.class, "forName", MethodType.methodType(Class.class, String.class, boolean.class, ClassLoader.class));
BOOLEAN_IDENTITY = MethodHandles.identity(Boolean.class);
DTT_CAST_TO_TYPE = LOOKUP.findStatic(DefaultTypeTransformation.class, "castToType", MethodType.methodType(Object.class,Object.class,Class.class));
SAM_CONVERSION = LOOKUP.findStatic(CachedSAMClass.class, "coerceToSAM", MethodType.methodType(Object.class, Closure.class, Method.class, Class.class, boolean.class));
HASHSET_CONSTRUCTOR = LOOKUP.findConstructor(HashSet.class, MethodType.methodType(void.class, Collection.class));
ARRAYLIST_CONSTRUCTOR = LOOKUP.findConstructor(ArrayList.class, MethodType.methodType(void.class, Collection.class));
GROOVY_CAST_EXCEPTION = LOOKUP.findConstructor(GroovyCastException.class, MethodType.methodType(void.class, Object.class, Class.class));
EQUALS = LOOKUP.findVirtual(Object.class, "equals", OBJECT_GUARD);
} catch (Exception e) {
throw new GroovyBugError(e);
}
}
protected static final MethodHandle NULL_REF = MethodHandles.constant(Object.class, null);
/**
* This method is called by he handle to realize the bean constructor
* with property map.
*/
public static Object setBeanProperties(MetaClass mc, Object bean, Map properties) {
for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
mc.setProperty(bean, key, value);
}
return bean;
}
/**
* {@link GroovyObject#invokeMethod(String, Object)} path as fallback.
* This method is called by the handle as exception handler in case the
* selected method causes a MissingMethodExecutionFailed, where
* we will just give through the exception, and a normal
* MissingMethodException where we call {@link GroovyObject#invokeMethod(String, Object)}
* if receiver class, the type transported by the exception and the name
* for the method stored in the exception and our current method name
* are equal.
* Should those conditions not apply we just rethrow the exception.
*/
public static Object invokeGroovyObjectInvoker(MissingMethodException e, Object receiver, String name, Object[] args) {
if (e instanceof MissingMethodExecutionFailed) {
throw (MissingMethodException)e.getCause();
} else if (receiver.getClass() == e.getType() && e.getMethod().equals(name)) {
//TODO: we should consider calling this one directly for MetaClassImpl,
// then we save the new method selection
// in case there's nothing else, invoke the object's own invokeMethod()
return ((GroovyObject)receiver).invokeMethod(name, args);
} else {
throw e;
}
}
/**
* Unwraps a {@link GroovyRuntimeException}.
* This method is called by the handle to unwrap internal exceptions
* of the runtime.
*/
public static Object unwrap(GroovyRuntimeException gre) throws Throwable {
throw ScriptBytecodeAdapter.unwrap(gre);
}
/**
* called by handle
*/
public static boolean isSameMetaClass(MetaClass mc, Object receiver) {
//TODO: remove this method if possible by switchpoint usage
return receiver instanceof GroovyObject && mc==((GroovyObject)receiver).getMetaClass();
}
/**
* Unwraps a {@link Wrapper}.
* This method is called by the handle to unwrap a Wrapper, which
* we use to force method selection.
*/
public static Object unwrap(Object o) {
Wrapper w = (Wrapper) o;
return w.unwrap();
}
/**
* Guard to check if the argument is null.
* This method is called by the handle to check
* if the provided argument is null.
*/
public static boolean isNull(Object o) {
return o == null;
}
/**
* Guard to check if the provided Object has the same
* class as the provided Class. This method will
* return false if the Object is null.
*/
public static boolean sameClass(Class c, Object o) {
if (o==null) return false;
return o.getClass() == c;
}
}