001: /*
002: * Copyright 2004 Brian S O'Neill
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.cojen.classfile;
018:
019: import java.io.InputStream;
020: import java.io.IOException;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.Method;
023: import java.lang.reflect.Modifier;
024: import java.util.MissingResourceException;
025:
026: /**
027: *
028: *
029: * @author Brian S O'Neill
030: */
031: public abstract class AbstractCodeAssembler implements CodeAssembler {
032: protected AbstractCodeAssembler() {
033: }
034:
035: public void ifComparisonBranch(Location location, String choice,
036: TypeDesc type) {
037: boolean trueBranch = false;
038: int length = choice.length();
039: if (choice.charAt(length - 1) == 't') {
040: trueBranch = true;
041: choice = choice.substring(0, length - 1);
042: }
043:
044: choice = choice.intern();
045:
046: switch (type.getTypeCode()) {
047: default:
048: if (choice == "==") {
049: ifEqualBranch(location, true);
050: } else if (choice == "!=") {
051: ifEqualBranch(location, false);
052: } else {
053: throw new IllegalArgumentException(
054: "Comparison not allowed on object types: "
055: + choice);
056: }
057: return;
058:
059: case TypeDesc.BOOLEAN_CODE:
060: case TypeDesc.CHAR_CODE:
061: case TypeDesc.BYTE_CODE:
062: case TypeDesc.SHORT_CODE:
063: case TypeDesc.INT_CODE:
064: ifComparisonBranch(location, choice);
065: return;
066:
067: case TypeDesc.LONG_CODE:
068: math(Opcode.LCMP);
069: break;
070:
071: case TypeDesc.FLOAT_CODE:
072: math((choice == (trueBranch ? "<=" : ">") || choice == (trueBranch ? "<"
073: : ">=")) ? Opcode.FCMPG : Opcode.FCMPL);
074: break;
075:
076: case TypeDesc.DOUBLE_CODE:
077: math((choice == (trueBranch ? "<=" : ">") || choice == (trueBranch ? "<"
078: : ">=")) ? Opcode.DCMPG : Opcode.DCMPL);
079: break;
080: }
081:
082: ifZeroComparisonBranch(location, choice);
083: }
084:
085: public void inline(Object code) {
086: // First load the class for the inlined code.
087:
088: Class codeClass = code.getClass();
089: String className = codeClass.getName().replace('.', '/')
090: + ".class";
091: ClassLoader loader = codeClass.getClassLoader();
092:
093: InputStream in;
094: if (loader == null) {
095: in = ClassLoader.getSystemResourceAsStream(className);
096: } else {
097: in = loader.getResourceAsStream(className);
098: }
099:
100: if (in == null) {
101: throw new MissingResourceException(
102: "Unable to find class file", className, null);
103: }
104:
105: ClassFile cf;
106: try {
107: cf = ClassFile.readFrom(in);
108: } catch (IOException e) {
109: MissingResourceException e2 = new MissingResourceException(
110: "Error loading class file: " + e.getMessage(),
111: className, null);
112: try {
113: e2.initCause(e);
114: } catch (NoSuchMethodError e3) {
115: }
116: throw e2;
117: }
118:
119: // Now find the single "define" method.
120: MethodInfo defineMethod = null;
121:
122: MethodInfo[] methods = cf.getMethods();
123: for (int i = 0; i < methods.length; i++) {
124: MethodInfo method = methods[i];
125: if ("define".equals(method.getName())) {
126: if (defineMethod != null) {
127: throw new IllegalArgumentException(
128: "Multiple define methods found");
129: } else {
130: defineMethod = method;
131: }
132: }
133: }
134:
135: if (defineMethod == null) {
136: throw new IllegalArgumentException("No define method found");
137: }
138:
139: // Copy stack arguments to expected local variables.
140: TypeDesc[] paramTypes = defineMethod.getMethodDescriptor()
141: .getParameterTypes();
142: LocalVariable[] paramVars = new LocalVariable[paramTypes.length];
143: for (int i = paramVars.length; --i >= 0;) {
144: LocalVariable paramVar = createLocalVariable(null,
145: paramTypes[i]);
146: storeLocal(paramVar);
147: paramVars[i] = paramVar;
148: }
149:
150: Label returnLocation = createLabel();
151: CodeDisassembler cd = new CodeDisassembler(defineMethod);
152: cd.disassemble(this , paramVars, returnLocation);
153: returnLocation.setLocation();
154: }
155:
156: public void invoke(Method method) {
157: TypeDesc ret = TypeDesc.forClass(method.getReturnType());
158:
159: Class[] paramClasses = method.getParameterTypes();
160: TypeDesc[] params = new TypeDesc[paramClasses.length];
161: for (int i = 0; i < params.length; i++) {
162: params[i] = TypeDesc.forClass(paramClasses[i]);
163: }
164:
165: Class clazz = method.getDeclaringClass();
166:
167: if (Modifier.isStatic(method.getModifiers())) {
168: invokeStatic(clazz.getName(), method.getName(), ret, params);
169: } else if (clazz.isInterface()) {
170: invokeInterface(clazz.getName(), method.getName(), ret,
171: params);
172: } else {
173: invokeVirtual(clazz.getName(), method.getName(), ret,
174: params);
175: }
176: }
177:
178: public void invokeSuper(Method method) {
179: TypeDesc ret = TypeDesc.forClass(method.getReturnType());
180:
181: Class[] paramClasses = method.getParameterTypes();
182: TypeDesc[] params = new TypeDesc[paramClasses.length];
183: for (int i = 0; i < params.length; i++) {
184: params[i] = TypeDesc.forClass(paramClasses[i]);
185: }
186:
187: invokeSuper(method.getDeclaringClass().getName(), method
188: .getName(), ret, params);
189: }
190:
191: public void invoke(Constructor constructor) {
192: Class[] paramClasses = constructor.getParameterTypes();
193: TypeDesc[] params = new TypeDesc[paramClasses.length];
194: for (int i = 0; i < params.length; i++) {
195: params[i] = TypeDesc.forClass(paramClasses[i]);
196: }
197:
198: invokeConstructor(constructor.getDeclaringClass().getName()
199: .toString(), params);
200: }
201: }
|