History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/tools/javal/LimboGen.java (1 of 18352 files). Show all

Unified · Split

java/tools/javal/LimboGen.java+677−0
@@ -0,0 +1,677 @@
1+package javal;
2+
3+import java.io.File;
4+import java.io.DataOutputStream;
5+import java.io.FileOutputStream;
6+import java.io.IOException;
7+
8+import java.lang.reflect.*;
9+
10+
11+public
12+class LimboGen
13+{
14+ public LimboGen( Class cl, Field[] fields, Method[] methods, boolean verbose )
15+ {
16+ theClass = cl;
17+ this.fields = fields;
18+ this.methods = methods;
19+ opt_verbose = verbose;
20+
21+ // create names
22+ String full_name = cl.getName();
23+ base_name = ClassBaseName( full_name );
24+ mod_name = base_name +"_L";
25+ limbo_dotm = mod_name +".m";
26+ limbo_dotb = mod_name +".b";
27+
28+ // some class are "special" to javal
29+ // if it is a special class we don't
30+ // want to generate adt's for it and
31+ // will use a special ADT name
32+ special = true; //assume special
33+ obj_adt = SpecialClass( full_name );
34+
35+ if ( obj_adt == null )
36+ {
37+ special = false;
38+ obj_adt = base_name +"_obj";
39+ }
40+
41+ // will only generate skeleton for native methods
42+ natives = GetNatives( methods );
43+ has_natives = natives.length > 0;
44+
45+ // need to distinguish between instance and static fields
46+ iFields = GetInstanceFields( fields );
47+ sFields = GetStaticFields( fields );
48+ }
49+
50+
51+ /**
52+ * Generate a Limbo Module Declaration
53+ * file (.m) for a java class containing
54+ * native methods.
55+ */
56+ public void DotM() throws IOException
57+ {
58+ // open a file
59+ out = MkFile( limbo_dotm );
60+
61+ // emit the Limbo Module File
62+
63+ Emit( "# generated file edit with care\n\n" );
64+ Emit( mod_name +" : module\n" );
65+ Emit( "{\n" );
66+
67+ GenADT();
68+
69+ Emit( "\n" );
70+
71+ GenFct(false);
72+
73+ Emit( "\n};\n" );
74+
75+ out.close();
76+
77+ if ( merge )
78+ {
79+ // save off existing .m and rename
80+ // tmp to .m
81+ File f = new File( limbo_dotm );
82+ File o = new File("old_"+limbo_dotm);
83+ File t = new File( tmpname );
84+
85+ if ( o.exists() ) o.delete();
86+ f.renameTo( o );
87+ t.renameTo( f );
88+
89+ }
90+
91+ }
92+
93+
94+ /**
95+ * Generate a Limbo Module Implementation
96+ * Skeleton containing native methods for
97+ * a java class.
98+ */
99+ public void DotB() throws IOException
100+ {
101+ // don't generate a .b if no natives
102+ if ( ! has_natives ) return;
103+
104+ // open a file
105+ out = MkFile( limbo_dotb );
106+
107+ // generate file prolog
108+ Emit("implement "+ mod_name +";\n\n" );
109+ Emit("include \"jni.m\";\n" );
110+ Emit(T1+"jni : JNI;\n" );
111+ Emit(T2+"ClassModule,\n");
112+ Emit(T2+ T_JString +",\n");
113+ Emit(T2+ T_JArray +",\n");
114+ Emit(T2+ T_JArrayI +",\n");
115+ Emit(T2+ T_JArrayC +",\n");
116+ Emit(T2+ T_JArrayB +",\n");
117+ Emit(T2+ T_JArrayS +",\n");
118+ Emit(T2+ T_JArrayJ +",\n");
119+ Emit(T2+ T_JArrayF +",\n");
120+ Emit(T2+ T_JArrayD +",\n");
121+ Emit(T2+ T_JArrayZ +",\n");
122+ Emit(T2+ T_JArrayJObject +",\n");
123+ Emit(T2+ T_JArrayJClass +",\n");
124+ Emit(T2+ T_JArrayJString +",\n");
125+ Emit(T2+ T_JClass +",\n");
126+ Emit(T2+T_JObject +" : import jni;\n\n");
127+
128+ Emit("#>> extra pre includes here\n\n#<<\n\n");
129+
130+ Emit("include \""+ limbo_dotm +"\";\n\n" );
131+
132+ Emit("#>> extra post includes here\n\n#<<\n\n");
133+
134+ // generate a skeleton for init() and each native method
135+ GenFct( true );
136+
137+ out.close();
138+
139+ if ( merge )
140+ FileMerge.Merge( limbo_dotb, tmpname );
141+ }
142+
143+
144+ /**
145+ * Generate an ADT declaration for the class
146+ * instance fields.
147+ */
148+ private void GenADT() throws IOException
149+ {
150+ // don't generate an ADT decl for "special" clases
151+ if ( special ) return;
152+
153+ Emit( T1+ obj_adt +" : adt\n"+ T1+ "{\n" );
154+
155+ // emit the std object header
156+ Emit( T2+ "cl_mod : ClassModule;\n" );
157+
158+ // walk through instance data emitting Limbo decl
159+ for( int x=0; x<iFields.length; x++ )
160+ {
161+ Emit( T2+ GenFieldDecl( iFields[x] ) +";\n" );
162+ }
163+
164+ Emit( T1+ "};\n" );
165+ }
166+
167+ private void GenFct( boolean skel ) throws IOException
168+ {
169+ // generate init fct
170+ GenInit( skel );
171+
172+ // walk native methods and generate
173+ // a limbo fct
174+ for( int x=0; x<natives.length; x++ )
175+ {
176+ String fct_name = MkFctName( natives[x] );
177+ String this_param = "";
178+
179+ // if fct is virtual generate implicit this param
180+ if ( ! Modifier.isStatic( natives[x].getModifiers() ) )
181+ {
182+ // if this is a special class then don't use ref
183+ // because the generated special name is already a ref
184+ this_param = ( special ? "this : " : "this : ref " );
185+ this_param += obj_adt;
186+ }
187+
188+ // determine fct parameters
189+ String params = GenFctParams( natives[x].getParameterTypes() );
190+
191+ StringBuffer fct_params = new StringBuffer(80);
192+ if ( this_param != "" )
193+ {
194+ fct_params.append( this_param );
195+ if ( params != "" )
196+ fct_params.append( ", " );
197+ }
198+
199+ fct_params.append( params );
200+
201+ // determine fct return type...if any
202+ String fct_t = LimboType( natives[x].getReturnType() );
203+ if ( ! fct_t.equals("") )
204+ fct_t = " : "+ fct_t;
205+
206+ if ( skel )
207+ {
208+ Emit( fct_name +"( "+
209+ fct_params.toString() +")"+
210+ fct_t +"\n{#>>\n}#<<\n\n" );
211+
212+ }
213+ else
214+ {
215+ Emit( T1+ fct_name +" : fn( "+
216+ fct_params.toString() +")"+
217+ fct_t +";\n" );
218+ }
219+ }
220+ }
221+
222+
223+ /**
224+ * every Limbo Native module has a init()
225+ * function which the loader will call
226+ * when the native mod is loaded. This
227+ * method generates that fct.
228+ *
229+ * @param skel If true gen a fct skel; else fct decl
230+ *
231+ */
232+ private void GenInit( boolean skel ) throws IOException
233+ {
234+ if ( skel )
235+ {
236+ Emit( "init( jni_p : JNI )\n{\n" );
237+ Emit( T1+"# save java native inteface mod instance\n" );
238+ Emit( T1+"jni = jni_p;\n" );
239+ Emit( T1+"#>>extra initialization here\n"+T1+"#<<\n" );
240+ Emit( "}\n\n" );
241+ }
242+ else
243+ {
244+ Emit( T1+"init : fn( jni_p : JNI );\n" );
245+ }
246+ }
247+
248+ /**
249+ * Given an array of types return a string with
250+ * a comma seperated sequence of java method
251+ * parameter declarations
252+ *
253+ * @param ptypes An array of types
254+ *
255+ * @return A string representing method param decls
256+ */
257+ private String GenFctParams( Class[] ptypes )
258+ {
259+ String fct_params = "";
260+ for( int x=0; x<ptypes.length; x++ )
261+ {
262+ fct_params = fct_params +"p"+ x +" : "+ LimboType( ptypes[x] );
263+ if ( x <ptypes.length-1 )
264+ fct_params = fct_params +",";
265+ }
266+
267+ return( fct_params );
268+ }
269+
270+
271+ /**
272+ * Take a Java class data-field and
273+ * return a string with a coresponding
274+ * Limbo adt field declaration.
275+ *
276+ * @param fi The Java field descriptor
277+ *
278+ * @return Limbo Declaration
279+ */
280+ private String GenFieldDecl( Field fi )
281+ {
282+ String fi_name = fi.getName();
283+ Class java_type = fi.getType();
284+
285+ String limbo_type = LimboType( java_type );
286+
287+ return( fi_name +" : "+ limbo_type );
288+ }
289+
290+
291+ /**
292+ * Accept a java Type descriptor and
293+ * return a corresponding limbo type
294+ * as a string. Return a empty string
295+ * if the type is void or an unknown.
296+ *
297+ * @param java_t Java type
298+ *
299+ * @return Limbo type
300+ */
301+ private String LimboType( Class java_t )
302+ {
303+ String limbo_t;
304+
305+ if ( java_t.isPrimitive() )
306+ {
307+ // a java primitive type convert to appropriate limbo type
308+ String t_name = java_t.getName();
309+ if ( t_name.equals( "short" ) ||
310+ t_name.equals( "char" ) ||
311+ t_name.equals( "int" ) )
312+ limbo_t = "int";
313+ else if ( t_name.equals( "long" ) )
314+ limbo_t = "big";
315+ else if ( t_name.equals( "float" ) ||
316+ t_name.equals( "double" ) )
317+ limbo_t = "real";
318+ else if ( t_name.equals( "byte" ) ||
319+ t_name.equals( "boolean" ) )
320+ limbo_t = "byte";
321+ else
322+ limbo_t = ""; // void
323+
324+ }
325+ else
326+ {
327+ // a java reference (i.e. object or array)
328+ String t_name = java_t.getName();
329+
330+ if ( t_name.startsWith( "[" ) )
331+ limbo_t = ArrayType( t_name );
332+ else
333+ limbo_t = ClassName( t_name );
334+ }
335+
336+ return( limbo_t );
337+ }
338+
339+ private String ArrayType( String name )
340+ {
341+ StringBuffer aryname = new StringBuffer(20);
342+ aryname.append( T_JArray );
343+
344+ char let = name.charAt(1);
345+
346+ if ( let == 'L' )
347+ {
348+ // array of some class, determine Limo name
349+ aryname.append( ClassName( name.substring(2, name.length()-1) ) );
350+ }
351+ else if ( let == '[' )
352+ {
353+ // array of array...
354+ // we only care about first level
355+ ;
356+ }
357+ else
358+ aryname.append( name.substring(1) ); //append type
359+
360+ return( aryname.toString() );
361+ }
362+
363+
364+ private String ClassName( String clname )
365+ {
366+ // we treat some classes special and
367+ // use specific Limbo adt's otherwise
368+ // use the generic JObject
369+ String sp_class = SpecialClass( clname );
370+ if ( sp_class != null )
371+ return( sp_class );
372+ else if ( "java.io.FileDescriptor".equals(clname) )
373+ return( T_JFd );
374+ else if ( "inferno.vm.FD".equals(clname) )
375+ return( T_JInfernoFD );
376+ else if ( clname.endsWith( base_name ) )
377+ return( "ref "+ obj_adt );
378+ return( T_JObject );
379+ }
380+
381+
382+ private String SpecialClass( String clname )
383+ {
384+ if ( "java.lang.String".equals(clname) )
385+ return( T_JString );
386+ else if ( "java.lang.Class".equals(clname) )
387+ return( T_JClass );
388+ else if ( "java.lang.Object".equals(clname) )
389+ return( T_JObject );
390+ else
391+ return( null );
392+ }
393+
394+ /**
395+ * Scan methods list and return list of
396+ * native methods.
397+ *
398+ * @return Array of native methods, else array of length 0.
399+ */
400+ private Method[] GetNatives( Method[] methods )
401+ {
402+ // walk the methods array and count natives
403+ int native_count = 0;
404+ for( int x=0; x<methods.length; x++ )
405+ if ( Modifier.isNative( methods[x].getModifiers() ) )
406+ native_count++;
407+
408+ if ( native_count == 0 ) return( new Method[0] );
409+
410+ if ( opt_verbose )
411+ System.out.println( "Native Methods:" );
412+
413+ // now create an array to hold natives and fill it
414+ Method[] natives = new Method[native_count];
415+ native_count = 0;
416+ for( int x=0; x<methods.length; x++ )
417+ if ( Modifier.isNative( methods[x].getModifiers() ) )
418+ {
419+ natives[native_count++] = methods[x];
420+ if ( opt_verbose )
421+ System.out.println( "\t"+ methods[x] );
422+ }
423+
424+ return( natives );
425+ }
426+
427+
428+ /**
429+ * Scan fields list and return list of
430+ * instance fields.
431+ *
432+ * @return Array of instnace fields, else array oflen 0
433+ */
434+ private Field[] GetInstanceFields( Field[] fields )
435+ {
436+ // walk the fields array and count non-statics
437+ int count = 0;
438+ for( int x=0; x<fields.length; x++ )
439+ if ( ! Modifier.isStatic( fields[x].getModifiers() ) )
440+ count++;
441+
442+ if ( count == 0 ) return( new Field[0] );
443+
444+ if ( opt_verbose )
445+ System.out.println( "Instance Fields:" );
446+
447+ // now create an array to hold instance-fields and fill it
448+ Field[] iFields = new Field[count];
449+ count = 0;
450+ for( int x=0; x<fields.length; x++ )
451+ if ( ! Modifier.isStatic( fields[x].getModifiers() ) )
452+ {
453+ iFields[count++] = fields[x];
454+ if ( opt_verbose )
455+ System.out.println( "\t"+ fields[x] );
456+ }
457+
458+ return( iFields );
459+ }
460+
461+
462+ /**
463+ * Scan fields list and return list of
464+ * static fields.
465+ *
466+ * @return Array of static fields, else array oflen 0
467+ */
468+ private Field[] GetStaticFields( Field[] fields )
469+ {
470+ // walk the fields array and count non-statics
471+ int count = 0;
472+ for( int x=0; x<fields.length; x++ )
473+ if ( Modifier.isStatic( fields[x].getModifiers() ) )
474+ count++;
475+
476+ if ( count == 0 ) return( new Field[0] );
477+
478+ if ( opt_verbose )
479+ System.out.println( "Instance Fields:" );
480+
481+ // now create an array to hold instance-fields and fill it
482+ Field[] sFields = new Field[count];
483+ count = 0;
484+ for( int x=0; x<fields.length; x++ )
485+ if ( Modifier.isStatic( fields[x].getModifiers() ) )
486+ {
487+ sFields[count++] = fields[x];
488+ if ( opt_verbose )
489+ System.out.println( "\t"+ fields[x] );
490+ }
491+
492+ return( sFields );
493+ }
494+
495+
496+ private String ClassBaseName( String name )
497+ {
498+ // for java.lang.Object return Object
499+ // if last char is ';' strip it off (arrays)
500+
501+ int start = name.lastIndexOf( '.' );
502+ int end = name.lastIndexOf( ';' );
503+
504+ // if neither found return name
505+ if ( (start == -1) && (end==-1) ) return( name );
506+
507+ // adjust if ';' not found
508+ end = ( (end==-1)? name.length() : end );
509+
510+ return( name.substring( start+1, end ) );
511+ }
512+
513+
514+ private String MkFctName( Method meth )
515+ {
516+ // build name from java method name
517+ // java method param types, and the
518+ // java method return type
519+
520+ StringBuffer encode = new StringBuffer(50);
521+ encode.append(meth.getName());
522+
523+ // append parmeter encoding
524+ Class[] jparam = meth.getParameterTypes();
525+ for( int x=0; x<jparam.length; x++ )
526+ {
527+ encode.append( "_" );
528+ encode.append( JTypeEncode( jparam[x] ) );
529+ }
530+
531+ // append the method return type encoding
532+ encode.append("_");
533+ encode.append( JTypeEncode( meth.getReturnType() ) );
534+
535+ if ( opt_verbose )
536+ System.out.println( "--mangled fct name:"+ encode );
537+
538+ return( encode.toString() );
539+ }
540+
541+
542+ private String JTypeEncode( Class jtype )
543+ {
544+ String t_name; //types name
545+ String encode = ""; //limbo encoding
546+
547+ if ( jtype.isPrimitive() )
548+ {
549+ // a java primitive type convert to appropriate limbo type
550+ t_name = jtype.getName();
551+
552+ // determine
553+ if ( t_name.equals( "int" ) )
554+ encode = "I";
555+ else if ( t_name.equals( "char" ) )
556+ encode = "C";
557+ else if ( t_name.equals( "short" ) )
558+ encode = "S";
559+ else if ( t_name.equals( "long" ) )
560+ encode = "J";
561+ else if ( t_name.equals( "boolean" ) )
562+ encode = "Z";
563+ else if ( t_name.equals( "byte" ) )
564+ encode = "B";
565+ else if ( t_name.equals( "float" ) )
566+ encode = "F";
567+ else if ( t_name.equals( "double" ) )
568+ encode = "D";
569+ else
570+ encode = "V";
571+ }
572+ else
573+ {
574+ // a java reference (i.e. object or array)
575+ t_name = jtype.getName();
576+
577+ if ( t_name.indexOf( '[' ) == -1 )
578+ {
579+ // just an object reference
580+ encode = "r"+ ClassBaseName( t_name );
581+ }
582+ else
583+ {
584+ // array
585+ int x=0;
586+ StringBuffer buf = new StringBuffer(40);
587+ while( t_name.charAt(x)== '[' )
588+ {
589+ buf.append('a');
590+ x++;
591+ }
592+ if ( t_name.charAt(x) == 'L' )
593+ buf.append( ClassBaseName(t_name.substring(x+1)) );
594+ else
595+ buf.append( t_name.substring(x) );
596+ encode = buf.toString();
597+ }
598+ }
599+
600+ return( encode );
601+ }
602+
603+
604+ private DataOutputStream MkFile( String name ) throws IOException
605+ {
606+ File f = new File( name );
607+ FileOutputStream fout;
608+
609+ tmpname = "tmp_"+ name;
610+
611+ if ( f.exists() )
612+ {
613+ fout = new FileOutputStream( tmpname );
614+ merge = true;
615+ }
616+ else
617+ fout = new FileOutputStream( name );
618+
619+ return( new DataOutputStream( fout ) );
620+ }
621+
622+ private void Emit( String info ) throws IOException
623+ {
624+ out.writeBytes( info );
625+ }
626+
627+
628+ // data fields
629+ private String base_name; // name of class
630+ private String mod_name; // module name of native "peer" module
631+ private String limbo_dotm; // name of limbo module decl .m file
632+ private String limbo_dotb; // name of limbo module impl .b file
633+ private String obj_adt; // adt describing objects instance fields
634+ private boolean special; // set true if a special class; a special
635+ // class is one known to this tool.
636+
637+ Class theClass; // class descriptor object
638+
639+ DataOutputStream out; // current gen output file
640+ boolean merge = false; // merge old and new gen'ed files
641+ String tmpname;
642+
643+ Method[] methods; // all methods
644+ Method[] natives; // native methods
645+
646+ Field[] fields; // all fields
647+ Field[] iFields; // instance fields
648+ Field[] sFields; // static fields
649+
650+ boolean opt_verbose; // print stuff if true
651+ boolean has_natives; // set true if class has native methods
652+
653+ // consts
654+ private static final String T1 = " ";
655+ private static final String T2 = " ";
656+ private static final String T3 = " ";
657+
658+ // generated Limbo/Java type names
659+ private static final String T_JObject = "JObject";
660+ private static final String T_JString = "JString";
661+ private static final String T_JClass = "JClass";
662+ private static final String T_JArrayI = "JArrayI";
663+ private static final String T_JArrayC = "JArrayC";
664+ private static final String T_JArrayS = "JArrayS";
665+ private static final String T_JArrayB = "JArrayB";
666+ private static final String T_JArrayJ = "JArrayJ";
667+ private static final String T_JArrayF = "JArrayF";
668+ private static final String T_JArrayD = "JArrayD";
669+ private static final String T_JArrayZ = "JArrayZ";
670+ private static final String T_JArrayJObject = "JArrayJObject";
671+ private static final String T_JArrayJClass = "JArrayJClass";
672+ private static final String T_JArrayJString = "JArrayJString";
673+ private static final String T_JArray = "JArray";
674+ private static final String T_JFd = "ref FileDescriptor_obj";
675+ private static final String T_JInfernoFD = "ref Sys->FD";
676+
677+}