-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ian Romanick wrote:
> Here is my first pass at run-time dispatch generation code for x86-64.
> It's not particularly well tested yet (or I'd just commit it now).  I
> wrote a test program that called fill_in_entrypoint with a few different
>  parameter signature strings, and I verified that the generated code
> looked correct.
> 
> After some discussion on IRC, I've been thinking about how we might make
> run-time dispatch generation work on "hardend" systems.  Those systems
> don't allow a memory region to be both writable and executable.  We can
> use mprotect to adjust the protections.  There are a couple sublte
> problems that need to be overcome to make this really work:

Is there any particular reason why the dispatch generation code lives in
src/mesa/glapi?  It is only actually used from libGL, and the rest of
the core libGL code lives in src/glx/x11.  I have a patch ready
(attached) the leaves the code in src/mesa/glapi, but I think the end
result will be much cleaner if the generation code lives in either
src/glx/x11 or perhaps a new directory called src/glx/common.

Opinions?

Here's the current patch.  It only works (i.e., builds) on x86.  The
idea will be that the platform dependent code is selected by only
building the correct C file (e.g., glapi_gen_x86.c, glapi_gen_ppc.c, etc.).

I have verified this works by building the libGL from (patched) sources
without GL_EXT_gpu_program_parameters support and using a driver with
support.  The dispatch routines were correctly generated and the
prog_parameters test passed.

This code does not contain any of the discussed work-arounds for case
where an app calls glXGetProcAddress for multiple synonym functions
before the driver gets loaded.  That's next.

SHA1SUM:
6d2a54073be7fb11e954c80b3ee934069f13e67d  gen_dispatch-200608151524.patch
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (GNU/Linux)

iD8DBQFE4krqX1gOwKyEAw8RAiEwAJ9lh8gpP5GMR5YobiqSa4OgaqOouwCfVh65
PwofFKW95Gb99CkjNH1wUZ8=
=oxb8
-----END PGP SIGNATURE-----
Index: configs/linux-dri-x86
===================================================================
RCS file: /cvs/mesa/Mesa/configs/linux-dri-x86,v
retrieving revision 1.12
diff -u -d -r1.12 linux-dri-x86
--- configs/linux-dri-x86	12 Sep 2005 15:19:19 -0000	1.12
+++ configs/linux-dri-x86	15 Aug 2006 22:25:44 -0000
@@ -9,7 +9,7 @@
 PIC_FLAGS = 
 
 # Add -m32 to CFLAGS:
-ARCH_FLAGS = -m32
+ARCH_FLAGS = -m32 -DDYNAMIC_DISPATCH
 
 ASM_FLAGS = -DUSE_X86_ASM -DUSE_MMX_ASM -DUSE_3DNOW_ASM -DUSE_SSE_ASM
 ASM_SOURCES = $(X86_SOURCES)
Index: src/mesa/sources
===================================================================
RCS file: /cvs/mesa/Mesa/src/mesa/sources,v
retrieving revision 1.66
diff -u -d -r1.66 sources
--- src/mesa/sources	12 Jun 2006 16:26:29 -0000	1.66
+++ src/mesa/sources	15 Aug 2006 22:25:44 -0000
@@ -65,7 +65,8 @@
 GLAPI_SOURCES = \
 	main/dispatch.c \
 	glapi/glapi.c \
-	glapi/glthread.c
+	glapi/glthread.c \
+	glapi/glapi_gen_x86.c
 
 MATH_SOURCES = \
 	math/m_debug_clip.c \
Index: src/mesa/glapi/glapi.c
===================================================================
RCS file: /cvs/mesa/Mesa/src/mesa/glapi/glapi.c,v
retrieving revision 1.103
diff -u -d -r1.103 glapi.c
--- src/mesa/glapi/glapi.c	16 Jun 2006 14:50:05 -0000	1.103
+++ src/mesa/glapi/glapi.c	15 Aug 2006 22:25:45 -0000
@@ -54,6 +54,7 @@
 #include "glapi.h"
 #include "glapioffsets.h"
 #include "glapitable.h"
