001    /*******************************************************************************
002     * Copyright (c) 2009 Progress Software, Inc.
003     * Copyright (c) 2004, 2007 IBM Corporation and others.
004     *
005     * All rights reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     *
010     *******************************************************************************/
011    package org.fusesource.hawtjni.generator;
012    
013    import java.lang.reflect.Modifier;
014    import java.util.List;
015    
016    import org.fusesource.hawtjni.generator.model.JNIClass;
017    import org.fusesource.hawtjni.generator.model.JNIMethod;
018    
019    /**
020     * 
021     * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
022     */
023    public class StatsGenerator extends JNIGenerator {
024    
025        boolean header;
026    
027        public StatsGenerator(boolean header) {
028            this.header = header;
029        }
030    
031        public void generateCopyright() {
032            outputln(fixDelimiter(getCopyright()));
033        }
034    
035        public void generateIncludes() {
036            if (!header) {
037                outputln("#include \"hawtjni.h\"");
038                outputln("#include \""+getOutputName()+"_stats.h\"");
039                outputln();
040            }
041        }
042    
043        public void generate(JNIClass clazz) {
044            if (header) {
045                generateHeaderFile(clazz);
046            } else {
047                generateSourceFile(clazz);
048            }
049        }
050    
051        void generateHeaderFile(JNIClass clazz) {
052            generateNATIVEMacros(clazz);
053            List<JNIMethod> methods = clazz.getDeclaredMethods();
054            sortMethods(methods);
055            generateFunctionEnum(methods);
056        }
057    
058        void generateNATIVEMacros(JNIClass clazz) {
059            String className = clazz.getSimpleName();
060            outputln("#ifdef NATIVE_STATS");
061            output("extern int ");
062            output(className);
063            outputln("_nativeFunctionCount;");
064            output("extern int ");
065            output(className);
066            outputln("_nativeFunctionCallCount[];");
067            output("extern char* ");
068            output(className);
069            outputln("_nativeFunctionNames[];");
070            output("#define ");
071            output(className);
072            output("_NATIVE_ENTER(env, that, func) ");
073            output(className);
074            outputln("_nativeFunctionCallCount[func]++;");
075            output("#define ");
076            output(className);
077            outputln("_NATIVE_EXIT(env, that, func) ");
078            outputln("#else");
079            output("#ifndef ");
080            output(className);
081            outputln("_NATIVE_ENTER");
082            output("#define ");
083            output(className);
084            outputln("_NATIVE_ENTER(env, that, func) ");
085            outputln("#endif");
086            output("#ifndef ");
087            output(className);
088            outputln("_NATIVE_EXIT");
089            output("#define ");
090            output(className);
091            outputln("_NATIVE_EXIT(env, that, func) ");
092            outputln("#endif");
093            outputln("#endif");
094            outputln();
095        }
096    
097        void generateSourceFile(JNIClass clazz) {
098            outputln("#ifdef NATIVE_STATS");
099            outputln();
100            List<JNIMethod> methods = clazz.getDeclaredMethods();
101            int methodCount = 0;
102            for (JNIMethod method : methods) {
103                if ((method.getModifiers() & Modifier.NATIVE) == 0)
104                    continue;
105                methodCount++;
106            }
107            String className = clazz.getSimpleName();
108            output("int ");
109            output(className);
110            output("_nativeFunctionCount = ");
111            output(String.valueOf(methodCount));
112            outputln(";");
113            output("int ");
114            output(className);
115            output("_nativeFunctionCallCount[");
116            output(String.valueOf(methodCount));
117            outputln("];");
118            output("char * ");
119            output(className);
120            outputln("_nativeFunctionNames[] = {");
121            sortMethods(methods);
122            for (JNIMethod method : methods) {
123                if ((method.getModifiers() & Modifier.NATIVE) == 0)
124                    continue;
125                String function = getFunctionName(method), function64 = getFunctionName(method, method.getParameterTypes64());
126                if (!function.equals(function64)) {
127                    output("#ifndef ");
128                    output(JNI64);
129                    outputln();
130                }
131                output("\t\"");
132                output(function);
133                outputln("\",");
134                if (!function.equals(function64)) {
135                    outputln("#else");
136                    output("\t\"");
137                    output(function64);
138                    outputln("\",");
139                    outputln("#endif");
140                }
141                if (progress != null)
142                    progress.step();
143            }
144            outputln("};");
145            outputln();
146            generateStatsNatives(className);
147            outputln();
148            outputln("#endif");
149        }
150    
151        void generateStatsNatives(String className) {
152            outputln("#define STATS_NATIVE(func) Java_org_fusesource_hawtjni_runtime_NativeStats_##func");
153            outputln();
154    
155            output("JNIEXPORT jint JNICALL STATS_NATIVE(");
156            output(toC(className + "_GetFunctionCount"));
157            outputln(")");
158            outputln("\t(JNIEnv *env, jclass that)");
159            outputln("{");
160            output("\treturn ");
161            output(className);
162            outputln("_nativeFunctionCount;");
163            outputln("}");
164            outputln();
165    
166            output("JNIEXPORT jstring JNICALL STATS_NATIVE(");
167            output(toC(className + "_GetFunctionName"));
168            outputln(")");
169            outputln("\t(JNIEnv *env, jclass that, jint index)");
170            outputln("{");
171            output("\treturn ");
172            if (isCPP) {
173                output("env->NewStringUTF(");
174            } else {
175                output("(*env)->NewStringUTF(env, ");
176            }
177            output(className);
178            outputln("_nativeFunctionNames[index]);");
179            outputln("}");
180            outputln();
181    
182            output("JNIEXPORT jint JNICALL STATS_NATIVE(");
183            output(toC(className + "_GetFunctionCallCount"));
184            outputln(")");
185            outputln("\t(JNIEnv *env, jclass that, jint index)");
186            outputln("{");
187            output("\treturn ");
188            output(className);
189            outputln("_nativeFunctionCallCount[index];");
190            outputln("}");
191        }
192    
193        void generateFunctionEnum(List<JNIMethod> methods) {
194            if (methods.isEmpty())
195                return;
196            outputln("typedef enum {");
197            for (JNIMethod method : methods) {
198                if ((method.getModifiers() & Modifier.NATIVE) == 0)
199                    continue;
200                String function = getFunctionName(method), function64 = getFunctionName(method, method.getParameterTypes64());
201                if (!function.equals(function64)) {
202                    output("#ifndef ");
203                    output(JNI64);
204                    outputln();
205                }
206                output("\t");
207                output(method.getDeclaringClass().getSimpleName()+"_"+function);
208                outputln("_FUNC,");
209                if (!function.equals(function64)) {
210                    outputln("#else");
211                    output("\t");
212                    output(method.getDeclaringClass().getSimpleName()+"_"+function64);
213                    outputln("_FUNC,");
214                    outputln("#endif");
215                }
216                if (progress != null)
217                    progress.step();
218            }
219            JNIClass clazz = methods.get(0).getDeclaringClass();
220            output("} ");
221            output(clazz.getSimpleName());
222            outputln("_FUNCS;");
223        }
224    
225    }