001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package runtime;
028:
029: import components.*;
030: import vm.*;
031: import jcc.Util;
032: import jcc.Const;
033: import jcc.EVMConst;
034: import util.*;
035: import java.util.*;
036: import java.io.OutputStream;
037:
038: /*
039: * Generate natives table for VM.
040: */
041:
042: public class CLDC_HI_NativesWriter implements CoreImageWriter, Const,
043: EVMConst {
044: /*
045: * Natives in the VM can be invoked in two ways -- as a "native" or as an
046: * "entry". Most methods are of the "native" type, unless specified in the
047: * following table.
048: *
049: * Note [1] that a method can be both "native" and "entry". Example:
050: * java.lang.System.arraycopy().
051: * Note [2] a "entry" method doesn't necessarily have the ACC_NATIVE
052: * flag -- the VM may try to execute a simple version of the
053: * method in "entry" code. If that fails, it will revert back
054: * to the Java implementation. Example: java.lang.String.compareTo
055: */
056: static String SYSTEM = "java/lang/System";
057: static String STRING = "java/lang/String";
058: static String MATH = "java/lang/Math";
059: static String VECTOR = "java/util/Vector";
060: static String STRINGBUFFER = "java/lang/StringBuffer";
061: static String INTEGER = "java/lang/Integer";
062: static String JVM = "com/sun/cldchi/jvm/JVM";
063:
064: static String[][] use_entries = {
065: // class method signature(null=any) entry_name
066: { SYSTEM, "arraycopy", null,
067: "native_system_arraycopy_entry", "also-native" },
068: { STRING, "charAt", null, "native_string_charAt_entry" },
069: { STRING, "<init>", "(Ljava/lang/StringBuffer;)V",
070: "native_string_init_entry" },
071: { STRING, "equals", null, "native_string_equals_entry" },
072: { STRING, "indexOf", "(Ljava/lang/String;I)I",
073: "native_string_indexof_string_entry" },
074: { STRING, "indexOf", "(Ljava/lang/String;)I",
075: "native_string_indexof0_string_entry" },
076: { STRING, "indexOf", "(II)I", "native_string_indexof_entry" },
077: { STRING, "indexOf", "(I)I", "native_string_indexof0_entry" },
078: { STRING, "startsWith", "(Ljava/lang/String;I)Z",
079: "native_string_startsWith_entry" },
080: { STRING, "startsWith", "(Ljava/lang/String;)Z",
081: "native_string_startsWith0_entry" },
082: { STRING, "endsWith", null, "native_string_endsWith_entry" },
083: { STRING, "substring", "(I)Ljava/lang/String;",
084: "native_string_substringI_entry" },
085: { STRING, "substring", "(II)Ljava/lang/String;",
086: "native_string_substringII_entry" },
087: { STRING, "valueOf", "(I)Ljava/lang/String;",
088: "native_integer_toString_entry" },
089: { VECTOR, "elementAt", "(I)Ljava/lang/Object;",
090: "native_vector_elementAt_entry" },
091: { VECTOR, "addElement", "(Ljava/lang/Object;)V",
092: "native_vector_addElement_entry" },
093: { STRINGBUFFER, "append", "(C)Ljava/lang/StringBuffer;",
094: "native_stringbuffer_append_entry" },
095: { INTEGER, "toString", "(I)Ljava/lang/String;",
096: "native_integer_toString_entry" },
097: { MATH, "sin", "(D)D", "native_math_sin_entry" },
098: { MATH, "cos", "(D)D", "native_math_cos_entry" },
099: { MATH, "tan", "(D)D", "native_math_tan_entry" },
100: { MATH, "sqrt", "(D)D", "native_math_sqrt_entry" },
101: { MATH, "ceil", "(D)D", "native_math_ceil_entry" },
102: { MATH, "floor", "(D)D", "native_math_floor_entry" },
103: { JVM, "unchecked_byte_arraycopy", null,
104: "native_jvm_unchecked_byte_arraycopy_entry" },
105: { JVM, "unchecked_char_arraycopy", null,
106: "native_jvm_unchecked_char_arraycopy_entry" },
107: { JVM, "unchecked_int_arraycopy", null,
108: "native_jvm_unchecked_int_arraycopy_entry" },
109: { JVM, "unchecked_long_arraycopy", null,
110: "native_jvm_unchecked_long_arraycopy_entry" },
111: { JVM, "unchecked_obj_arraycopy", null,
112: "native_jvm_unchecked_obj_arraycopy_entry" } };
113:
114: /* INSTANCE DATA */
115: protected String outputFileName;
116: protected Exception failureMode = null; // only interesting on failure
117:
118: CCodeWriter out;
119:
120: protected vm.VMClassFactory classMaker = new vm.EVMClassFactory();
121:
122: boolean formatError;
123:
124: public CLDC_HI_NativesWriter() {
125: }
126:
127: public void init(boolean classDebug,
128: ClassnameFilterList nativeTypes, boolean verbose,
129: int maxSegmentSize) {
130: }
131:
132: public boolean setAttribute(String attribute) {
133: return false;
134: }
135:
136: public boolean open(String filename) {
137: if (out != null) {
138: close();
139: }
140: outputFileName = filename;
141: if (filename == null) {
142: out = new CCodeWriter(System.out);
143: } else {
144: try {
145: OutputStream os = new java.io.FileOutputStream(filename);
146: out = new CCodeWriter(os);
147: } catch (java.io.IOException e) {
148: failureMode = e;
149: return false;
150: }
151: }
152: return true;
153: }
154:
155: public void close() {
156: if (out != null) {
157: out.close();
158: outputFileName = null;
159: out = null;
160: }
161: }
162:
163: public boolean writeClasses(ConstantPool consts) {
164: return writeClasses(consts, null);
165: }
166:
167: public void printError(java.io.PrintStream o) {
168: if (failureMode != null) {
169: failureMode.printStackTrace(o);
170: } else {
171: if (out != null && out.checkError())
172: o.println(outputFileName + ": Output write error");
173: }
174: }
175:
176: public boolean writeClasses(ConstantPool consts,
177: ConstantPool sharedconsts) {
178: ClassClass classes[] = ClassClass.getClassVector(classMaker);
179: ClassClass.setTypes();
180:
181: // write out some constant pool stuff here,
182: writeProlog();
183:
184: try {
185: writeAllNativeTables(classes);
186: } catch (RuntimeException e) {
187: out.flush();
188: System.out.println(e);
189: e.printStackTrace(System.out);
190: formatError = true;
191: }
192: writeEpilog();
193: return (!formatError) && (!out.checkError());
194: }
195:
196: int checkEntry(EVMClass cc, MethodInfo mi) {
197: for (int i = 0; i < use_entries.length; i++) {
198: if (cc.ci.className.equals(use_entries[i][0])
199: && mi.name.string.equals(use_entries[i][1])) {
200: if (use_entries[i][2] == null) {
201: return i;
202: }
203: if (mi.type.string.equals(use_entries[i][2])) {
204: return i;
205: }
206: }
207: }
208: return -1;
209: }
210:
211: boolean isNativeFunc(EVMClass cc, MethodInfo mi) {
212: int entry;
213: entry = checkEntry(cc, mi);
214: if (entry < 0 || use_entries[entry].length > 4) {
215: return true;
216: } else {
217: return false;
218: }
219: }
220:
221: boolean isEntryFunc(EVMClass cc, MethodInfo mi) {
222: int entry;
223: entry = checkEntry(cc, mi);
224: if (entry >= 0) {
225: return true;
226: } else {
227: return false;
228: }
229: }
230:
231: boolean isNativeOrEntryFunc(EVMClass cc, MethodInfo mi) {
232: if ((mi.access & Const.ACC_NATIVE) != 0) {
233: return true;
234: } else {
235: return isEntryFunc(cc, mi);
236: }
237: }
238:
239: void sortClasses(ClassClass classes[]) {
240: ArrayList list = new ArrayList();
241: for (int i = 0; i < classes.length; i++) {
242: list.add(classes[i]);
243: }
244: Collections.sort(list, new Comparator() {
245: public int compare(Object o1, Object o2) {
246: ClassClass c1 = (ClassClass) o1;
247: ClassClass c2 = (ClassClass) o2;
248:
249: return c1.ci.className.compareTo(c2.ci.className);
250: }
251: });
252: for (int i = 0; i < list.size(); i++) {
253: classes[i] = (ClassClass) list.get(i);
254: }
255: }
256:
257: void sortMethods(EVMMethodInfo methods[]) {
258: ArrayList list = new ArrayList();
259: for (int i = 0; i < methods.length; i++) {
260: list.add(methods[i]);
261: }
262: Collections.sort(list, new Comparator() {
263: public int compare(Object o1, Object o2) {
264: MethodInfo m1 = ((EVMMethodInfo) o1).method;
265: MethodInfo m2 = ((EVMMethodInfo) o2).method;
266:
267: int n = m1.name.string.compareTo(m2.name.string);
268: if (n != 0) {
269: return n;
270: } else {
271: return m1.type.string.compareTo(m2.type.string);
272: }
273: }
274: });
275: for (int i = 0; i < list.size(); i++) {
276: methods[i] = (EVMMethodInfo) list.get(i);
277: }
278: }
279:
280: protected void writeAllNativeTables(ClassClass classes[]) {
281: sortClasses(classes);
282: Vector nativeClasses = new Vector();
283:
284: // (1) Write all the function declarations
285: for (int i = 0; i < classes.length; i++) {
286: boolean classHasNatives = false;
287: EVMClass cc = (EVMClass) classes[i];
288: if (cc.isPrimitiveClass() || cc.isArrayClass()) {
289: continue;
290: }
291: EVMMethodInfo m[] = cc.methods;
292: sortMethods(m);
293: int nmethod = (m == null) ? 0 : m.length;
294: for (int j = 0; j < nmethod; j++) {
295: EVMMethodInfo meth = m[j];
296: MethodInfo mi = meth.method;
297: if (!isNativeOrEntryFunc(cc, mi)) {
298: continue;
299: }
300: if (!classHasNatives) {
301: classHasNatives = true;
302: nativeClasses.addElement(cc);
303: }
304: int entry;
305: entry = checkEntry(cc, mi);
306: if (entry < 0 || use_entries[entry].length > 4) {
307: // This is a "native"
308: out.println("extern \"C\" " + mi.getJNIReturnType()
309: + " " + mi.getNativeName(true) + "();");
310: }
311: if (entry >= 0) {
312: // This is an "entry" (could also be a "native")
313: out.println("extern \"C\" void "
314: + use_entries[entry][3] + "();");
315: }
316: }
317: }
318: out.println();
319: out.println();
320:
321: // (2) Write all the "_natives[]" and "_entries[]" tables for
322: // individual classes
323:
324: for (Enumeration e = nativeClasses.elements(); e
325: .hasMoreElements();) {
326: EVMClass cc = (EVMClass) e.nextElement();
327: EVMMethodInfo m[] = cc.methods;
328: int nmethod = (m == null) ? 0 : m.length;
329: int num_native_methods = 0;
330: int num_entry_methods = 0;
331:
332: for (int j = 0; j < nmethod; j++) {
333: EVMMethodInfo meth = m[j];
334: MethodInfo mi = meth.method;
335: if (!isNativeOrEntryFunc(cc, mi)) {
336: continue;
337: }
338: if (isNativeFunc(cc, mi)) {
339: num_native_methods++;
340: }
341: if (isEntryFunc(cc, mi)) {
342: num_entry_methods++;
343: }
344: }
345:
346: // Write the "_natives[]" struct
347: if (num_native_methods > 0) {
348: out.println("static const JvmNativeFunction "
349: + cc.getNativeName() + "_natives[] = " + "{");
350: for (int j = 0; j < nmethod; j++) {
351: EVMMethodInfo meth = m[j];
352: MethodInfo mi = meth.method;
353: if (!isNativeOrEntryFunc(cc, mi)) {
354: continue;
355: }
356: if (isNativeFunc(cc, mi)) {
357: out.print(pad(" JVM_NATIVE(\""
358: + mi.name.string + "\",", 30));
359: out.print(pad("\"" + mi.type.string + "\", ",
360: 25));
361: out.println(mi.getNativeName(true) + "),");
362: }
363: }
364: out.println(" {(char*)0, (char*)0, (void*)0}");
365: out.println("};");
366: out.println();
367: }
368:
369: // Write the "_entries[]" struct
370: if (num_entry_methods > 0) {
371: out.println("static const JvmNativeFunction "
372: + cc.getNativeName() + "_entries[] = " + "{");
373: for (int j = 0; j < nmethod; j++) {
374: EVMMethodInfo meth = m[j];
375: MethodInfo mi = meth.method;
376: if (!isNativeOrEntryFunc(cc, mi)) {
377: continue;
378: }
379: int entry;
380: if ((entry = checkEntry(cc, mi)) >= 0) {
381: out.print(" JVM_ENTRY(\"" + mi.name.string
382: + "\","
383: + spaces(20 - mi.name.string.length()));
384: out.print("\"" + mi.type.string + "\", ");
385: out.println(use_entries[entry][3] + "),");
386: }
387: }
388: out.println(" {(char*)0, (char*)0, (void*)0}");
389: out.println("};");
390: out.println();
391: }
392: }
393:
394: // (3) Write the top-level table
395:
396: out.println("const JvmNativesTable jvm_natives_table[] = {");
397:
398: for (Enumeration e = nativeClasses.elements(); e
399: .hasMoreElements();) {
400: EVMClass cc = (EVMClass) e.nextElement();
401: String className = cc.ci.className;
402: out.println(" JVM_TABLE(\"" + className + "\",");
403: EVMMethodInfo m[] = cc.methods;
404: int nmethod = (m == null) ? 0 : m.length;
405:
406: int num_native_methods = 0;
407: int num_entry_methods = 0;
408:
409: for (int j = 0; j < nmethod; j++) {
410: EVMMethodInfo meth = m[j];
411: MethodInfo mi = meth.method;
412: if (!isNativeOrEntryFunc(cc, mi)) {
413: continue;
414: }
415: if (isNativeFunc(cc, mi)) {
416: num_native_methods++;
417: }
418: if (isEntryFunc(cc, mi)) {
419: num_entry_methods++;
420: }
421: }
422:
423: if (num_native_methods > 0) {
424: out.println(spaces(40) + cc.getNativeName()
425: + "_natives,");
426: } else {
427: out.println(spaces(40) + "(JvmNativeFunction*)0,");
428: }
429: if (num_entry_methods > 0) {
430: out.println(spaces(40) + cc.getNativeName()
431: + "_entries),");
432: } else {
433: out.println(spaces(40) + "(JvmNativeFunction*)0),");
434: }
435: }
436: out.println(" JVM_TABLE((char*)0, (JvmNativeFunction*)0, "
437: + "(JvmNativeFunction*)0)");
438: out.println("};");
439:
440: // (4) Write the jvm_native_execution_top-level table
441:
442: out.println("const JvmExecutionEntry jvm_api_entries[] = {");
443: for (Enumeration e = nativeClasses.elements(); e
444: .hasMoreElements();) {
445: EVMClass cc = (EVMClass) e.nextElement();
446: EVMMethodInfo m[] = cc.methods;
447: int nmethod = (m == null) ? 0 : m.length;
448:
449: for (int j = 0; j < nmethod; j++) {
450: EVMMethodInfo meth = m[j];
451: MethodInfo mi = meth.method;
452: int index;
453: if ((index = checkEntry(cc, mi)) >= 0) {
454: String entryName = use_entries[index][3];
455: out.println("{(unsigned char*)&" + entryName + ",");
456: out.println("(char*)\"" + entryName + "\"},");
457: }
458: }
459: }
460: out.println("{(unsigned char*)0, (char*)0}};");
461: }
462:
463: String pad(String str, int width) {
464: int len = str.length();
465: if (len < width) {
466: return str + spaces(width - len);
467: } else {
468: return str;
469: }
470: }
471:
472: protected void writeProlog() {
473: out.println("/* This is a generated file. Do not modify.");
474: out.println(" * Generated on " + new java.util.Date());
475: out.println(" */");
476: out.println();
477: out.println("/*");
478: out.println(" *");
479: out
480: .println(" * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.");
481: out
482: .println(" * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER");
483: out.println(" * ");
484: out
485: .println(" * This program is free software; you can redistribute it and/or");
486: out
487: .println(" * modify it under the terms of the GNU General Public License version");
488: out
489: .println(" * 2 only, as published by the Free Software Foundation.");
490: out.println(" * ");
491: out
492: .println(" * This program is distributed in the hope that it will be useful, but");
493: out
494: .println(" * WITHOUT ANY WARRANTY; without even the implied warranty of");
495: out
496: .println(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU");
497: out
498: .println(" * General Public License version 2 for more details (a copy is");
499: out.println(" * included at /legal/license.txt).");
500: out.println(" * ");
501: out
502: .println(" * You should have received a copy of the GNU General Public License");
503: out
504: .println(" * version 2 along with this work; if not, write to the Free Software");
505: out
506: .println(" * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA");
507: out.println(" * 02110-1301 USA");
508: out.println(" * ");
509: out
510: .println(" * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa");
511: out
512: .println(" * Clara, CA 95054 or visit www.sun.com if you need additional");
513: out.println(" * information or have any questions.");
514: out.println(" */");
515: out.println();
516: out.println("#include \"jvmconfig.h\"");
517: out.println("#if !defined(ROMIZING) || !defined(PRODUCT)");
518: out.println("#include \"NativesTable.hpp\"");
519: out.println("#include \"kni.h\"");
520: out.println();
521: out.println();
522: }
523:
524: protected void writeEpilog() {
525: out.println();
526: out.println("#endif");
527: }
528:
529: public void printSpaceStats(java.io.PrintStream stream) {
530: }
531:
532: private String spaces(int length) {
533: if (length <= 1) {
534: return " ";
535: }
536: if (length <= 10) {
537: return " ".substring(0, length);
538: } else {
539: return spaces(10) + spaces(length - 10);
540: }
541: }
542:
543: private boolean isOverloadedNative(MethodInfo mi) {
544: ClassInfo ci = mi.parent;
545: int nmethods = ci.methods.length;
546: for (int j = 0; j < nmethods; j++) {
547: MethodInfo m = ci.methods[j];
548: if ((m != mi) && ((m.access & Const.ACC_NATIVE) != 0)
549: && (m.name.equals(mi.name))) {
550: return true;
551: }
552: }
553: return false;
554: }
555:
556: }
|