/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.reflection;
import java.lang.reflect.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.constant.*;
/**
* This class serves two purposes. Firstly, it is a marker for classes whose bytecodes should not be verified (a la
* {@link sun.reflect.MagicAccessorImpl}). Secondly, it provides static methods for generating invocation stubs that
* are used to implement {@link Method#invoke(Object, Object...)} and {@link Constructor#newInstance(Object...)}.
*
* The bytecode generation is derived from the JDK 1.4 mechanism for the same purpose.
* @see sun.reflect.MethodAccessorGenerator
*/
public abstract class InvocationStub {
InvocationStub() {
// MUST BE EMPTY
}
/**
* Determines if this stub can access a given type. Only used to determine if the stub can be run under HotSpot or
* any other VM that will subject the stub to standard verification.
*/
public boolean canAccess(Class type) {
return Modifier.isPublic(type.getModifiers()) || getClass().getPackage().equals(type.getPackage());
}
/**
* Determines if this stub can access all the given types.
*
* @see #canAccess(Class)
*/
public boolean canAccess(Class... types) {
for (Class type : types) {
if (!canAccess(type)) {
return false;
}
}
return true;
}
/**
* A reference to the constructor or method for which this stub was generated.
*/
private MethodActor target;
final void setTarget(AccessibleObject target) {
assert this.target == null;
if (target instanceof Constructor) {
this.target = MethodActor.fromJavaConstructor((Constructor) target);
} else {
assert target instanceof Method;
this.target = MethodActor.fromJava((Method) target);
}
}
@Override
public final String toString() {
return getClass().getSimpleName() + "[" + target + "]";
}
/**
* Generates a stub for invoking a given method reflectively.
*/
public static MethodInvocationStub newMethodStub(Method method, Boxing boxing) {
final MethodInvocationStub stub = new InvocationStubGenerator<MethodInvocationStub>(
method,
MethodInvocationStub.class,
MethodActor.fromJava(method).name,
method.getDeclaringClass(),
method.getReturnType(),
method.getParameterTypes(),
Modifier.isStatic(method.getModifiers()),
Modifier.isPrivate(method.getModifiers()),
null,
boxing).stub();
stub.setTarget(method);
return stub;
}
/**
* Generates a stub for invoking a given constructor reflectively.
* @param constructor that is to be invoked
* @param classToInstantiate only non-null in the serialization context where it may differ from constructor.getDeclaringClass()
*/
public static ConstructorInvocationStub newConstructorStub(Constructor constructor, Class classToInstantiate, Boxing boxing) {
final ConstructorInvocationStub stub = new InvocationStubGenerator<ConstructorInvocationStub>(
constructor,
ConstructorInvocationStub.class,
SymbolTable.INIT,
constructor.getDeclaringClass(),
Void.TYPE,
constructor.getParameterTypes(),
false,
Modifier.isPrivate(constructor.getModifiers()),
classToInstantiate,
boxing).stub();
stub.setTarget(constructor);
return stub;
}
}