This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Java compiler patch: compile resource files into executables



I've added a new compiling mode to gcj for compiling resource files
into .o files.  These resource files can be any kind of file.  These
files are then accessible to java programs with a new protocol called
`core'.  They are identified using core:/ URLs.  Here's an example...

gcj -R poppy.bird -o poppy.o -c myresource.txt

This generates an object file, poppy.o, from the input file
myresource.txt, and is given the name "poppy.bird".  Programs can
refer to this in-memory resource with the URL "core:/poppy/bird" (or
"core:///poppy/bird", etc).

If we arrange for "core:/" to be on the java.class.path, then the
runtime will be in a position to find system resources like property
files compiled into the program image.  This is very important for
gcj.

Here's a program that prints out its own source...

$ make
gcj -R source -o source.o -c CoreTest.java
gcj --main=CoreTest -o CoreTest CoreTest.java source.o
$ ./CoreTest
import java.io.*;
import java.net.*;

public class CoreTest
{
  public static void main (String[] args)
  {
    try {
      URL u = new URL("core:/source");
      LineNumberReader lnr =
	new LineNumberReader
	  (new InputStreamReader
	    (u.openConnection ().getInputStream ()));
      
      while (true)
	{
	  String s = lnr.readLine ();
	  
	  if (s != null)
	    System.out.println (s);
	  else
	    return;
	}
    } catch (Exception e) {
      e.printStackTrace ();
    }
  }
}


This is the compiler part of the patch.  I'll send the runtime patch in another mail. 


Sun Sep  2 17:05:59 2001  Anthony Green  <green@redhat.com>

	* class.c (O_BINARY): Define if necessary.
	(registerResource_libfunc): Declare.
	(init_class_processing): Initilize registerResource_libfunc.
	(compile_resource_file): New function.
	* java-tree.h (resouce_name): Declare.
	* jcf-parse.c (yyparse): Handle compiling java resource files.
	* lang.c (java_decode_option): Handle -fcompile-resource option.
	* jvspec.c (lang_specific_driver): Handle -R flag for compiling
	resource files.
	* gcj.texi (Code Generation): Add documentation for -R flag.

Index: gcc/java/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/class.c,v
retrieving revision 1.112
diff -u -p -r1.112 class.c
--- class.c	2001/08/31 20:07:31	1.112
+++ class.c	2001/09/03 00:35:16
@@ -38,8 +38,14 @@ The Free Software Foundation is independ
 #include "parse.h"
 #include "function.h"
 #include "ggc.h"
+#include "stdio.h"
 #include "target.h"
 
+/* DOS brain-damage */
+#ifndef O_BINARY
+#define O_BINARY 0 /* MS-DOS brain-damage */
+#endif
+
 static tree make_method_value PARAMS ((tree));
 static tree build_java_method_type PARAMS ((tree, tree, int));
 static int32 hashUtf8String PARAMS ((const char *, int));
@@ -53,6 +59,7 @@ static struct hash_entry *init_test_hash
 							  struct hash_table *,
 							  hash_table_key));
 static rtx registerClass_libfunc;
+static rtx registerResource_libfunc;
 
 extern struct obstack permanent_obstack;
 struct obstack temporary_obstack;
@@ -832,6 +839,109 @@ hashUtf8String (str, len)
   return hash;
 }
 
+/* Generate a byte array representing the contents of FILENAME.  The
+   array is assigned a unique local symbol.  The array represents a
+   compiled Java resource, which is accessed by the runtime using
+   NAME.  
+*/
+void
+compile_resource_file (char *name, char *filename)
+{
+  struct stat stat_buf;
+  int fd;
+  char *buffer;
+  char buf[60];
+  tree rtype, field = NULL_TREE, data_type, rinit, data, decl;
+  static int Jr_count = 0;
+
+  fd = open (filename, O_RDONLY | O_BINARY);
+  if (fd < 0)
+    {
+      perror ("Failed to read resource file");
+      return;
+    }
+  if (fstat (fd, &stat_buf) != 0
+      || ! S_ISREG (stat_buf.st_mode))
+    {
+      perror ("Could not figure length of resource file");
+      return;
+    }
+  buffer = xmalloc (strlen (name) + stat_buf.st_size);
+  strcpy (buffer, name);
+  read (fd, buffer + strlen (name), stat_buf.st_size);
+  close (fd);
+  data_type = build_prim_array_type (unsigned_byte_type_node,
+				     strlen (name) + stat_buf.st_size);
+  rtype = make_node (RECORD_TYPE);
+  PUSH_FIELD (rtype, field, "name_length", unsigned_int_type_node);
+  PUSH_FIELD (rtype, field, "resource_length", unsigned_int_type_node);
+  PUSH_FIELD (rtype, field, "data", data_type);
+  FINISH_RECORD (rtype);
+  START_RECORD_CONSTRUCTOR (rinit, rtype);
+  PUSH_FIELD_VALUE (rinit, "name_length", 
+		    build_int_2 (strlen (name), 0));
+  PUSH_FIELD_VALUE (rinit, "resource_length", 
+		    build_int_2 (stat_buf.st_size, 0));
+  data = build_string (strlen(name) + stat_buf.st_size, buffer);
+  TREE_TYPE (data) = data_type;
+  PUSH_FIELD_VALUE (rinit, "data", data);
+  FINISH_RECORD_CONSTRUCTOR (rinit);
+  TREE_CONSTANT (rinit) = 1;
+
+  /* Generate a unique-enough identifier.  */
+  sprintf(buf, "_Jr%d", ++Jr_count);
+
+  decl = build_decl (VAR_DECL, get_identifier (buf), rtype);
+  TREE_STATIC (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  TREE_READONLY (decl) = 1;
+  TREE_THIS_VOLATILE (decl) = 0;
+  DECL_INITIAL (decl) = rinit;
+  layout_decl (decl, 0);
+  pushdecl (decl);
+  rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0);
+  make_decl_rtl (decl, (char*) 0);
+  assemble_variable (decl, 1, 0, 0);
+
+  {
+    extern tree get_file_function_name PARAMS ((int));
+    tree init_name = get_file_function_name ('I');
+    tree init_type = build_function_type (void_type_node, end_params_node);
+    tree init_decl;
+    tree t;
+    
+    init_decl = build_decl (FUNCTION_DECL, init_name, init_type);
+    SET_DECL_ASSEMBLER_NAME (init_decl, init_name);
+    TREE_STATIC (init_decl) = 1;
+    current_function_decl = init_decl;
+    DECL_RESULT (init_decl) = build_decl(RESULT_DECL, NULL_TREE, void_type_node);
+    /*  DECL_EXTERNAL (init_decl) = 1;*/
+    TREE_PUBLIC (init_decl) = 1;
+    pushlevel (0);
+    make_decl_rtl (init_decl, NULL);
+    init_function_start (init_decl, input_filename, 0);
+    expand_function_start (init_decl, 0);
+    
+    emit_library_call (registerResource_libfunc, 0, VOIDmode, 1,
+		       gen_rtx (SYMBOL_REF, Pmode, buf), 
+		       Pmode);
+    
+    expand_function_end (input_filename, 0, 0);
+    poplevel (1, 0, 1);
+    { 
+      /* Force generation, even with -O3 or deeper. Gross hack. FIXME */
+      int saved_flag = flag_inline_functions;
+      flag_inline_functions = 0;	
+      rest_of_compilation (init_decl);
+      flag_inline_functions = saved_flag;
+    }
+    current_function_decl = NULL_TREE;
+    (* targetm.asm_out.constructor) (XEXP (DECL_RTL (init_decl), 0),
+				     DEFAULT_INIT_PRIORITY);
+  }     
+}
+
 tree utf8_decl_list = NULL_TREE;
 
 tree
@@ -1995,6 +2105,8 @@ void
 init_class_processing ()
 {
   registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
+  registerResource_libfunc = 
+    gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterResource");
   ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree));
   fields_ident = get_identifier ("fields");
   info_ident = get_identifier ("info");
Index: gcc/java/gcj.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/gcj.texi,v
retrieving revision 1.13
diff -u -p -r1.13 gcj.texi
--- gcj.texi	2001/08/09 04:19:12	1.13
+++ gcj.texi	2001/09/03 00:35:16
@@ -167,7 +167,7 @@ in which case they will all be compiled.
 option, all the input files will be compiled together, producing a
 single output file, named @var{FILENAME}.
 This is allowed even when using @code{-S} or @code{-c},
-but not when using @code{-C}.
+but not when using @code{-C} or @code{-R}.
 (This is an extension beyond the what plain @code{gcc} allows.)
 (If more than one input file is specified, all must currently
 be @code{.java} files, though we hope to fix this.)
@@ -336,6 +336,11 @@ using the @code{java.lang.System.getProp
 @item -C
 This option is used to tell @code{gcj} to generate bytecode
 (@file{.class} files) rather than object code.
+
+@item -R @var{resource-name}
+This option is used to tell @code{gcj} to compile the contents of a
+given file to object code so it may be accessed at runtime with the core
+protocol handler as @var{core:/resource-name}.
 
 @item -d @var{directory}
 When used with @code{-C}, this causes all generated @file{.class} files
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.119
diff -u -p -r1.119 java-tree.h
--- java-tree.h	2001/08/17 21:07:07	1.119
+++ java-tree.h	2001/09/03 00:35:16
@@ -163,6 +163,9 @@ extern int flag_emit_xref;
 /* When doing xrefs, tell when not to fold.   */
 extern int do_not_fold;
 
+/* Resource name.  */
+extern char * resource_name;
+
 /* Turned to 1 if -Wall was encountered. See lang.c for their meanings.  */
 extern int flag_wall;
 extern int flag_redundant;
Index: gcc/java/jcf-parse.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jcf-parse.c,v
retrieving revision 1.92
diff -u -p -r1.92 jcf-parse.c
--- jcf-parse.c	2001/08/30 21:28:19	1.92
+++ jcf-parse.c	2001/09/03 00:35:16
@@ -36,6 +36,7 @@ The Free Software Foundation is independ
 #include "parse.h"
 #include "ggc.h"
 #include "debug.h"
+#include "assert.h"
 
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
@@ -1083,6 +1084,20 @@ yyparse ()
 
   if (filename_count == 0)
     warning ("no input file specified");
+
+  if (resource_name)
+    {
+      /* Only one resource file may be compiled at a time.  */
+      assert (TREE_CHAIN (current_file_list) == NULL);
+
+      input_filename = IDENTIFIER_POINTER (TREE_VALUE (current_file_list));
+      compile_resource_file (resource_name, input_filename);
+      
+      java_expand_classes ();
+      if (!java_report_errors ())
+	emit_register_classes ();
+      return 0;
+    }
 
   current_jcf = main_jcf;
   current_file_list = nreverse (current_file_list);
Index: gcc/java/jvspec.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/jvspec.c,v
retrieving revision 1.45
diff -u -p -r1.45 jvspec.c
--- jvspec.c	2001/08/12 20:36:22	1.45
+++ jvspec.c	2001/09/03 00:35:16
@@ -1,4 +1,4 @@
- /* Specific flags and argument handling of the front-end of the 
+/* Specific flags and argument handling of the front-end of the 
    GNU compiler for the Java(TM) language.
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
@@ -42,6 +42,8 @@ The Free Software Foundation is independ
 #define ZIP_FILE_ARG	(1<<5)
 /* True if this arg is @FILE - where FILE contains a list of filenames. */
 #define INDIRECT_FILE_ARG (1<<6)
+/* True if this arg is a resource file.  */
+#define RESOURCE_FILE_ARG (1<<7)
 
 static char *find_spec_file	PARAMS ((const char *));
 
@@ -59,6 +61,7 @@ const char jvgenmain_spec[] =
 		   %{v:-version} %{pg:-p} %{p}\
 		   %{<fbounds-check} %{<fno-bounds-check}\
 		   %{<fassume-compiled} %{<fno-assume-compiled}\
+                   %{<fcompile-resource*}\
 		   %{<femit-class-file} %{<femit-class-files} %{<fencoding*}\
 		   %{<fuse-boehm-gc} %{<fhash-synchronization} %{<fjni}\
 		   %{<fclasspath*} %{<fCLASSPATH*} %{<foutput-class-dir}\
@@ -164,7 +167,8 @@ lang_specific_driver (in_argc, in_argv, 
   int saw_libgcj ATTRIBUTE_UNUSED = 0;
 #endif
 
-  /* Saw -C or -o option, respectively. */
+  /* Saw -R, -C or -o options, respectively. */
+  int saw_R = 0;
   int saw_C = 0;
   int saw_o = 0;
 
@@ -256,6 +260,16 @@ lang_specific_driver (in_argc, in_argv, 
 	      library = 0;
 	      will_link = 0;
 	    }
+	  else if (strcmp (argv[i], "-R") == 0)
+	    {
+	      saw_R = 1;
+	      quote = argv[i];
+	      want_spec_file = 0;
+	      if (library != 0)
+		added -= 2;
+	      library = 0;
+	      will_link = 0;
+	    }
 	  else if (argv[i][1] == 'D')
 	    saw_D = 1;
 	  else if (argv[i][1] == 'g')
@@ -324,6 +338,13 @@ lang_specific_driver (in_argc, in_argv, 
 	      continue;
 	    }
 
+	  if (saw_R)
+	    {
+	      args[i] |= RESOURCE_FILE_ARG;
+	      last_input_index = i;
+	      added += 2;  /* for -xjava and -xnone */
+	    }
+
 	  if (argv[i][0] == '@')
 	    {
 	      args[i] |= INDIRECT_FILE_ARG;
@@ -362,6 +383,11 @@ lang_specific_driver (in_argc, in_argv, 
     fatal ("can't specify `-D' without `--main'\n");
 
   num_args = argc + added;