+#include "glapi_gen_common.h"
 
 /***** BEGIN NO-OP DISPATCH *****/
 
@@ -64,8 +65,9 @@
 static void init_glapi_relocs(void);
 #endif
 
-static _glapi_proc generate_entrypoint(GLuint functionOffset);
-static void fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset);
+struct _glapi_function;
+static int generate_dispatch_function(struct _glapi_function *func);
+static void init_glapi_platform(void);
 
 /*
  * Enable/disable printing of warning messages.
@@ -525,135 +527,73 @@
 
 static struct _glapi_function ExtEntryTable[MAX_EXTENSION_FUNCS];
 static GLuint NumExtEntryPoints = 0;
+struct _glapi_dispatch_factory  factory;
 
-#ifdef USE_SPARC_ASM
-extern void __glapi_sparc_icache_flush(unsigned int *);
+
+static void
+init_glapi_platform(void)
+{
+#ifdef DYNAMIC_DISPATCH
+   factory.next_offset = _gloffset_FIRST_DYNAMIC;
+   _glapi_gen_platform_init(& factory);
 #endif
+}
 
-/**
- * Generate a dispatch function (entrypoint) which jumps through
- * the given slot number (offset) in the current dispatch table.
- * We need assembly language in order to accomplish this.
- */
-static _glapi_proc
-generate_entrypoint(GLuint functionOffset)
+
+static int
+generate_dispatch_function(struct _glapi_function *func)
 {
-#if defined(USE_X86_ASM)
-   /* 32 is chosen as something of a magic offset.  For x86, the dispatch
-    * at offset 32 is the first one where the offset in the
-    * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
-    */
-   const GLubyte * const template_func = gl_dispatch_functions_start 
-     + (X86_DISPATCH_FUNCTION_SIZE * 32);
-   GLubyte * const code = (GLubyte *) malloc( X86_DISPATCH_FUNCTION_SIZE );
+#ifdef DYNAMIC_DISPATCH
+    struct _glapi_dispatch_header *h;
+    unsigned hash;
+    unsigned byte_offset;
 
 
-   if ( code != NULL ) {
-      (void) memcpy( code, template_func, X86_DISPATCH_FUNCTION_SIZE );
-      fill_in_entrypoint_offset( (_glapi_proc) code, functionOffset );
-   }
+    /* Get a pointer to the dispatch header for the requested function
+     * signature.
+     */
+    hash = (*factory.hash_signature)(func->parameter_signature);
+    h = & factory.header[ hash ];
 
-   return (_glapi_proc) code;
-#elif defined(USE_SPARC_ASM)
 
-#ifdef __arch64__
-   static const unsigned int insn_template[] = {
-	   0x05000000,	/* sethi	%uhi(_glapi_Dispatch), %g2	*/
-	   0x03000000,	/* sethi	%hi(_glapi_Dispatch), %g1	*/
-	   0x8410a000,	/* or		%g2, %ulo(_glapi_Dispatch), %g2	*/
-	   0x82106000,	/* or		%g1, %lo(_glapi_Dispatch), %g1	*/
-	   0x8528b020,	/* sllx		%g2, 32, %g2			*/
-	   0xc2584002,	/* ldx		[%g1 + %g2], %g1		*/
-	   0x05000000,	/* sethi	%hi(8 * glapioffset), %g2	*/
-	   0x8410a000,	/* or		%g2, %lo(8 * glapioffset), %g2	*/
-	   0xc6584002,	/* ldx		[%g1 + %g2], %g3		*/
-	   0x81c0c000,	/* jmpl		%g3, %g0			*/
-	   0x01000000	/*  nop						*/
-   };
-#else
-   static const unsigned int insn_template[] = {
-	   0x03000000,	/* sethi	%hi(_glapi_Dispatch), %g1	  */
-	   0xc2006000,	/* ld		[%g1 + %lo(_glapi_Dispatch)], %g1 */
-	   0xc6006000,	/* ld		[%g1 + %lo(4*glapioffset)], %g3	  */
-	   0x81c0c000,	/* jmpl		%g3, %g0			  */
-	   0x01000000	/*  nop						  */
-   };
-#endif /* __arch64__ */
-   unsigned int *code = (unsigned int *) malloc(sizeof(insn_template));
-   unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
-   if (code) {
-      memcpy(code, insn_template, sizeof(insn_template));
+    /* If there is no page with available functions, dip into the platform-
+     * specific code and get one!
+     */
+    if (h->current_page == NULL) {
+	int err;
+	
+	h->base_dispatch_offset = factory.next_offset;
+	h->current_offset = 0;
 
-#ifdef __arch64__
-      code[0] |= (glapi_addr >> (32 + 10));
-      code[1] |= ((glapi_addr & 0xffffffff) >> 10);
-      __glapi_sparc_icache_flush(&code[0]);
-      code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
-      code[3] |= (glapi_addr & ((1 << 10) - 1));
-      __glapi_sparc_icache_flush(&code[2]);
-      code[6] |= ((functionOffset * 8) >> 10);
-      code[7] |= ((functionOffset * 8) & ((1 << 10) - 1));
-      __glapi_sparc_icache_flush(&code[6]);
-#else
-      code[0] |= (glapi_addr >> 10);
-      code[1] |= (glapi_addr & ((1 << 10) - 1));
-      __glapi_sparc_icache_flush(&code[0]);
-      code[2] |= (functionOffset * 4);
-      __glapi_sparc_icache_flush(&code[2]);
-#endif /* __arch64__ */
-   }
-   return (_glapi_proc) code;
-#else
-   (void) functionOffset;
-   return NULL;
-#endif /* USE_*_ASM */
-}
+	err = (*factory.get_page)(& factory, h, hash);
+	if (err < 0) {
+	    return err;
+	}
 
+	factory.next_offset += h->functions_per_page;
+    }
 
