netscape-revival
sun-java/classsrc/netscape/tools/jric/StubGenerator.java
// Copyright (c) 1995 Netscape Communications Corporation. All rights reserved.
package netscape.tools.jric;
import netscape.tools.ClassFileParser.*;
import java.io.*;
public
class StubGenerator extends NativesGenerator {
public StubGenerator(Main global, ClassDef clazz) {
super(global, clazz);
}
public String getFileName() {
return clazzCName + ".c";
}
protected String getHeaderString() {
return clazz.name + " stub file\n * Generated by jric";
}
public void generateOutput() throws IOException {
int i;
String prefix = clazz.getPrefix();
out.println("#include \"jri.h\"\n");
out.println("#ifdef IMPLEMENT_" + clazzCName);
out.println("#define _implementing_" + clazzCName);
out.println("#endif /* IMPLEMENT_" + clazzCName + " */");
out.println("#define IMPLEMENT_" + clazzCName);
out.println("#include \"" + clazzCName + ".h\"\n");
for (i = 0; i < clazz.fields.length; i++) {
FieldDef field = clazz.fields[i];
String fname = field.getCName();
out.println("#ifndef UNUSED_" + fname);
out.println("JRIFieldID FAR fieldID_" + fname
+ " = JRIUninitialized;");
out.println("#ifdef DEBUG");
forwardDeclare(field);
boolean isStatic = field.hasAccess(ClassFileParser.ACC_STATIC);
String resultType = getTypeName(field.signature, 0);
String suffix = getSuffix(field.signature, 0);
out.println("JRI_PUBLIC_API(" + resultType + ")");
out.print("get_" + fname);
printGetterArgDecl(field);
out.println(" {");
out.println("\tif (fieldID_" + fname + " == JRIUninitialized) {");
out.println("\t\tassert(!\"Forgot to call use_" + clazzCName
+ "(env) before accessing field "
+ field.name + " " + field.signature + "\");");
out.println("\t}");
out.print("\treturn ");
if (suffix.equals(""))
out.print("(" + resultType + ")\n\t\t");
out.print("JRI_Get" + (isStatic ? "Static" : "") + "Field" + suffix);
printGetterArgUse(field, true);
out.print(";\n}\n");
out.println("JRI_PUBLIC_API(void)");
out.print("set_" + fname);
printSetterArgDecl(field);
out.println(" {");
out.println("\tif (fieldID_" + fname + " == JRIUninitialized) {");
out.println("\t\tassert(!\"Forgot to call use_" + clazzCName
+ "(env) before accessing field "
+ field.name + " " + field.signature + "\");");
out.println("\t}");
out.print("\tJRI_Set" + (isStatic ? "Static" : "") + "Field" + suffix);
printSetterArgUse(field, true);
out.print(";\n}\n");
out.println("#endif /* DEBUG */");
out.println("#endif /* UNUSED_" + fname + " */\n");
}
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
String mname = prefix + "_" + method.getCName(i);
out.println("#ifndef UNUSED_" + mname);
out.println("JRIMethodID FAR methodID_" + mname
+ " = JRIUninitialized;");
out.println("#ifdef DEBUG");
printMethodFunctionSig(prefix, method, i, false);
out.println(" {");
out.println("\tif (methodID_" + mname + " == JRIUninitialized) {");
out.println("\t\tassert(!\"Forgot to call use_" + clazzCName
+ "(env) before calling method "
+ method.name + " " + method.signature + "\");");
out.println("\t}");
String resultType = getResultTypeName(method);
if (method.isConstructor()) {
out.print("\treturn (struct " + clazzCName + "*)JRI_NewObject(env)");
printMethodArgUse(prefix, method, i, true, false);
out.println(";\n}");
}
else {
boolean isStatic = method.hasAccess(ClassFileParser.ACC_STATIC);
boolean isVoid = resultType.equals("void");
out.print("\t" + (isVoid ? "" : "return ") + "(" + resultType + ")JRI_Call"
+ (isStatic ? "Static" : "") + "Method"
+ getResultSuffix(method) + "(env)");
printMethodArgUse(prefix, method, i, true, false);
out.println(";\n}");
}
out.println("#endif /* DEBUG */");
out.println("#endif /* UNUSED_" + mname + " */\n");
}
// Generate use and unuse routines
out.println("#ifndef UNUSED_use_" + clazzCName + "\n");
out.println("static jglobal _globalclass_" + clazzCName
+ " = NULL;\n");
// Generate the use_ routine
out.println("JRI_PUBLIC_API(struct java_lang_Class*)\nuse_"
+ clazzCName + "(JRIEnv* env)\n{");
out.println("\tif (_globalclass_" + clazzCName + " == NULL) {");
out.println("\t\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_"
+ clazzCName + ");");
out.println("\t\tif (clazz == NULL) {");
out.println("\t\t\tJRI_ThrowNew(env, JRI_FindClass(env, \"java/lang/ClassNotFoundException\"), classname_"
+ clazzCName + ");");
out.println("\t\t\treturn NULL;");
out.println("\t\t}");
for (i = 0; i < clazz.fields.length; i++) {
FieldDef field = clazz.fields[i];
String fname = field.getCName();
out.println("\t\tuse_" + fname + "(env, clazz);");
}
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
String mname = prefix + "_" + method.getCName(i);
out.println("\t\tuse_" + mname + "(env, clazz);");
}
out.println("\t\t_globalclass_" + clazzCName +
" = JRI_NewGlobalRef(env, clazz);");
out.println("\t\treturn clazz;");
out.println("\t}");
out.println("\telse {");
out.println("\t\treturn JRI_GetGlobalRef(env, _globalclass_" + clazzCName
+ ");");
out.println("\t}");
out.println("}\n");
// Generate the unuse_ routine
out.println("JRI_PUBLIC_API(void)\nunuse_"
+ clazzCName + "(JRIEnv* env)\n{");
out.println("\tif (_globalclass_" + clazzCName + " != NULL) {");
out.println("\t\tstruct java_lang_Class* clazz = JRI_GetGlobalRef(env, _globalclass_"
+ clazzCName + ");");
for (i = 0; i < clazz.fields.length; i++) {
FieldDef field = clazz.fields[i];
String fname = field.getCName();
out.println("\t\tunuse_" + fname + "(env, clazz);");
}
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
String mname = prefix + "_" + method.getCName(i);
out.println("\t\tunuse_" + mname + "(env, clazz);");
}
out.println("\t\tJRI_DisposeGlobalRef(env, _globalclass_" + clazzCName + ");");
out.println("\t\t_globalclass_" + clazzCName + " = NULL;");
out.println("\t\tclazz = NULL; /* prevent unused variable 'clazz' warning */");
out.println("\t}");
out.println("}\n");
out.println("#endif /* UNUSED_use_" + clazzCName + " */\n");
out.println("#ifdef _implementing_" + clazzCName + "\n");
// Generate the register_ routine
out.println("JRI_PUBLIC_API(struct java_lang_Class*)\nregister_"
+ clazzCName + "(JRIEnv* env)\n{");
out.println("\tchar* nativeNamesAndSigs[] = {");
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
if (method.hasAccess(ClassFileParser.ACC_NATIVE)) {
out.println("\t\t\"" + method.name + method.signature + "\",");
}
}
out.println("\t\tNULL"); /* trailing terminator */
out.println("\t};");
out.println("\tvoid* nativeProcs[] = {");
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
String mname = prefix + "_" + method.getCName(i);
if (method.hasAccess(ClassFileParser.ACC_NATIVE)) {
out.println("\t\t(void*)native_" + mname + ",");
}
}
out.println("\t\tNULL"); /* trailing terminator */
out.println("\t};");
out.println("\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_"
+ clazzCName + ");");
out.println("\tif (clazz == NULL) {");
out.println("\t\tJRI_ThrowNew(env, JRI_FindClass(env, \"java/lang/ClassNotFoundException\"), classname_"
+ clazzCName + ");");
out.println("\t\treturn NULL;");
out.println("\t}");
out.println("\tJRI_RegisterNatives(env, clazz, nativeNamesAndSigs, nativeProcs);");
out.println("\tuse_" + clazzCName + "(env);");
out.println("\treturn clazz;");
out.println("}\n");
// Generate the unregister_ routine
out.println("JRI_PUBLIC_API(void)\nunregister_" + clazzCName + "(JRIEnv* env)\n{");
out.println("\tstruct java_lang_Class* clazz = JRI_FindClass(env, classname_"
+ clazzCName + ");");
out.println("\tJRI_UnregisterNatives(env, clazz);");
out.println("\tunuse_" + clazzCName + "(env);");
out.println("}\n");
out.println("#endif /* _implementing_" + clazzCName + " */\n");
out.println("/* These stub routines are generated for compatibility with the JDK: */\n");
out.println("#ifndef NO_JDK\n");
for (i = 0; i < clazz.methods.length; i++) {
MethodDef method = clazz.methods[i];
if (method.hasAccess(ClassFileParser.ACC_NATIVE)) {
String mname = prefix + "_" + method.getCName(i);
String sig = method.signature;
method.describe(out);
out.println("JRI_PUBLIC_API(JRI_JDK_stack_item*)");
out.println("Java_" + mname + "_stub(JRI_JDK_stack_item* _P_, JRIEnv* _EE_) {");
byte resultIndex = MemberDef.getSigType(sig.charAt(method.getResultIndex()));
switch (resultIndex) {
case MemberDef.TYPE_BOOLEAN:
printNativeInvocation(method, mname,
"\t_P_[0].i = ");
out.println(" ? 1 : 0;\n\treturn _P_ + 1;");
break;
case MemberDef.TYPE_BYTE:
case MemberDef.TYPE_CHAR:
case MemberDef.TYPE_SHORT:
case MemberDef.TYPE_INT:
printNativeInvocation(method, mname,
"\t_P_[0].i = ");
out.println(";\n\treturn _P_ + 1;");
break;
case MemberDef.TYPE_LONG:
out.println("\tJRI_JDK_Java8 _tval;");
printNativeInvocation(method, mname,
"\tJRI_SET_INT64(_tval, _P_, ");
out.println(");");
out.println("\treturn _P_ + 2;");
break;
case MemberDef.TYPE_FLOAT:
printNativeInvocation(method, mname,
"\t_P_[0].f = ");
out.println(";\n\treturn _P_ + 1;");
break;
case MemberDef.TYPE_DOUBLE:
out.println("\tJRI_JDK_Java8 _tval;");
printNativeInvocation(method, mname,
"\tJRI_SET_DOUBLE(_tval, _P_, ");
out.println(");");
out.println("\treturn _P_ + 2;");
break;
case MemberDef.TYPE_VOID:
printNativeInvocation(method, mname, "\t(void)");
out.println(";\n\treturn _P_;");
break;
case MemberDef.TYPE_CLASS:
case MemberDef.TYPE_ARRAY:
printNativeInvocation(method, mname,
"\t_P_[0].p = ");
out.println(";\n\treturn _P_ + 1;");
break;
default:
throw new IOException("Unsupported return type: " + resultIndex);
}
out.println("}\n");
}
}
out.println("#endif /* NO_JDK */\n");
}
void printNativeInvocation(MethodDef method, String mname,
String assignment)
throws IOException {
boolean isStatic = method.hasAccess(ClassFileParser.ACC_STATIC);
String sig = method.signature;
int i = 1;
char c;
int argn = isStatic ? 0 : 1;
StringBuffer argList = new StringBuffer();
StringBuffer declList = new StringBuffer();
while ((c = sig.charAt(i++)) != ClassFileParser.SIG_ENDMETHOD) {
byte index = MemberDef.getSigType(c);
switch (index) {
case MemberDef.TYPE_BOOLEAN:
argList.append(", (_P_[" + argn + "].i ? 1 : 0)");
break;
case MemberDef.TYPE_BYTE:
case MemberDef.TYPE_CHAR:
case MemberDef.TYPE_SHORT:
case MemberDef.TYPE_INT:
argList.append(", _P_[" + argn + "].i");
break;
case MemberDef.TYPE_LONG:
declList.append("\tJRI_JDK_Java8 _t" + argn + ";\n");
argList.append(", JRI_GET_INT64(_t" + argn + ", _P_+" + argn + ")");
argn++;
break;
case MemberDef.TYPE_FLOAT:
argList.append(", _P_[" + argn + "].f");
break;
case MemberDef.TYPE_DOUBLE:
declList.append("\tJRI_JDK_Java8 _t" + argn + ";\n");
argList.append(", JRI_GET_DOUBLE(_t" + argn + ", _P_+" + argn + ")");
argn++;
break;
case MemberDef.TYPE_VOID:
argList.append(", _P_[" + argn + "].p");
break;
case MemberDef.TYPE_CLASS:
while (sig.charAt(i++) != ClassFileParser.SIG_ENDCLASS);
argList.append(", _P_[" + argn + "].p");
break;
case MemberDef.TYPE_ARRAY:
while (sig.charAt(i) == ClassFileParser.SIG_ARRAY) i++;
if (sig.charAt(i++) == ClassFileParser.SIG_CLASS)
while (sig.charAt(i++) != ClassFileParser.SIG_ENDCLASS);
argList.append(", _P_[" + argn + "].p");
break;
default:
throw new IOException("Unsupported argument type: " + index);
}
argn++;
}
out.print(declList);
out.print(assignment);
out.print("native_" + mname + "(");
if (isStatic)
out.print("_EE_, class_" + clazzCName + "(_EE_)");
else
out.print("_EE_, _P_[0].p");
out.print(argList);
out.print(")");
}
}