+  if (saw_R)
+    {
+      if (! saw_o)
+	fatal ("-R requires -o");
+    }
   if (saw_C)
     {
       num_args += 3;
@@ -433,6 +459,29 @@ lang_specific_driver (in_argc, in_argv, 
 
       if ((args[i] & PARAM_ARG) || i == 0)
 	continue;
+
+      if ((args[i] & RESOURCE_FILE_ARG) != 0)
+	{
+	  arglist[j++] = "-xjava";
+	  arglist[j++] = argv[i];
+	  arglist[j] = "-xnone";
+	}
+
+      if (strcmp (argv[i], "-R") == 0)
+	{
+	  char *ptr = argv[i+i];
+	  while (*ptr)
+	    {
+	      if (*ptr == '.')
+		*ptr = '/';
+	      ptr++;
+	    }
+	  arglist[j] = concat ("-fcompile-resource=",
+			       *argv[i+1] == '/' ? "" : "/",
+			       argv[i+1], NULL);
+	  i++;
+	  continue;
+	}
 
       if (strcmp (argv[i], "-classpath") == 0
 	  || strcmp (argv[i], "-CLASSPATH") == 0)
Index: gcc/java/lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.70
diff -u -p -r1.70 lang.c
--- lang.c	2001/08/30 21:28:19	1.70
+++ lang.c	2001/09/03 00:35:16
@@ -99,6 +99,8 @@ int compiling_from_source;
 
 const char * const language_string = "GNU Java";
 
+char * resource_name;
+
 int flag_emit_class_files = 0;
 
 /* Nonzero if input file is a file with a list of filenames to compile. */
@@ -246,6 +248,13 @@ java_decode_option (argc, argv)
       return 0;
     }
 
+#define CLARG "-fcompile-resource="
+  if (strncmp (p, CLARG, sizeof (CLARG) - 1) == 0)
+    {
+      resource_name = p + sizeof (CLARG) - 1;
+      return 1;
+    }
+#undef CLARG
 #define CLARG "-fassume-compiled="
   if (strncmp (p, CLARG, sizeof (CLARG) - 1) == 0)
     {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]