-/**
- * This function inserts a new dispatch offset into the assembly language
- * stub that was generated with the preceeding function.
- */
-static void
-fill_in_entrypoint_offset(_glapi_proc entrypoint, GLuint offset)
-{
-#if defined(USE_X86_ASM)
-   GLubyte * const code = (GLubyte *) entrypoint;
 
-#if X86_DISPATCH_FUNCTION_SIZE == 32
-   *((unsigned int *)(code + 11)) = 4 * offset;
-   *((unsigned int *)(code + 22)) = 4 * offset;
-#elif X86_DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
-   *((unsigned int *)(code +  8)) = 4 * offset;
-#elif X86_DISPATCH_FUNCTION_SIZE == 16
-   *((unsigned int *)(code +  7)) = 4 * offset;
-#else
-# error Invalid X86_DISPATCH_FUNCTION_SIZE!
-#endif
+    byte_offset = h->current_offset * h->bytes_per_function;
 
-#elif defined(USE_SPARC_ASM)
+    func->dispatch_offset = h->current_offset + h->base_dispatch_offset;
+    func->dispatch_stub = (_glapi_proc)((char *)h->current_page + byte_offset);
 
-   /* XXX this hasn't been tested! */
-   unsigned int *code = (unsigned int *) entrypoint;
-#ifdef __arch64__
-   code[6] = 0x05000000;  /* sethi	%hi(8 * glapioffset), %g2	*/
-   code[7] = 0x8410a000;  /* or		%g2, %lo(8 * glapioffset), %g2	*/
-   code[6] |= ((offset * 8) >> 10);
-   code[7] |= ((offset * 8) & ((1 << 10) - 1));
-   __glapi_sparc_icache_flush(&code[6]);
-#else /* __arch64__ */
-   code[2] = 0xc6006000;  /* ld		[%g1 + %lo(4*glapioffset)], %g3	  */
-   code[2] |= (offset * 4);
-   __glapi_sparc_icache_flush(&code[2]);
-#endif /* __arch64__ */
+    h->current_offset++;
 
-#else
 
-   /* an unimplemented architecture */
-   (void) entrypoint;
-   (void) offset;
+    /* If this is the last function on the page, NULL out the page pointer
+     * so that the next call for this signature will create a new page.
+     */
+    if (h->current_offset >= h->functions_per_page) {
+	h->current_page = NULL;
+    }
 
-#endif /* USE_*_ASM */
+
+    return 0;
+#else
+   return -ENOSYS;
+#endif /* DYNAMIC_DISPATCH */
 }
 
 
