blob: 123b89c664fda3f05353d5bab487de15f2236151 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.eval;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
public class CodeSnippetCodeStream extends CodeStream {
static InvocationSite NO_INVOCATION_SITE =
new InvocationSite(){
public TypeBinding[] genericTypeArguments() { return null; }
public boolean isSuperAccess(){ return false; }
public boolean isTypeAccess() { return false; }
public void setActualReceiverType(ReferenceBinding receiverType) {}
public void setDepth(int depth) {}
public void setFieldIndex(int depth){}
public int sourceStart() { return 0; }
public int sourceEnd() { return 0; }
};
/**
* CodeSnippetCodeStream constructor comment.
* @param classFile org.eclipse.jdt.internal.compiler.ClassFile
*/
public CodeSnippetCodeStream(org.eclipse.jdt.internal.compiler.ClassFile classFile) {
super(classFile, JDK1_4);
}
protected void checkcast(int baseId) {
this.countLabels = 0;
if (classFileOffset + 2 >= bCodeStream.length) {
resizeByteArray();
}
this.position++;
this.bCodeStream[this.classFileOffset++] = OPC_checkcast;
switch (baseId) {
case T_byte :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangByteConstantPoolName));
break;
case T_short :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangShortConstantPoolName));
break;
case T_char :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangCharacterConstantPoolName));
break;
case T_int :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangIntegerConstantPoolName));
break;
case T_long :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangLongConstantPoolName));
break;
case T_float :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangFloatConstantPoolName));
break;
case T_double :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangDoubleConstantPoolName));
break;
case T_boolean :
writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangBooleanConstantPoolName));
}
}
public void generateEmulatedAccessForMethod(Scope scope, MethodBinding methodBinding) {
CodeSnippetCodeStream localCodeStream = this;
localCodeStream.generateEmulationForMethod(scope, methodBinding);
localCodeStream.invokeJavaLangReflectMethodInvoke();
}
public void generateEmulatedReadAccessForField(FieldBinding fieldBinding) {
CodeSnippetCodeStream localCodeStream = this;
localCodeStream.generateEmulationForField(fieldBinding);
// swap the field with the receiver
this.swap();
localCodeStream.invokeJavaLangReflectFieldGetter(fieldBinding.type.id);
if (!fieldBinding.type.isBaseType()) {
this.checkcast(fieldBinding.type);
}
}
public void generateEmulatedWriteAccessForField(FieldBinding fieldBinding) {
CodeSnippetCodeStream localCodeStream = this;
localCodeStream.invokeJavaLangReflectFieldSetter(fieldBinding.type.id);
}
public void generateEmulationForConstructor(Scope scope, MethodBinding methodBinding) {
// leave a java.lang.reflect.Field object on the stack
CodeSnippetCodeStream localCodeStream = this;
this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
int paramLength = methodBinding.parameters.length;
this.generateInlinedValue(paramLength);
this.newArray(scope.createArrayType(scope.getType(TypeConstants.JAVA_LANG_CLASS, 3), 1));
if (paramLength > 0) {
this.dup();
for (int i = 0; i < paramLength; i++) {
this.generateInlinedValue(i);
TypeBinding parameter = methodBinding.parameters[i];
if (parameter.isBaseType()) {
this.getTYPE(parameter.id);
} else if (parameter.isArrayType()) {
ArrayBinding array = (ArrayBinding)parameter;
if (array.leafComponentType.isBaseType()) {
this.getTYPE(array.leafComponentType.id);
} else {
this.ldc(String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
}
int dimensions = array.dimensions;
this.generateInlinedValue(dimensions);
this.newarray(T_int);
this.invokeArrayNewInstance();
this.invokeObjectGetClass();
} else {
// parameter is a reference binding
this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
}
this.aastore();
if (i < paramLength - 1) {
this.dup();
}
}
}
localCodeStream.invokeClassGetDeclaredConstructor();
this.dup();
this.iconst_1();
localCodeStream.invokeAccessibleObjectSetAccessible();
}
public void generateEmulationForField(FieldBinding fieldBinding) {
// leave a java.lang.reflect.Field object on the stack
CodeSnippetCodeStream localCodeStream = this;
this.ldc(String.valueOf(fieldBinding.declaringClass.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
this.ldc(String.valueOf(fieldBinding.name));
localCodeStream.invokeClassGetDeclaredField();
this.dup();
this.iconst_1();
localCodeStream.invokeAccessibleObjectSetAccessible();
}
public void generateEmulationForMethod(Scope scope, MethodBinding methodBinding) {
// leave a java.lang.reflect.Field object on the stack
CodeSnippetCodeStream localCodeStream = this;
this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
this.ldc(String.valueOf(methodBinding.selector));
int paramLength = methodBinding.parameters.length;
this.generateInlinedValue(paramLength);
this.newArray(scope.createArrayType(scope.getType(TypeConstants.JAVA_LANG_CLASS, 3), 1));
if (paramLength > 0) {
this.dup();
for (int i = 0; i < paramLength; i++) {
this.generateInlinedValue(i);
TypeBinding parameter = methodBinding.parameters[i];
if (parameter.isBaseType()) {
this.getTYPE(parameter.id);
} else if (parameter.isArrayType()) {
ArrayBinding array = (ArrayBinding)parameter;
if (array.leafComponentType.isBaseType()) {
this.getTYPE(array.leafComponentType.id);
} else {
this.ldc(String.valueOf(array.leafComponentType.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
}
int dimensions = array.dimensions;
this.generateInlinedValue(dimensions);
this.newarray(T_int);
this.invokeArrayNewInstance();
this.invokeObjectGetClass();
} else {
// parameter is a reference binding
this.ldc(String.valueOf(methodBinding.declaringClass.constantPoolName()).replace('/', '.'));
this.invokeClassForName();
}
this.aastore();
if (i < paramLength - 1) {
this.dup();
}
}
}
localCodeStream.invokeClassGetDeclaredMethod();
this.dup();
this.iconst_1();
localCodeStream.invokeAccessibleObjectSetAccessible();
}
public void generateObjectWrapperForType(TypeBinding valueType) {
/* The top of stack must be encapsulated inside
* a wrapper object if it corresponds to a base type
*/
TypeBinding wrapperType = this.methodDeclaration.scope.boxing(valueType);
new_(wrapperType);
if (valueType.id == T_long || valueType.id == T_double) {
dup_x2();
dup_x2();
pop();
} else {
dup_x1();
swap();
}
MethodBinding methodBinding = this.methodDeclaration.scope.getMethod(
wrapperType,
ConstantPool.Init,
new TypeBinding[] {valueType},
NO_INVOCATION_SITE);
invokespecial(methodBinding);
}
public void getBaseTypeValue(int baseTypeID) {
switch (baseTypeID) {
case T_byte :
// invokevirtual: byteValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangByteConstantPoolName,
ConstantPool.BYTEVALUE_BYTE_METHOD_NAME,
ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE);
break;
case T_short :
// invokevirtual: shortValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangShortConstantPoolName,
ConstantPool.SHORTVALUE_SHORT_METHOD_NAME,
ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE);
break;
case T_char :
// invokevirtual: charValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangCharacterConstantPoolName,
ConstantPool.CHARVALUE_CHARACTER_METHOD_NAME,
ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE);
break;
case T_int :
// invokevirtual: intValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangIntegerConstantPoolName,
ConstantPool.INTVALUE_INTEGER_METHOD_NAME,
ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE);
break;
case T_long :
// invokevirtual: longValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
2, // return type size
ConstantPool.JavaLangLongConstantPoolName,
ConstantPool.LONGVALUE_LONG_METHOD_NAME,
ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE);
break;
case T_float :
// invokevirtual: floatValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangFloatConstantPoolName,
ConstantPool.FLOATVALUE_FLOAT_METHOD_NAME,
ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE);
break;
case T_double :
// invokevirtual: doubleValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
2, // return type size
ConstantPool.JavaLangDoubleConstantPoolName,
ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_NAME,
ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE);
break;
case T_boolean :
// invokevirtual: booleanValue()
this.invoke(
OPC_invokevirtual,
0, // argCount
1, // return type size
ConstantPool.JavaLangBooleanConstantPoolName,
ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_NAME,
ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE);
}
}
protected void invokeAccessibleObjectSetAccessible() {
// invokevirtual: java.lang.reflect.AccessibleObject.setAccessible(Z)V;
this.invoke(
OPC_invokevirtual,
1, // argCount
0, // return type size
ConstantPool.JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME,
ConstantPool.SETACCESSIBLE_NAME,
ConstantPool.SETACCESSIBLE_SIGNATURE);
}
protected void invokeArrayNewInstance() {
// invokestatic: java.lang.reflect.Array.newInstance(Ljava.lang.Class;int[])Ljava.lang.Object;
this.invoke(
OPC_invokestatic,
2, // argCount
1, // return type size
ConstantPool.JAVALANGREFLECTARRAY_CONSTANTPOOLNAME,
ConstantPool.NewInstance,
ConstantPool.NewInstanceSignature);
}
protected void invokeClassGetDeclaredConstructor() {
// invokevirtual: java.lang.Class getDeclaredConstructor([Ljava.lang.Class)Ljava.lang.reflect.Constructor;
this.invoke(
OPC_invokevirtual,
1, // argCount
1, // return type size
ConstantPool.JavaLangClassConstantPoolName,
ConstantPool.GETDECLAREDCONSTRUCTOR_NAME,
ConstantPool.GETDECLAREDCONSTRUCTOR_SIGNATURE);
}
protected void invokeClassGetDeclaredField() {
// invokevirtual: java.lang.Class.getDeclaredField(Ljava.lang.String)Ljava.lang.reflect.Field;
this.invoke(
OPC_invokevirtual,
1, // argCount
1, // return type size
ConstantPool.JavaLangClassConstantPoolName,
ConstantPool.GETDECLAREDFIELD_NAME,
ConstantPool.GETDECLAREDFIELD_SIGNATURE);
}
protected void invokeClassGetDeclaredMethod() {
// invokevirtual: java.lang.Class getDeclaredMethod(Ljava.lang.String, [Ljava.lang.Class)Ljava.lang.reflect.Method;
this.invoke(
OPC_invokevirtual,
2, // argCount
1, // return type size
ConstantPool.JavaLangClassConstantPoolName,
ConstantPool.GETDECLAREDMETHOD_NAME,
ConstantPool.GETDECLAREDMETHOD_SIGNATURE);
}
protected void invokeJavaLangReflectConstructorNewInstance() {
// invokevirtual: java.lang.reflect.Constructor.newInstance([Ljava.lang.Object;)Ljava.lang.Object;
this.invoke(
OPC_invokevirtual,
1, // argCount
1, // return type size
ConstantPool.JavaLangReflectConstructor,
ConstantPool.NewInstance,
ConstantPool.JavaLangReflectConstructorNewInstanceSignature);
}
protected void invokeJavaLangReflectFieldGetter(int typeID) {
int returnTypeSize = 1;
char[] signature = null;
char[] selector = null;
switch (typeID) {
case T_int :
selector = ConstantPool.GET_INT_METHOD_NAME;
signature = ConstantPool.GET_INT_METHOD_SIGNATURE;
break;
case T_byte :
selector = ConstantPool.GET_BYTE_METHOD_NAME;
signature = ConstantPool.GET_BYTE_METHOD_SIGNATURE;
break;
case T_short :
selector = ConstantPool.GET_SHORT_METHOD_NAME;
signature = ConstantPool.GET_SHORT_METHOD_SIGNATURE;
break;
case T_long :
selector = ConstantPool.GET_LONG_METHOD_NAME;
signature = ConstantPool.GET_LONG_METHOD_SIGNATURE;
returnTypeSize = 2;
break;
case T_float :
selector = ConstantPool.GET_FLOAT_METHOD_NAME;
signature = ConstantPool.GET_FLOAT_METHOD_SIGNATURE;
break;
case T_double :
selector = ConstantPool.GET_DOUBLE_METHOD_NAME;
signature = ConstantPool.GET_DOUBLE_METHOD_SIGNATURE;
returnTypeSize = 2;
break;
case T_char :
selector = ConstantPool.GET_CHAR_METHOD_NAME;
signature = ConstantPool.GET_CHAR_METHOD_SIGNATURE;
break;
case T_boolean :
selector = ConstantPool.GET_BOOLEAN_METHOD_NAME;
signature = ConstantPool.GET_BOOLEAN_METHOD_SIGNATURE;
break;
default :
selector = ConstantPool.GET_OBJECT_METHOD_NAME;
signature = ConstantPool.GET_OBJECT_METHOD_SIGNATURE;
break;
}
this.invoke(
OPC_invokevirtual,
1, // argCount
returnTypeSize, // return type size
ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME,
selector,
signature);
}
protected void invokeJavaLangReflectFieldSetter(int typeID) {
int argCount = 2;
char[] signature = null;
char[] selector = null;
switch (typeID) {
case T_int :
selector = ConstantPool.SET_INT_METHOD_NAME;
signature = ConstantPool.SET_INT_METHOD_SIGNATURE;
break;
case T_byte :
selector = ConstantPool.SET_BYTE_METHOD_NAME;
signature = ConstantPool.SET_BYTE_METHOD_SIGNATURE;
break;
case T_short :
selector = ConstantPool.SET_SHORT_METHOD_NAME;
signature = ConstantPool.SET_SHORT_METHOD_SIGNATURE;
break;
case T_long :
selector = ConstantPool.SET_LONG_METHOD_NAME;
signature = ConstantPool.SET_LONG_METHOD_SIGNATURE;
argCount = 3;
break;
case T_float :
selector = ConstantPool.SET_FLOAT_METHOD_NAME;
signature = ConstantPool.SET_FLOAT_METHOD_SIGNATURE;
break;
case T_double :
selector = ConstantPool.SET_DOUBLE_METHOD_NAME;
signature = ConstantPool.SET_DOUBLE_METHOD_SIGNATURE;
argCount = 3;
break;
case T_char :
selector = ConstantPool.SET_CHAR_METHOD_NAME;
signature = ConstantPool.SET_CHAR_METHOD_SIGNATURE;
break;
case T_boolean :
selector = ConstantPool.SET_BOOLEAN_METHOD_NAME;
signature = ConstantPool.SET_BOOLEAN_METHOD_SIGNATURE;
break;
default :
selector = ConstantPool.SET_OBJECT_METHOD_NAME;
signature = ConstantPool.SET_OBJECT_METHOD_SIGNATURE;
break;
}
this.invoke(
OPC_invokevirtual,
argCount, // argCount
0, // return type size
ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME,
selector,
signature);
}
protected void invokeJavaLangReflectMethodInvoke() {
// invokevirtual: java.lang.reflect.Method.invoke(Ljava.lang.Object;[Ljava.lang.Object;)Ljava.lang.Object;
this.invoke(
OPC_invokevirtual,
2, // argCount
1, // return type size
ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME,
ConstantPool.INVOKE_METHOD_METHOD_NAME,
ConstantPool.INVOKE_METHOD_METHOD_SIGNATURE);
}
private final void resizeByteArray() {
int length = bCodeStream.length;
int requiredSize = length + length;
if (classFileOffset > requiredSize) {
// must be sure to grow by enough
requiredSize = classFileOffset + length;
}
System.arraycopy(bCodeStream, 0, bCodeStream = new byte[requiredSize], 0, length);
}
}