/*
* 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 static com.sun.max.lang.Classes.*;
import static com.sun.max.vm.reflection.InvocationStubGenerator.*;
import java.lang.reflect.*;
import com.sun.max.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.bytecode.graft.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.type.*;
import com.sun.max.vm.value.*;
/**
* An enumerated type to distinguish the style of boxing performed by a stub.
*/
public enum Boxing {
/**
* Parameters and return values are boxed in {@link Object} instances.
*/
JAVA {
private final SignatureDescriptor invokeSignature = SignatureDescriptor.fromJava(getDeclaredMethod(Method.class, "invoke", Object.class, Object[].class));
private final SignatureDescriptor newInstanceSignature = SignatureDescriptor.fromJava(getDeclaredMethod(Constructor.class, "newInstance", Object[].class));
@Override
public SignatureDescriptor invokeSignature() {
return invokeSignature;
}
@Override
public SignatureDescriptor newInstanceSignature() {
return newInstanceSignature;
}
@Override
Class[] runtimeParameterTypes(Class[] parameterTypes, Class declaringClass, boolean isStatic, boolean isConstructor) {
return parameterTypes;
}
@Override
void box(BytecodeAssembler asm, boolean isConstructor, Kind returnKind) {
if (!isConstructor) {
if (returnKind == Kind.VOID) {
asm.aconst_null();
} else if (returnKind != Kind.REFERENCE) {
if (returnKind.isWord) {
throw new IllegalArgumentException("cannot reflectively invoke method with a Word return type");
}
asm.invokestatic(JAVA_BOX_PRIMITIVE.get(returnKind.asEnum), returnKind.stackSlots, 1);
}
}
}
@Override
void unbox(BytecodeAssembler asm, Class parameterType, int parameterTypePoolConstantIndex) {
final Kind parameterKind = Kind.fromJava(parameterType);
if (parameterKind.isReference) {
asm.checkcast(parameterTypePoolConstantIndex);
} else {
if (parameterKind.isWord) {
throw new IllegalArgumentException("cannot reflectively invoke method with Word type parameter");
}
asm.invokestatic(JAVA_UNBOX_PRIMITIVE.get(parameterKind.asEnum), 1, parameterKind.stackSlots);
}
}
@Override
String sourceDeclaration(boolean isConstructor) {
if (isConstructor) {
return "public Object newInstance(Object... args) throws InstantiationException, IllegalArgumentException, InvocationTargetException";
}
return "public Object invoke(Object obj, Object... args) throws IllegalArgumentException, InvocationTargetException";
}
@Override
String sourceBox(ConstantPool pool, boolean isConstructor, Kind returnKind, String value) {
if (!isConstructor) {
if (returnKind == Kind.VOID) {
return "null";
} else if (returnKind != Kind.REFERENCE) {
if (returnKind.isWord) {
throw new IllegalArgumentException("cannot reflectively invoke method with a Word return type");
}
final ClassMethodRefConstant boxMethod = pool.classMethodAt(JAVA_BOX_PRIMITIVE.get(returnKind.asEnum));
return boxMethod.holder(pool).toJavaString(false) + "." + boxMethod.name(pool) + "(" + value + ")";
}
}
return value;
}
@Override
String sourceUnbox(ConstantPool pool, Class parameterType, String parameter) {
final Kind parameterKind = Kind.fromJava(parameterType);
if (parameterKind.isReference) {
return "(" + parameterType.getSimpleName() + ") " + parameter;
}
if (parameterKind.isWord) {
throw new IllegalArgumentException("cannot reflectively invoke method with Word type parameter");
}
final ClassMethodRefConstant unboxMethod = pool.classMethodAt(JAVA_UNBOX_PRIMITIVE.get(parameterKind.asEnum));
return unboxMethod.holder(pool).toJavaString(false) + "." + unboxMethod.name(pool) + "(" + parameter + ")";
}
},
/**
* Parameters and return values are boxed in {@link Value} instances.
*/
VALUE {
private final SignatureDescriptor invokeSignature = SignatureDescriptor.fromJava(getDeclaredMethod(MethodInvocationStub.class, "invoke", Value[].class));
private final SignatureDescriptor newInstanceSignature = SignatureDescriptor.fromJava(getDeclaredMethod(ConstructorInvocationStub.class, "newInstance", Value[].class));
@Override
public SignatureDescriptor invokeSignature() {
return invokeSignature;
}
@Override
public SignatureDescriptor newInstanceSignature() {
return newInstanceSignature;
}
@Override
Class[] runtimeParameterTypes(Class[] parameterTypes, Class declaringClass, boolean isStatic, boolean isConstructor) {
return (isStatic || isConstructor) ? parameterTypes : Utils.prepend(parameterTypes, declaringClass);
}
@Override
void box(BytecodeAssembler asm, boolean isConstructor, Kind returnKind) {
if (!isConstructor) {
if (returnKind == Kind.VOID) {
asm.getstatic(VoidValue_VOID);
} else {
asm.invokestatic(VALUE_BOX.get(returnKind.asEnum), returnKind.stackSlots, 1);
}
} else {
asm.invokestatic(VALUE_BOX.get(Kind.REFERENCE.asEnum), 1, 1);
}
}
@Override
void unbox(BytecodeAssembler asm, Class parameterType, int parameterTypePoolConstantIndex) {
final Kind parameterKind = Kind.fromJava(parameterType);
asm.invokevirtual(VALUE_UNBOX.get(parameterKind.asEnum), 1, parameterKind.stackSlots);
if (parameterKind.isReference) {
// cast against Object is unnecessary AND causes problems with values that are StaticTuples
if (parameterType != Object.class) {
asm.checkcast(parameterTypePoolConstantIndex);
}
} else if (parameterKind.isWord) {
if (parameterType != Word.class) {
Integer methodRefIndex = CAST_WORD.get(parameterType);
asm.invokevirtual(methodRefIndex, 1, 1);
}
}
}
@Override
String sourceDeclaration(boolean isConstructor) {
if (isConstructor) {
return "public Value newInstance(Value... args) throws InstantiationException, IllegalArgumentException, InvocationTargetException";
}
return "public Value invoke(Value... args) throws IllegalArgumentException, InvocationTargetException";
}
@Override
String sourceBox(ConstantPool pool, boolean isConstructor, Kind returnKind, String value) {
if (!isConstructor) {
if (returnKind == Kind.VOID) {
return "VoidValue.VOID";
}
final ClassMethodRefConstant boxMethod = pool.classMethodAt(VALUE_BOX.get(returnKind.asEnum));
return boxMethod.holder(pool).toJavaString(false) + "." + boxMethod.name(pool) + "(" + value + ")";
}
final ClassMethodRefConstant boxMethod = pool.classMethodAt(VALUE_BOX.get(Kind.REFERENCE.asEnum));
return boxMethod.holder(pool).toJavaString(false) + "." + boxMethod.name(pool) + "(" + value + ")";
}
@Override
String sourceUnbox(ConstantPool pool, Class parameterType, String parameter) {
final Kind parameterKind = Kind.fromJava(parameterType);
final ClassMethodRefConstant unboxMethod = pool.classMethodAt(VALUE_UNBOX.get(parameterKind.asEnum));
final String unboxedParameter = parameter + "." + unboxMethod.name(pool) + "()";
if (parameterKind.isReference) {
return "(" + parameterType.getSimpleName() + ") " + unboxedParameter;
} else if (parameterKind.isWord) {
// The following instructions will be optimized away to nothing
return "Boxing.castWord(" + parameterType.getSimpleName() + ", " + unboxedParameter + ")";
}
return unboxedParameter;
}
};
public abstract SignatureDescriptor invokeSignature();
public abstract SignatureDescriptor newInstanceSignature();
abstract void box(BytecodeAssembler asm, boolean isConstructor, Kind returnKind);
abstract Class[] runtimeParameterTypes(Class[] parameterTypes, Class declaringClass, boolean isStatic, boolean isConstructor);
abstract void unbox(BytecodeAssembler asm, Class parameterType, int parameterTypePoolConstantIndex);
abstract String sourceDeclaration(boolean isConstructor);
abstract String sourceBox(ConstantPool pool, boolean isConstructor, Kind returnKind, String value);
abstract String sourceUnbox(ConstantPool pool, Class parameterType, String parameter);
}