@@ -671,21 +611,31 @@
  */
 
 static struct _glapi_function *
-add_function_name( const char * funcName )
+add_function_name(const char * funcName, const char *signature)
 {
    struct _glapi_function * entry = NULL;
+#if defined(PTHREADS) || defined(GLX_USE_TLS)
+   static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+   pthread_once(& once_control, init_glapi_platform);
+#else
+   static int once_control = 0;
+
+
+   if (!once_control) {
+      init_glapi_platform();
+      once_control = 1;
+   }
+#endif
    
    if (NumExtEntryPoints < MAX_EXTENSION_FUNCS) {
-      _glapi_proc entrypoint = generate_entrypoint(~0);
-      if (entrypoint != NULL) {
-	 entry = & ExtEntryTable[NumExtEntryPoints];
+       ExtEntryTable[NumExtEntryPoints].name = str_dup(funcName);
+       ExtEntryTable[NumExtEntryPoints].parameter_signature = 
+	   (signature == NULL) ? NULL : str_dup(signature);
 
-	 ExtEntryTable[NumExtEntryPoints].name = str_dup(funcName);
-	 ExtEntryTable[NumExtEntryPoints].parameter_signature = NULL;
-	 ExtEntryTable[NumExtEntryPoints].dispatch_offset = ~0;
-	 ExtEntryTable[NumExtEntryPoints].dispatch_stub = entrypoint;
-	 NumExtEntryPoints++;
-      }
+       if (generate_dispatch_function(& ExtEntryTable[NumExtEntryPoints]) == 0) {
+	   entry = & ExtEntryTable[NumExtEntryPoints];
+	   NumExtEntryPoints++;
+       }
    }
 
    return entry;
@@ -743,7 +693,6 @@
 _glapi_add_dispatch( const char * const * function_names,
 		     const char * parameter_signature )
 {
-   static int next_dynamic_offset = _gloffset_FIRST_DYNAMIC;
    const char * const real_sig = (parameter_signature != NULL)
      ? parameter_signature : "";
    struct _glapi_function * entry[8];
@@ -786,48 +735,43 @@
    
       for ( j = 0 ; j < NumExtEntryPoints ; j++ ) {
 	 if (strcmp(ExtEntryTable[j].name, function_names[i]) == 0) {
-	    /* The offset may be ~0 if the function name was added by
-	     * glXGetProcAddress but never filled in by the driver.
+	    /* The parameter_signature will be NULL if the function name was
+	     * added by glXGetProcAddress.
 	     */
 
-	    if (ExtEntryTable[j].dispatch_offset != ~0) {
-	       if (strcmp(real_sig, ExtEntryTable[j].parameter_signature) 
-		   != 0) {
-		  return -1;
-	       }
-
-	       if ( (offset != ~0) && (ExtEntryTable[j].dispatch_offset != offset) ) {
-		  return -1;
-	       }
+	    if ((ExtEntryTable[j].parameter_signature != NULL)
+		&& strcmp(real_sig, ExtEntryTable[j].parameter_signature) != 0) {
+	       return -1;
+	    }
 
-	       offset = ExtEntryTable[j].dispatch_offset;
+	    if ((offset != ~0) 
+		&& (ExtEntryTable[j].dispatch_offset != offset)) {
+	       return -1;
 	    }
-	    
+
+	    offset = ExtEntryTable[j].dispatch_offset;
 	    entry[i] = & ExtEntryTable[j];
 	    break;
 	 }
       }
    }
 
-   if (offset == ~0) {
-      offset = next_dynamic_offset;
-      next_dynamic_offset++;
-   }
 
    for ( i = 0 ; function_names[i] != NULL ; i++ ) {
       if (! is_static[i] ) {
 	 if (entry[i] == NULL) {
-	    entry[i] = add_function_name( function_names[i] );
+	    entry[i] = add_function_name(function_names[i], real_sig);
 	    if (entry[i] == NULL) {
 	       /* FIXME: Possible memory leak here.
 		*/
 	       return -1;
 	    }
-	 }
 
-	 entry[i]->parameter_signature = str_dup(real_sig);
-	 fill_in_entrypoint_offset(entry[i]->dispatch_stub, offset);
-	 entry[i]->dispatch_offset = offset;
+	    offset = entry[i]->dispatch_offset;
+	 }
+	 else if (entry[i]->parameter_signature == NULL) {
+	    entry[i]->parameter_signature = str_dup(real_sig);
+	 }
       }
    }
    
@@ -889,7 +833,7 @@
    }
 #endif /* !defined( XFree86Server ) */
 
