/* * Copyright 2004-2010 Brian S O'Neill * * Licensed 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.cojen.classfile; import java.io.InputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.MissingResourceException; /** * * * @author Brian S O'Neill */ public abstract class AbstractCodeAssembler implements CodeAssembler { protected AbstractCodeAssembler() { } public void ifComparisonBranch(Location location, String choice, TypeDesc type) { boolean trueBranch = false; int length = choice.length(); if (choice.charAt(length - 1) == 't') { trueBranch = true; choice = choice.substring(0, length - 1); } choice = choice.intern(); switch (type.getTypeCode()) { default: if (choice == "==") { ifEqualBranch(location, true); } else if (choice == "!=") { ifEqualBranch(location, false); } else { throw new IllegalArgumentException ("Comparison not allowed on object types: " + choice); } return; case TypeDesc.BOOLEAN_CODE: case TypeDesc.CHAR_CODE: case TypeDesc.BYTE_CODE: case TypeDesc.SHORT_CODE: case TypeDesc.INT_CODE: ifComparisonBranch(location, choice); return; case TypeDesc.LONG_CODE: math(Opcode.LCMP); break; case TypeDesc.FLOAT_CODE: math((choice == (trueBranch ? "<=" : ">") || choice == (trueBranch ? "<" : ">=")) ? Opcode.FCMPG : Opcode.FCMPL); break; case TypeDesc.DOUBLE_CODE: math((choice == (trueBranch ? "<=" : ">") || choice == (trueBranch ? "<" : ">=")) ? Opcode.DCMPG : Opcode.DCMPL); break; } ifZeroComparisonBranch(location, choice); } public void inline(Object code) { // First load the class for the inlined code. Class codeClass = code.getClass(); String className = codeClass.getName().replace('.', '/') + ".class"; ClassLoader loader = codeClass.getClassLoader(); InputStream in; if (loader == null) { in = ClassLoader.getSystemResourceAsStream(className); } else { in = loader.getResourceAsStream(className); } if (in == null) { throw new MissingResourceException("Unable to find class file", className, null); } ClassFile cf; try { cf = ClassFile.readFrom(in); } catch (IOException e) { MissingResourceException e2 = new MissingResourceException ("Error loading class file: " + e.getMessage(), className, null); try { e2.initCause(e); } catch (NoSuchMethodError e3) { } throw e2; } // Now find the single "define" method. MethodInfo defineMethod = null; MethodInfo[] methods = cf.getMethods(); for (int i=0; i<methods.length; i++) { MethodInfo method = methods[i]; if ("define".equals(method.getName())) { if (defineMethod != null) { throw new IllegalArgumentException("Multiple define methods found"); } else { defineMethod = method; } } } if (defineMethod == null) { throw new IllegalArgumentException("No define method found"); } // Copy stack arguments to expected local variables. TypeDesc[] paramTypes = defineMethod.getMethodDescriptor().getParameterTypes(); LocalVariable[] paramVars = new LocalVariable[paramTypes.length]; for (int i=paramVars.length; --i>=0; ) { LocalVariable paramVar = createLocalVariable(null, paramTypes[i]); storeLocal(paramVar); paramVars[i] = paramVar; } Label returnLocation = createLabel(); CodeDisassembler cd = new CodeDisassembler(defineMethod); cd.disassemble(this, paramVars, returnLocation); returnLocation.setLocation(); } public void invoke(Method method) { TypeDesc ret = TypeDesc.forClass(method.getReturnType()); Class[] paramClasses = method.getParameterTypes(); TypeDesc[] params = new TypeDesc[paramClasses.length]; for (int i=0; i<params.length; i++) { params[i] = TypeDesc.forClass(paramClasses[i]); } Class clazz = method.getDeclaringClass(); if (Modifier.isStatic(method.getModifiers())) { invokeStatic(clazz.getName(), method.getName(), ret, params); } else if (clazz.isInterface()) { invokeInterface(clazz.getName(), method.getName(), ret, params); } else { invokeVirtual(clazz.getName(), method.getName(), ret, params); } } public void invokeSuper(Method method) { TypeDesc ret = TypeDesc.forClass(method.getReturnType()); Class[] paramClasses = method.getParameterTypes(); TypeDesc[] params = new TypeDesc[paramClasses.length]; for (int i=0; i<params.length; i++) { params[i] = TypeDesc.forClass(paramClasses[i]); } invokeSuper(method.getDeclaringClass().getName(), method.getName(), ret, params); } public void invoke(Constructor constructor) { Class[] paramClasses = constructor.getParameterTypes(); TypeDesc[] params = new TypeDesc[paramClasses.length]; for (int i=0; i<params.length; i++) { params[i] = TypeDesc.forClass(paramClasses[i]); } invokeConstructor(constructor.getDeclaringClass().getName().toString(), params); } }