001/*******************************************************************************
002 * Copyright (C) 2009-2011 FuseSource Corp.
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 *******************************************************************************/
011package org.fusesource.hawtjni.generator;
012
013import java.lang.reflect.Modifier;
014import java.util.List;
015
016import org.fusesource.hawtjni.generator.model.JNIClass;
017import org.fusesource.hawtjni.generator.model.JNIMethod;
018
019/**
020 * 
021 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
022 */
023public 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}