-   entry = add_function_name(funcName);
+   entry = add_function_name(funcName, NULL);
    return (entry == NULL) ? NULL : entry->dispatch_stub;
 }
 
Index: src/mesa/glapi/glapi_gen_SPARC.c
===================================================================
RCS file: src/mesa/glapi/glapi_gen_SPARC.c
diff -N src/mesa/glapi/glapi_gen_SPARC.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/mesa/glapi/glapi_gen_SPARC.c	15 Aug 2006 22:25:45 -0000
@@ -0,0 +1,151 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * COPYRIGHT HOLDERS, AUTHORS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file glapi_gen_SPARC.c
+ * SPARC platform dependent code for dispatch generation.
+ *
+ * \author Brian Paul
+ * \author Ian Romanick <[EMAIL PROTECTED]>
+ */
+
+extern void __glapi_sparc_icache_flush(unsigned int *);
+
+#ifdef __arch64__
+static const unsigned int insn_template[] = {
+   0x05000000,	/* sethi	%uhi(_glapi_Dispatch), %g2	*/
+   0x03000000,	/* sethi	%hi(_glapi_Dispatch), %g1	*/
+   0x8410a000,	/* or		%g2, %ulo(_glapi_Dispatch), %g2	*/
+   0x82106000,	/* or		%g1, %lo(_glapi_Dispatch), %g1	*/
+   0x8528b020,	/* sllx		%g2, 32, %g2			*/
+   0xc2584002,	/* ldx		[%g1 + %g2], %g1		*/
+   0x05000000,	/* sethi	%hi(8 * glapioffset), %g2	*/
+   0x8410a000,	/* or		%g2, %lo(8 * glapioffset), %g2	*/
+   0xc6584002,	/* ldx		[%g1 + %g2], %g3		*/
+   0x81c0c000,	/* jmpl		%g3, %g0			*/
+   0x01000000	/* nop						*/
+};
+#else
+static const unsigned int insn_template[] = {
+   0x03000000,	/* sethi	%hi(_glapi_Dispatch), %g1	  */
+   0xc2006000,	/* ld		[%g1 + %lo(_glapi_Dispatch)], %g1 */
+   0xc6006000,	/* ld		[%g1 + %lo(4*glapioffset)], %g3	  */
+   0x81c0c000,	/* jmpl		%g3, %g0			  */
+   0x01000000	/* nop						  */
+};
+#endif /* __arch64__ */
+
+
+static unsigned
+sparc_hash_signature(const char *signature)
+{
+    (void) signature;
+    return 0;
+}
+
+
+/**
+ * \bug
+ * This code is completely wrong.  It's taken directly from glapi.c, but it
+ * doesn't use the proper thread-safe accessors in the generated dispatch
+ * functions.
+ */
+static int
+sparc_get_page(const struct _glapi_dispatch_factory *factory,
+	       struct _glapi_dispatch_header *header, unsigned signature_hash)
+{
+   unsigned i;
+   unsigned char *page;
+
+
+   /* There are three distinct steps to this process.  First, a single page
+    * is allocated.  Then the page is filled with dispatch functions.
+    * Finally, the page is marked as read-only and executable.
+    */
+   page = malloc((factory->page_size * 2) - 1);
+   if (page == NULL) {
+      return -ENOMEM;
+   }
+
+   page = (void *) (((intptr_t)page + (factory->page_size - 1))
+		    & ~(factory->page_size - 1));
+
+
+   for (i = 0; i < header->functions_per_page; i++) {
+      unsigned int * const code = 
+	  (unsigned int *)(page + (i * sizeof(insn_template)));
+      const unsigned offset = header->base_dispatch_offset + i;
+      unsigned long glapi_addr = (unsigned long) &_glapi_Dispatch;
+
+      (void) memcpy(code, insn_template, sizeof(insn_template));
+
+#ifdef __arch64__
+      code[0] |= (glapi_addr >> (32 + 10));
+      code[1] |= ((glapi_addr & 0xffffffff) >> 10);
+      __glapi_sparc_icache_flush(&code[0]);
+      code[2] |= ((glapi_addr >> 32) & ((1 << 10) - 1));
+      code[3] |= (glapi_addr & ((1 << 10) - 1));
+      __glapi_sparc_icache_flush(&code[2]);
+      code[6] |= ((offset * 8) >> 10);
+      code[7] |= ((offset * 8) & ((1 << 10) - 1));
+      __glapi_sparc_icache_flush(&code[6]);
+#else
+      code[0] |= (glapi_addr >> 10);
+      code[1] |= (glapi_addr & ((1 << 10) - 1));
+      __glapi_sparc_icache_flush(&code[0]);
+      code[2] |= (offset * 4);
+      __glapi_sparc_icache_flush(&code[2]);
+#endif /* __arch64__ */
+   }
+
+    if (mprotect(page, factory->page_size, PROT_READ|PROT_EXEC)) {
+	free(page);
+	return -errno;
+    }
+
+    header->current_page = page;
+    return 0;
+}
+
+
+int
+_glapi_gen_platform_init(struct _glapi_dispatch_factory *factory)
+{
+   factory->num_signatures = 1;
+   factory->page_size = getpagesize();
+   factory->hash_signature = sparc_hash_signature;
+   factory->get_page = sparc_get_page;
+
+   factory->header = calloc(1, sizeof(struct _glapi_dispatch_header));
+   if (factory->header == NULL) {
+      return -ENOMEM;
+   }
+
+   factory->header->bytes_per_function = sizeof(insn_template);
+   factory->header->functions_per_page = factory->page_size /
+       factory->header->bytes_per_function;
+
+   return 0;
+}
Index: src/mesa/glapi/glapi_gen_common.h
===================================================================
RCS file: src/mesa/glapi/glapi_gen_common.h
diff -N src/mesa/glapi/glapi_gen_common.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/mesa/glapi/glapi_gen_common.h	15 Aug 2006 22:25:45 -0000
@@ -0,0 +1,143 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * COPYRIGHT HOLDERS, AUTHORS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GLAPI_GEN_COMMON_H
+#define GLAPI_GEN_COMMON_H
+
+/**
+ * \file glapi_gen_common.h
+ * Platform independent structures and prototypes for dispatch generation.
+ * 
+ * \author Ian Romanick <[EMAIL PROTECTED]>
+ */
+
+/**
+ * Control structure for generating dispatch functions.
+ *
+ * Each architecture has some fixed number of possible dispatch function
+ * signatures.  For each possible signature, there is a page allocated.
+ * This page is initialized with as many dispatch functions as will fit.
+ * These functions are complete, so this implies that dispatch offset for
+ * the functions are assigned at this time.
+ */
+struct _glapi_dispatch_factory {
+    /**
+     * Total number of possible function signatures for this architecture.
+     * For x86, which passes all parameters on the stack, and architectures
+     * that use TLS, this will be 1.  For non-TLS x86-64, which has 6
+     * integer registers and 8 floating point registers, this is
+     * (6 + 1) * (8 + 1) = 63.
+     */
+    unsigned num_signatures;
+
+    /**
+     * Size, in bytes, of a single page for this architecture.
+     */
+    unsigned page_size;
+
+    /**
+     * When the next page is created, this is the dispatch offset of the
+     * first function stored on that page.
+     */
+    unsigned next_offset;
+
+    /**
+     * Array of \c ::num_signatures dispatch header structures.
+     */
+    struct _glapi_dispatch_header * header;
+
+    /**
+     * Hash a signature to create an index into \c ::header.  If this function
+     * is called via \c glXGetProcAddress, the function signature will not
+     * be known.  In that case, \c signature will be \c NULL.
+     * 
+     * \param signature  Signature string to be hashed.
+     *
+     * \return
+     * An index into the \c ::header array.  By definition this must be
+     * less than \c ::num_signatures.
+     */
+    unsigned (*hash_signature)(const char *signature);
+
+    /**
+     * When \c header::current_page is \c NULL, this function is called to
+     * allocate and initialize a fresh page of dispatch functions.
+     *
+     * \param header     Pointer to the bin to be refilled.
+     * \param signature  Signature index associated with the bin.
+     *
+     * \note
+     * This function assumes that the caller will have properly initialized
+     * \c header::base_dispatch_offset and \c header::current_offset.
+     *
+     * \return
+     * Zero on success or a negative errno value on failure.
+     */
+    int (*get_page)(const struct _glapi_dispatch_factory *factory,
+		    struct _glapi_dispatch_header *header, 
+		    unsigned signature_hash);
+};
+
+
+/**
+ * Bookkeeping structure for an individual dispatch function signature.
+ */
+struct _glapi_dispatch_header {
+    /**
+     * Each of the possible dispatch functions for a given architecture can
+     * have a different size.  This will depend, for example, on how many
+     * registers need to be saved and restored around the call to get the
+     * current dispatch pointer.  This value stores that size for this
+     * function signature signature.
+     */
+    unsigned bytes_per_function;
+
+    /**
+     * Total number of dispatch functions with this signature that fit in a
+     * single page.
+     */
+    unsigned functions_per_page;
+
+    /**
+     * Dispatch offset of the first function stored in the current page.
+     */
+    unsigned base_dispatch_offset;
+
+    /**
+     * Offset, on the range [0, n-1], of the next dispatch function with this
+     * signature to be returned.  n is the number of dispatch functions stored
+     * per page.
+     */
+    unsigned current_offset;
+
+    /**
+     * Base address of the current page.  If no page is currently available,
+     * this will be \c NULL.
+     */
+    void * current_page;
+};
+
+extern int _glapi_gen_platform_init(struct _glapi_dispatch_factory *factory);
+
+#endif /* GLAPI_GEN_COMMON_H */
Index: src/mesa/glapi/glapi_gen_x86.c
===================================================================
RCS file: src/mesa/glapi/glapi_gen_x86.c
diff -N src/mesa/glapi/glapi_gen_x86.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/mesa/glapi/glapi_gen_x86.c	15 Aug 2006 22:25:45 -0000
@@ -0,0 +1,149 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
+ * COPYRIGHT HOLDERS, AUTHORS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file glapi_gen_x86.c
+ * x86 platform dependent code for dispatch generation.
+ *
+ * \author Brian Paul
+ * \author Ian Romanick <[EMAIL PROTECTED]>
+ */
+
+#include <GL/gl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "glapi_gen_common.h"
+
+#if defined(GLX_USE_TLS)
+extern       GLubyte gl_dispatch_functions_start[];
+extern       GLubyte gl_dispatch_functions_end[];
+extern void *_x86_get_dispatch(void);
+#else
+extern const GLubyte gl_dispatch_functions_start[];
+#endif
+
+#if defined(THREADS) && !defined(GLX_USE_TLS)
+# define X86_DISPATCH_FUNCTION_SIZE  32
+#else
+# define X86_DISPATCH_FUNCTION_SIZE  16
+#endif
+
+static unsigned char insn_template[X86_DISPATCH_FUNCTION_SIZE];
+
+
+static unsigned
+x86_hash_signature(const char *signature)
+{
+    (void) signature;
+    return 0;
+}
+
+
+static int
+x86_get_page(const struct _glapi_dispatch_factory *factory,
+	     struct _glapi_dispatch_header *header, unsigned signature_hash)
+
+{
+   unsigned i;
+   unsigned char *page;
+
+
+   /* There are three distinct steps to this process.  First, a single page
+    * is allocated.  Then the page is filled with dispatch functions.
+    * Finally, the page is marked as read-only and executable.
+    */
+   page = malloc((factory->page_size * 2) - 1);
+   if (page == NULL) {
+      return -ENOMEM;
+   }
+
+   page = (void *) (((intptr_t)page + (factory->page_size - 1))
+		    & ~(factory->page_size - 1));
+
+
+   for (i = 0; i < header->functions_per_page; i++) {
+      GLubyte * const code = page + (i * sizeof(insn_template));
+      const unsigned offset = header->base_dispatch_offset + i;
+
+      (void) memcpy(code, insn_template, sizeof(insn_template));
+
+#if X86_DISPATCH_FUNCTION_SIZE == 32
+      *((unsigned int *)(code + 11)) = 4 * offset;
+      *((unsigned int *)(code + 22)) = 4 * offset;
+#elif X86_DISPATCH_FUNCTION_SIZE == 16 && defined( GLX_USE_TLS )
+      *((unsigned int *)(code +  8)) = 4 * offset;
+#elif X86_DISPATCH_FUNCTION_SIZE == 16
+      *((unsigned int *)(code +  7)) = 4 * offset;
+#else
+# error Invalid X86_DISPATCH_FUNCTION_SIZE!
+#endif
+   }
+
+   if (mprotect(page, factory->page_size, PROT_READ|PROT_EXEC) < 0) {
+      free(page);
+      return -errno;
+   }
+
+   header->current_page = page;
+   return 0;
+}
+
+
+int
+_glapi_gen_platform_init(struct _glapi_dispatch_factory *factory)
+{
+   /* 32 is chosen as something of a magic offset.  For x86, the dispatch
+    * at offset 32 is the first one where the offset in the
+    * "jmp OFFSET*4(%eax)" can't be encoded in a single byte.
+    */
+   const unsigned char * const template_func = gl_dispatch_functions_start 
+       + (X86_DISPATCH_FUNCTION_SIZE * 32);
+
+
+   factory->num_signatures = 1;
+   factory->page_size = getpagesize();
+   factory->hash_signature = x86_hash_signature;
+   factory->get_page = x86_get_page;
+
+   factory->header = calloc(1, sizeof(struct _glapi_dispatch_header));
+   if (factory->header == NULL) {
+      return -ENOMEM;
+   }
+
+   factory->header->bytes_per_function = X86_DISPATCH_FUNCTION_SIZE;
+   factory->header->functions_per_page = factory->page_size /
+       factory->header->bytes_per_function;
+
+
+   (void) memcpy(insn_template, template_func, X86_DISPATCH_FUNCTION_SIZE);
+#ifdef GLX_USE_TLS
+   (void) memcpy(insn_template, _x86_get_dispatch, 6);
+#endif
+   return 0;
+}
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Mesa3d-dev mailing list
Mesa3d-dev@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to