/*
* Copyright (c) 2009, 2012, 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 test.com.sun.max.vm.bytecode;
import static com.sun.max.vm.classfile.constant.SymbolTable.*;
import java.io.*;
import java.lang.reflect.*;
import com.sun.cri.ci.*;
import com.sun.max.io.*;
import com.sun.max.vm.actor.*;
import com.sun.max.vm.actor.holder.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.bytecode.graft.*;
import com.sun.max.vm.classfile.*;
import com.sun.max.vm.classfile.ClassfileWriter.ClassInfo;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.hosted.*;
import com.sun.max.vm.type.*;
/**
* A facility for creating a class method actor via bytecode assembly. A subclass simply has to override
* {@link #generateCode()} to emit the desired bytecode.
*
*/
public abstract class TestBytecodeAssembler extends BytecodeAssembler {
private final boolean isStatic;
private final Utf8Constant methodName;
private final Utf8Constant className;
private final SignatureDescriptor signature;
private ClassMethodActor classMethodActor;
/**
* Generates a class method actor via bytecode assembly.
*
* @param isStatic specifies if the generated class method is static
* @param className the {@linkplain ClassActor#name() name} of the class actor. If null, then the name will be
* derived from the {@code superClass} parameter provided to {@link #compile(Class, boolean, boolean, CiStatistics)}.
* @param methodName the {@linkplain Actor#name() name} of the class method actor
* @param signature the {@linkplain MethodActor#descriptor() signature} of the class method actor
*/
public TestBytecodeAssembler(boolean isStatic, String className, String methodName, SignatureDescriptor signature) {
super(new ConstantPool(HostedVMClassLoader.HOSTED_VM_CLASS_LOADER).edit());
this.isStatic = isStatic;
this.methodName = makeSymbol(methodName);
this.className = className == null ? null : makeSymbol(className);
this.signature = signature;
this.codeStream = new SeekableByteArrayOutputStream();
allocateParameters(isStatic, signature);
}
public TestBytecodeAssembler(boolean isStatic, String methodName, SignatureDescriptor signature) {
this(isStatic, null, methodName, signature);
}
private final SeekableByteArrayOutputStream codeStream;
@Override
protected void setWriteBCI(int bci) {
codeStream.seek(bci);
}
@Override
protected void writeByte(byte b) {
codeStream.write(b);
}
@Override
public byte[] code() {
fixup();
return codeStream.toByteArray();
}
protected abstract void generateCode();
/**
* Generates a default constructor that simply calls the super class' default constructor. If the
* latter does not exist, then this method returns null.
*/
private ClassMethodActor generateDefaultConstructor(Class<?> superClass) {
final ByteArrayBytecodeAssembler asm = new ByteArrayBytecodeAssembler(constantPoolEditor());
asm.allocateLocal(Kind.REFERENCE);
try {
final Constructor superDefaultConstructor = superClass.getDeclaredConstructor();
asm.aload(0);
asm.invokespecial(PoolConstantFactory.createClassMethodConstant(superDefaultConstructor), 1, 0);
asm.vreturn();
final CodeAttribute codeAttribute = new CodeAttribute(
constantPool(),
asm.code(),
(char) asm.maxStack(),
(char) asm.maxLocals(),
CodeAttribute.NO_EXCEPTION_HANDLER_TABLE,
LineNumberTable.EMPTY,
LocalVariableTable.EMPTY,
null);
return new VirtualMethodActor(
SymbolTable.INIT,
SignatureDescriptor.fromJava(Void.TYPE),
Modifier.PUBLIC | Actor.INITIALIZER,
codeAttribute, null);
} catch (NoSuchMethodException e) {
return null;
}
}
/**
* @param superClass the super class of generated holder for the generated class method actor
*/
public ClassMethodActor classMethodActor(Class superClass) {
if (classMethodActor == null) {
generateCode();
final CodeAttribute codeAttribute = new CodeAttribute(
constantPool(),
code(),
(char) 100, // TODO: compute max stack
(char) maxLocals(),
CodeAttribute.NO_EXCEPTION_HANDLER_TABLE,
LineNumberTable.EMPTY,
LocalVariableTable.EMPTY,
null);
classMethodActor = isStatic ?
new StaticMethodActor(
methodName,
signature,
Modifier.PUBLIC | Modifier.STATIC,
codeAttribute, null) :
new VirtualMethodActor(
methodName,
signature,
Modifier.PUBLIC,
codeAttribute, null);
final Utf8Constant className = this.className == null ? makeSymbol(superClass.getName() + "_$GENERATED$_" + methodName) : this.className;
final ClassMethodActor defaultConstructor = generateDefaultConstructor(superClass);
final ClassMethodActor[] classMethodActors;
if (defaultConstructor != null) {
classMethodActors = new ClassMethodActor[]{classMethodActor, defaultConstructor};
} else {
classMethodActors = new ClassMethodActor[]{classMethodActor};
}
final ClassActor classActor = ClassActorFactory.createTupleOrHybridClassActor(
constantPool(),
BootClassLoader.BOOT_CLASS_LOADER,
className,
ClassfileReader.JAVA_1_5_VERSION,
(char) 0,
Modifier.PUBLIC | Actor.REFLECTION_STUB,
ClassActor.fromJava(superClass),
new InterfaceActor[0],
new FieldActor[0],
classMethodActors,
Actor.NO_GENERIC_SIGNATURE,
Actor.NO_RUNTIME_VISIBLE_ANNOTATION_BYTES,
ClassActor.NO_SOURCE_FILE_NAME,
ClassActor.NO_INNER_CLASSES,
ClassActor.NO_OUTER_CLASS,
ClassActor.NO_ENCLOSING_METHOD_INFO);
try {
if (ClassRegistry.define(classActor) == classActor) {
ClassfileWriter.saveGeneratedClass(new ClassInfo(classActor), constantPoolEditor());
}
} catch (IOException e) {
throw (NoClassDefFoundError) new NoClassDefFoundError(className.toString()).initCause(e);
}
constantPoolEditor().release();
}
return classMethodActor;
}
}