Milán Major

netscape-revival

1 branch
Code

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(")");
    }

}