diff -urN povray-3.6.1/configure.ac povray-3.6.1-ww/configure.ac
--- povray-3.6.1/configure.ac	2004-07-18 12:18:52.000000000 +0200
+++ povray-3.6.1-ww/configure.ac	2004-08-08 17:04:21.000000000 +0200
@@ -396,6 +396,9 @@
 # libm
 AC_CHECK_LIB([m], [sin])
 
+# dlopen for JIT compiler
+AC_CHECK_LIB([dl], [dlopen])
+
 
 # asinh and friends (requires libm)
 AC_CHECK_FUNCS([asinh],
@@ -1083,6 +1086,18 @@
 
 ###############################################################################
 
+# Save some information in conf.h for the JIT compiler config: 
+AC_DEFINE_UNQUOTED([JITC_USED_COMPILER],["$CXX"],[Used C++ compiler.])
+AC_DEFINE_UNQUOTED([JITC_COMPILER_FLAGS],["$CXXFLAGS"],[Compiler flags.])
+AC_DEFINE_UNQUOTED([JITC_COMPILER_INCS],
+	["$INCZ $INCPNG $INCTIFF $INCJPEG"],[Compiler includes.])
+AC_DEFINE_UNQUOTED([JITC_COMPILER_SRC],["$(sh -c "cd $srcdir; pwd")"],
+	[Source dir])
+AC_DEFINE_UNQUOTED([JITC_COMPILER_BUILD],["$(pwd)"],
+	[Build dir])
+
+###############################################################################
+
 AC_MSG_RESULT([
 Makefiles
 ---------])
diff -urN povray-3.6.1/source/Makefile.am povray-3.6.1-ww/source/Makefile.am
--- povray-3.6.1/source/Makefile.am	2004-07-18 14:10:10.000000000 +0200
+++ povray-3.6.1-ww/source/Makefile.am	2004-08-08 17:04:21.000000000 +0200
@@ -33,7 +33,8 @@
 
 # Source files.
 libpovray_a_SOURCES = \
-atmosph.cpp atmosph.h bbox.cpp bbox.h bcyl.cpp bcyl.h benchmark.cpp benchmark.h bezier.cpp bezier.h blob.cpp blob.h boxes.cpp boxes.h bsphere.cpp bsphere.h camera.cpp camera.h chi2.cpp chi2.h colour.cpp colour.h colutils.cpp colutils.h cones.cpp cones.h csg.cpp csg.h discs.cpp discs.h express.cpp express.h fncode.cpp fncode.h fnintern.cpp fnintern.h fnpovfpu.cpp fnpovfpu.h fnsyntax.cpp fnsyntax.h fpmetric.cpp fpmetric.h fractal.cpp fractal.h frame.h function.cpp function.h gif.cpp gifdecod.cpp gifdecod.h gif.h hcmplx.cpp hcmplx.h hfield.cpp hfield.h histogra.cpp histogra.h iff.cpp iff.h image.cpp image.h interior.cpp interior.h isosurf.cpp isosurf.h jpeg_pov.cpp jpeg_pov.h lathe.cpp lathe.h lbuffer.cpp lbuffer.h lightgrp.cpp lightgrp.h lighting.cpp lighting.h mathutil.cpp mathutil.h matrices.cpp matrices.h media.cpp media.h mesh.cpp mesh.h normal.cpp normal.h objects.cpp objects.h octree.cpp octree.h optout.cpp optout.h parse.cpp parse.h parsestr.cpp parsestr.h parstxtr.cpp parstxtr.h pattern.cpp pattern.h pgm.cpp pgm.h photons.cpp photons.h pigment.cpp pigment.h planes.cpp planes.h png_pov.cpp png_pov.h point.cpp point.h poly.cpp polygon.cpp polygon.h poly.h polysolv.cpp polysolv.h pov_mem.cpp pov_mem.h povmsend.cpp povmsend.h povmsrec.cpp povmsrec.h povray.cpp povray.h pov_util.cpp pov_util.h ppm.cpp ppm.h prism.cpp prism.h quadrics.cpp quadrics.h quatern.cpp quatern.h rad_data.cpp radiosit.cpp radiosit.h ray.cpp ray.h rendctrl.cpp rendctrl.h render.cpp render.h renderio.cpp renderio.h sor.cpp sor.h spheres.cpp spheres.h sphsweep.cpp sphsweep.h splines.cpp splines.h statspov.cpp statspov.h super.cpp super.h targa.cpp targa.h texture.cpp texture.h tiff_pov.cpp tiff_pov.h tokenize.cpp tokenize.h torus.cpp torus.h triangle.cpp triangle.h truetype.cpp truetype.h txttest.cpp txttest.h userdisp.cpp userdisp.h userio.cpp userio.h vbuffer.cpp vbuffer.h vector.h vlbuffer.cpp vlbuffer.h warps.cpp warps.h
+atmosph.cpp atmosph.h bbox.cpp bbox.h bcyl.cpp bcyl.h benchmark.cpp benchmark.h bezier.cpp bezier.h blob.cpp blob.h boxes.cpp boxes.h bsphere.cpp bsphere.h camera.cpp camera.h chi2.cpp chi2.h colour.cpp colour.h colutils.cpp colutils.h cones.cpp cones.h csg.cpp csg.h discs.cpp discs.h express.cpp express.h fncode.cpp fncode.h fnintern.cpp fnintern.h fnpovfpu.cpp fnpovfpu.h fnsyntax.cpp fnsyntax.h fpmetric.cpp fpmetric.h fractal.cpp fractal.h frame.h function.cpp function.h gif.cpp gifdecod.cpp gifdecod.h gif.h hcmplx.cpp hcmplx.h hfield.cpp hfield.h histogra.cpp histogra.h iff.cpp iff.h image.cpp image.h interior.cpp interior.h isosurf.cpp isosurf.h jpeg_pov.cpp jpeg_pov.h lathe.cpp lathe.h lbuffer.cpp lbuffer.h lightgrp.cpp lightgrp.h lighting.cpp lighting.h mathutil.cpp mathutil.h matrices.cpp matrices.h media.cpp media.h mesh.cpp mesh.h normal.cpp normal.h objects.cpp objects.h octree.cpp octree.h optout.cpp optout.h parse.cpp parse.h parsestr.cpp parsestr.h parstxtr.cpp parstxtr.h pattern.cpp pattern.h pgm.cpp pgm.h photons.cpp photons.h pigment.cpp pigment.h planes.cpp planes.h png_pov.cpp png_pov.h point.cpp point.h poly.cpp polygon.cpp polygon.h poly.h polysolv.cpp polysolv.h pov_mem.cpp pov_mem.h povmsend.cpp povmsend.h povmsrec.cpp povmsrec.h povray.cpp povray.h pov_util.cpp pov_util.h ppm.cpp ppm.h prism.cpp prism.h quadrics.cpp quadrics.h quatern.cpp quatern.h rad_data.cpp radiosit.cpp radiosit.h ray.cpp ray.h rendctrl.cpp rendctrl.h render.cpp render.h renderio.cpp renderio.h sor.cpp sor.h spheres.cpp spheres.h sphsweep.cpp sphsweep.h splines.cpp splines.h statspov.cpp statspov.h super.cpp super.h targa.cpp targa.h texture.cpp texture.h tiff_pov.cpp tiff_pov.h tokenize.cpp tokenize.h torus.cpp torus.h triangle.cpp triangle.h truetype.cpp truetype.h txttest.cpp txttest.h userdisp.cpp userdisp.h userio.cpp userio.h vbuffer.cpp vbuffer.h vector.h vlbuffer.cpp vlbuffer.h warps.cpp warps.h \
+jitcompiler.h jitcompiler.cpp refstring.cpp linkedlist.h refstring.h
 
 # Include paths for headers.
 AM_CPPFLAGS = \
diff -urN povray-3.6.1/source/fncode.cpp povray-3.6.1-ww/source/fncode.cpp
--- povray-3.6.1/source/fncode.cpp	2004-07-18 12:16:25.000000000 +0200
+++ povray-3.6.1-ww/source/fncode.cpp	2004-08-08 17:04:21.000000000 +0200
@@ -144,6 +144,9 @@
 	function->private_copy_method = NULL;
 	function->private_destroy_method = NULL;
 	function->private_data = NULL;
+	
+	function->jitc_state=1;
+	function->jitc_sofunc=NULL;
 
 	if(is_local == true)
 		function->flags |= FN_LOCAL_FLAG;
@@ -426,6 +429,10 @@
 		else
 			fnew->private_data = NULL;
 	}
+	
+	fnew->jitc_state=f->jitc_state;
+	fnew->jitc_sofunc=f->jitc_sofunc;
+	f->jitc_sofunc->aqref();
 }
 
 
@@ -500,6 +507,14 @@
 			POV_FREE(f->private_data);
 		f->private_data = NULL;
 	}
+	
+	if(f->jitc_sofunc)
+	{
+		if(f->jitc_sofunc->deref())
+		{  jit_compiler->RemoveFunction(f->jitc_sofunc);  }
+		f->jitc_sofunc=NULL;
+	}
+	f->jitc_state=0;
 }
 
 
diff -urN povray-3.6.1/source/fncode.h povray-3.6.1-ww/source/fncode.h
--- povray-3.6.1/source/fncode.h	2004-07-18 12:16:25.000000000 +0200
+++ povray-3.6.1-ww/source/fncode.h	2004-08-08 17:04:21.000000000 +0200
@@ -43,6 +43,9 @@
 #include "tokenize.h"
 #include "textstream.h"
 
+#include "jitcompiler.h"
+
+
 BEGIN_POV_NAMESPACE
 
 #ifndef DEBUG_FLOATFUNCTION
@@ -83,6 +86,13 @@
 	FNCODE_PRIVATE_COPY_METHOD private_copy_method;
 	FNCODE_PRIVATE_DESTROY_METHOD private_destroy_method;
 	void *private_data;
+	// JITC_FPU: 
+	// State: 
+	//    0 -> use jitc_sofunc or if NULL, then normal POV FPU
+	//    1 -> to be compiled; nothing done
+	//    2 -> function added to JIT compiler; not yet compiled
+	int jitc_state;
+	JustInTimeCompiler::SOFunction *jitc_sofunc;
 } FunctionCode;
 
 void FNCode_Copy(FunctionCode *, FunctionCode *);
diff -urN povray-3.6.1/source/fnpovfpu.cpp povray-3.6.1-ww/source/fnpovfpu.cpp
--- povray-3.6.1/source/fnpovfpu.cpp	2004-07-18 12:16:25.000000000 +0200
+++ povray-3.6.1-ww/source/fnpovfpu.cpp	2004-08-08 17:44:56.000000000 +0200
@@ -238,12 +238,31 @@
 #include "fnintern.h"
 #include "mathutil.h"
 
+#include "jitcompiler.h"
+#include <assert.h>
+
 BEGIN_POV_NAMESPACE
 
 /*****************************************************************************
 * Local preprocessor defines
 ******************************************************************************/
 
+// More or less ugly print macros for the JIT compiler: 
+#define PR_lbl_A(x)  do { strbuf->printf("lbl_%04d:;\n",x); } while(0)
+#define PR_lbl()  PR_lbl_A(pc)
+#define _PR(x) \
+	strbuf->printf(\
+	"#undef k\n" \
+	"#define k %dU\n" \
+	/*"\tk=%d;\n"*/ \
+	"\t%s\n", \
+	k,""#x );
+#define PR(x) PR_lbl(); _PR(x)
+#define PR_nolbl(x) _PR(x)
+#define PR_goto(kv)  strbuf->printf("\t goto lbl_%04d;\n",(kv));
+#define PR_direct(x...)  strbuf->printf(x);
+
+
 #define _OP_MATH_ABCOP(a,b,c,op) \
     case (a+b+0): r0 = r0 op c; break; \
     case (a+b+1): r1 = r1 op c; break; \
@@ -254,6 +273,17 @@
     case (a+b+6): r6 = r6 op c; break; \
     case (a+b+7): r7 = r7 op c; break
 
+#define _P_OP_MATH_ABCOP(a,b,c,op) \
+    case (a+b+0): PR(r0 = r0 op c;); break; \
+    case (a+b+1): PR(r1 = r1 op c;); break; \
+    case (a+b+2): PR(r2 = r2 op c;); break; \
+    case (a+b+3): PR(r3 = r3 op c;); break; \
+    case (a+b+4): PR(r4 = r4 op c;); break; \
+    case (a+b+5): PR(r5 = r5 op c;); break; \
+    case (a+b+6): PR(r6 = r6 op c;); break; \
+    case (a+b+7): PR(r7 = r7 op c;); break
+
+
 #define _OP_ABS_ABC(a,b,c) \
     case (a+b+0): r0 = fabs(c); break; \
     case (a+b+1): r1 = fabs(c); break; \
@@ -264,6 +294,17 @@
     case (a+b+6): r6 = fabs(c); break; \
     case (a+b+7): r7 = fabs(c); break
 
+#define _P_OP_ABS_ABC(a,b,c) \
+    case (a+b+0): PR(r0 = fabs(c);); break; \
+    case (a+b+1): PR(r1 = fabs(c);); break; \
+    case (a+b+2): PR(r2 = fabs(c);); break; \
+    case (a+b+3): PR(r3 = fabs(c);); break; \
+    case (a+b+4): PR(r4 = fabs(c);); break; \
+    case (a+b+5): PR(r5 = fabs(c);); break; \
+    case (a+b+6): PR(r6 = fabs(c);); break; \
+    case (a+b+7): PR(r7 = fabs(c);); break
+
+
 #define OP_MOD_ABC(a,b,c) \
     case ((a*64)+(b*8)+0): r0 = fmod(r0, c); break; \
     case ((a*64)+(b*8)+1): r1 = fmod(r1, c); break; \
@@ -274,6 +315,17 @@
     case ((a*64)+(b*8)+6): r6 = fmod(r6, c); break; \
     case ((a*64)+(b*8)+7): r7 = fmod(r7, c); break
 
+#define P_OP_MOD_ABC(a,b,c) \
+    case ((a*64)+(b*8)+0): PR(r0 = fmod(r0, c);); break; \
+    case ((a*64)+(b*8)+1): PR(r1 = fmod(r1, c);); break; \
+    case ((a*64)+(b*8)+2): PR(r2 = fmod(r2, c);); break; \
+    case ((a*64)+(b*8)+3): PR(r3 = fmod(r3, c);); break; \
+    case ((a*64)+(b*8)+4): PR(r4 = fmod(r4, c);); break; \
+    case ((a*64)+(b*8)+5): PR(r5 = fmod(r5, c);); break; \
+    case ((a*64)+(b*8)+6): PR(r6 = fmod(r6, c);); break; \
+    case ((a*64)+(b*8)+7): PR(r7 = fmod(r7, c);); break
+
+
 #define OP_MATH_AOP(a,op) \
     _OP_MATH_ABCOP((a*64),(0*8),r0,op); \
     _OP_MATH_ABCOP((a*64),(1*8),r1,op); \
@@ -284,6 +336,17 @@
     _OP_MATH_ABCOP((a*64),(6*8),r6,op); \
     _OP_MATH_ABCOP((a*64),(7*8),r7,op)
 
+#define P_OP_MATH_AOP(a,op) \
+    _P_OP_MATH_ABCOP((a*64),(0*8),r0,op); \
+    _P_OP_MATH_ABCOP((a*64),(1*8),r1,op); \
+    _P_OP_MATH_ABCOP((a*64),(2*8),r2,op); \
+    _P_OP_MATH_ABCOP((a*64),(3*8),r3,op); \
+    _P_OP_MATH_ABCOP((a*64),(4*8),r4,op); \
+    _P_OP_MATH_ABCOP((a*64),(5*8),r5,op); \
+    _P_OP_MATH_ABCOP((a*64),(6*8),r6,op); \
+    _P_OP_MATH_ABCOP((a*64),(7*8),r7,op)
+
+
 #define OP_MOD_A(a) \
     OP_MOD_ABC(a,0,r0); \
     OP_MOD_ABC(a,1,r1); \
@@ -294,6 +357,17 @@
     OP_MOD_ABC(a,6,r6); \
     OP_MOD_ABC(a,7,r7)
 
+#define P_OP_MOD_A(a) \
+    P_OP_MOD_ABC(a,0,r0); \
+    P_OP_MOD_ABC(a,1,r1); \
+    P_OP_MOD_ABC(a,2,r2); \
+    P_OP_MOD_ABC(a,3,r3); \
+    P_OP_MOD_ABC(a,4,r4); \
+    P_OP_MOD_ABC(a,5,r5); \
+    P_OP_MOD_ABC(a,6,r6); \
+    P_OP_MOD_ABC(a,7,r7)
+
+
 #define OP_ABS_A(a) \
     _OP_ABS_ABC((a*64),(0*8),r0); \
     _OP_ABS_ABC((a*64),(1*8),r1); \
@@ -304,6 +378,17 @@
     _OP_ABS_ABC((a*64),(6*8),r6); \
     _OP_ABS_ABC((a*64),(7*8),r7)
 
+#define P_OP_ABS_A(a) \
+    _P_OP_ABS_ABC((a*64),(0*8),r0); \
+    _P_OP_ABS_ABC((a*64),(1*8),r1); \
+    _P_OP_ABS_ABC((a*64),(2*8),r2); \
+    _P_OP_ABS_ABC((a*64),(3*8),r3); \
+    _P_OP_ABS_ABC((a*64),(4*8),r4); \
+    _P_OP_ABS_ABC((a*64),(5*8),r5); \
+    _P_OP_ABS_ABC((a*64),(6*8),r6); \
+    _P_OP_ABS_ABC((a*64),(7*8),r7)
+
+
 #define OP_XCC_ABOP(a,b,op) \
     case ((a*64)+(b*8)+0): if(r0 op 0.0) POVFPU_Exception(fn); break; \
     case ((a*64)+(b*8)+1): if(r1 op 0.0) POVFPU_Exception(fn); break; \
@@ -314,6 +399,17 @@
     case ((a*64)+(b*8)+6): if(r6 op 0.0) POVFPU_Exception(fn); break; \
     case ((a*64)+(b*8)+7): if(r7 op 0.0) POVFPU_Exception(fn); break; \
 
+#define P_OP_XCC_ABOP(a,b,op) \
+    case ((a*64)+(b*8)+0): PR(if(r0 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+1): PR(if(r1 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+2): PR(if(r2 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+3): PR(if(r3 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+4): PR(if(r4 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+5): PR(if(r5 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+6): PR(if(r6 op 0.0) POVFPU_Exception(fn);); break; \
+    case ((a*64)+(b*8)+7): PR(if(r7 op 0.0) POVFPU_Exception(fn);); break; \
+
+
 #define OP_MATH_ABCOP(a,b,c,op) \
     case ((a*64)+(b*8)+0): r0 = (r0 op c); break; \
     case ((a*64)+(b*8)+1): r1 = (r1 op c); break; \
@@ -324,6 +420,16 @@
     case ((a*64)+(b*8)+6): r6 = (r6 op c); break; \
     case ((a*64)+(b*8)+7): r7 = (r7 op c); break
 
+#define P_OP_MATH_ABCOP(a,b,c,op) \
+    case ((a*64)+(b*8)+0): PR(r0 = (r0 op c);); break; \
+    case ((a*64)+(b*8)+1): PR(r1 = (r1 op c);); break; \
+    case ((a*64)+(b*8)+2): PR(r2 = (r2 op c);); break; \
+    case ((a*64)+(b*8)+3): PR(r3 = (r3 op c);); break; \
+    case ((a*64)+(b*8)+4): PR(r4 = (r4 op c);); break; \
+    case ((a*64)+(b*8)+5): PR(r5 = (r5 op c);); break; \
+    case ((a*64)+(b*8)+6): PR(r6 = (r6 op c);); break; \
+    case ((a*64)+(b*8)+7): PR(r7 = (r7 op c);); break
+
 
 #define OP_ASSIGN_ABOP(a,b,op) \
     case ((a*64)+(b*8)+0): r0 = op; break; \
@@ -335,6 +441,17 @@
     case ((a*64)+(b*8)+6): r6 = op; break; \
     case ((a*64)+(b*8)+7): r7 = op; break
 
+#define P_OP_ASSIGN_ABOP(a,b,op) \
+    case ((a*64)+(b*8)+0): PR(r0 = op;); break; \
+    case ((a*64)+(b*8)+1): PR(r1 = op;); break; \
+    case ((a*64)+(b*8)+2): PR(r2 = op;); break; \
+    case ((a*64)+(b*8)+3): PR(r3 = op;); break; \
+    case ((a*64)+(b*8)+4): PR(r4 = op;); break; \
+    case ((a*64)+(b*8)+5): PR(r5 = op;); break; \
+    case ((a*64)+(b*8)+6): PR(r6 = op;); break; \
+    case ((a*64)+(b*8)+7): PR(r7 = op;); break
+
+
 #define OP_REVASSIGN_ABOP(a,b,op) \
     case ((a*64)+(b*8)+0): op = r0; break; \
     case ((a*64)+(b*8)+1): op = r1; break; \
@@ -345,6 +462,17 @@
     case ((a*64)+(b*8)+6): op = r6; break; \
     case ((a*64)+(b*8)+7): op = r7; break
 
+#define P_OP_REVASSIGN_ABOP(a,b,op) \
+    case ((a*64)+(b*8)+0): PR(op = r0;); break; \
+    case ((a*64)+(b*8)+1): PR(op = r1;); break; \
+    case ((a*64)+(b*8)+2): PR(op = r2;); break; \
+    case ((a*64)+(b*8)+3): PR(op = r3;); break; \
+    case ((a*64)+(b*8)+4): PR(op = r4;); break; \
+    case ((a*64)+(b*8)+5): PR(op = r5;); break; \
+    case ((a*64)+(b*8)+6): PR(op = r6;); break; \
+    case ((a*64)+(b*8)+7): PR(op = r7;); break
+
+
 #define OP_CMP_ABC(a,b,c) \
     case ((a*64)+(b*8)+0): ccr = (((c > r0) & 1) << 1) | ((c == r0) & 1); break; \
     case ((a*64)+(b*8)+1): ccr = (((c > r1) & 1) << 1) | ((c == r1) & 1); break; \
@@ -355,27 +483,58 @@
     case ((a*64)+(b*8)+6): ccr = (((c > r6) & 1) << 1) | ((c == r6) & 1); break; \
     case ((a*64)+(b*8)+7): ccr = (((c > r7) & 1) << 1) | ((c == r7) & 1); break; \
 
+#define P_OP_CMP_ABC(a,b,c) \
+    case ((a*64)+(b*8)+0): PR(ccr = (((c > r0) & 1) << 1) | ((c == r0) & 1);); break; \
+    case ((a*64)+(b*8)+1): PR(ccr = (((c > r1) & 1) << 1) | ((c == r1) & 1);); break; \
+    case ((a*64)+(b*8)+2): PR(ccr = (((c > r2) & 1) << 1) | ((c == r2) & 1);); break; \
+    case ((a*64)+(b*8)+3): PR(ccr = (((c > r3) & 1) << 1) | ((c == r3) & 1);); break; \
+    case ((a*64)+(b*8)+4): PR(ccr = (((c > r4) & 1) << 1) | ((c == r4) & 1);); break; \
+    case ((a*64)+(b*8)+5): PR(ccr = (((c > r5) & 1) << 1) | ((c == r5) & 1);); break; \
+    case ((a*64)+(b*8)+6): PR(ccr = (((c > r6) & 1) << 1) | ((c == r6) & 1);); break; \
+    case ((a*64)+(b*8)+7): PR(ccr = (((c > r7) & 1) << 1) | ((c == r7) & 1);); break; \
+
 #define OP_SPECIAL(a,b,c,op) \
     case ((a*64)+(b*8)+c): op; break
 
+#define P_OP_SPECIAL(a,b,c,P_op) \
+    case ((a*64)+(b*8)+c): P_op; break
+
 #define OP_SPECIAL_CASE(a,b,c) \
     case ((a*64)+(b*8)+c):
 
+
 #define OP_INT_MATH_ABOP(a,b,op) \
     case ((a*64)+(b*4)+0): iA = iA op iA; break; \
     case ((a*64)+(b*4)+1): iA = iA op iB; break; \
     case ((a*64)+(b*4)+2): iB = iB op iA; break; \
     case ((a*64)+(b*4)+3): iB = iB op iB; break
 
+#define P_OP_INT_MATH_ABOP(a,b,op) \
+    case ((a*64)+(b*4)+0): PR(iA = iA op iA;); break; \
+    case ((a*64)+(b*4)+1): PR(iA = iA op iB;); break; \
+    case ((a*64)+(b*4)+2): PR(iB = iB op iA;); break; \
+    case ((a*64)+(b*4)+3): PR(iB = iB op iB;); break
+
+
 #define OP_INT_MATH_SHIFT_ABOP(a,b,op,c) \
     case ((a*64)+(b*4)+0): iA = (c(iA) op iA); break; \
     case ((a*64)+(b*4)+1): iA = (c(iA) op iB); break; \
     case ((a*64)+(b*4)+2): iB = (c(iB) op iA); break; \
     case ((a*64)+(b*4)+3): iB = (c(iB) op iB); break
 
+#define P_OP_INT_MATH_SHIFT_ABOP(a,b,op,c) \
+    case ((a*64)+(b*4)+0): PR(iA = (c(iA) op iA);); break; \
+    case ((a*64)+(b*4)+1): PR(iA = (c(iA) op iB);); break; \
+    case ((a*64)+(b*4)+2): PR(iB = (c(iB) op iA);); break; \
+    case ((a*64)+(b*4)+3): PR(iB = (c(iB) op iB);); break
+
+
 #define OP_INT_SPECIAL(a,b,c,op) \
     case ((a*64)+(b*4)+c): op; break
 
+#define P_OP_INT_SPECIAL(a,b,c,op) \
+    case ((a*64)+(b*4)+c): PR(op;); break
+
 #define OP_INT_SPECIAL_CASE(a,b,c) \
     case ((a*64)+(b*4)+c):
 
@@ -396,6 +555,9 @@
 * Global variables
 ******************************************************************************/
 
+// Global just-in-time compiler for fast FPU. 
+JustInTimeCompiler *jit_compiler=NULL;
+
 const Opcode POVFPU_Opcodes[] =
 {
 	{ "add",   OPCODE_ADD,    ITYPE_R },
@@ -476,6 +638,30 @@
 	NULL
 };
 
+const char *POVFPU_Sys1Table_str[] =
+{
+	"sin",            // 0
+	"cos",            // 1
+	"tan",            // 2
+	"asin",           // 3
+	"acos",           // 4
+	"atan",           // 5
+	"sinh",           // 6
+	"cosh",           // 7
+	"tanh",           // 8
+	"asinh",          // 9
+	"acosh",          // 10
+	"atanh",          // 11
+	"floor",          // 12
+	"ceil",           // 13
+	"sqrt",           // 14
+	"exp",            // 15
+	"log",            // 16
+	"log10",          // 17
+	"jit_math_int",       // 18
+	NULL
+};
+
 const Sys2 POVFPU_Sys2Table[] =
 {
 	pow,            // 0
@@ -485,6 +671,14 @@
 	NULL
 };
 
+const char *POVFPU_Sys2Table_str[] =
+{
+	"pow",            // 0
+	"atan2",          // 1
+	"fmod",           // 2
+	"jit_math_div",       // 3
+	NULL
+};
 
 const unsigned int POVFPU_Sys1TableSize = 19;
 const unsigned int POVFPU_Sys2TableSize = 4;
@@ -609,6 +803,20 @@
 	POVFPU_AddConstant(1.0);
 
 	SYS_INIT_FUNCTIONS();
+	
+	// Initialize the JIT compiler: 
+	char *env_val=getenv("POV_USE_JITCOMPILER");
+	if(env_val)
+	{
+		if(!strcasecmp(env_val,"yes"))
+		{
+			jit_compiler=new JustInTimeCompiler();
+			POVFPU_BasicJITCSetup();
+		}
+	}
+	if(!jit_compiler)
+	{  Debug_Info("JIT compiler disabled. "
+		"(Use env var POV_USE_JITCOMPILER=yes to enable.)\n");  }
 }
 
 
@@ -657,6 +865,9 @@
 		POV_FREE(POVFPU_Current_Context);
 	}
 	POVFPU_Current_Context = NULL;
+	
+	if(jit_compiler)
+	{  delete jit_compiler;  jit_compiler=NULL;  }
 }
 
 
@@ -1089,32 +1300,45 @@
 		POVFPU_Functions[0].reference_count = 1;
 		SYS_ADD_FUNCTION(fn);
 		POVFPU_FunctionCnt = 1;
-
-		return 0;
 	}
-
-	if(POVFPU_FunctionCnt == MAX_FN)
+	else
 	{
-		for(fn = 0; fn < MAX_FN; fn++)
+		if(POVFPU_FunctionCnt == MAX_FN)
 		{
-			if(POVFPU_Functions[fn].reference_count == 0)
-				break;
-		}
+			for(fn = 0; fn < MAX_FN; fn++)
+			{
+				if(POVFPU_Functions[fn].reference_count == 0)
+					break;
+			}
 
-		if(fn == MAX_K)
-			Error("Maximum number (%d) of functions per scene reached.", MAX_FN);
+			if(fn == MAX_K)
+				Error("Maximum number (%d) of functions per scene reached.", MAX_FN);
+		}
+		else
+		{
+			fn = POVFPU_FunctionCnt;
+			POVFPU_FunctionCnt++;
+		}
+		
+		POVFPU_Functions = (FunctionEntry *)POV_REALLOC(POVFPU_Functions, 
+			sizeof(FunctionEntry) * POVFPU_FunctionCnt, "fn: FunctionEntry");
+		POVFPU_Functions[fn].fn = *f;
+		POVFPU_Functions[fn].reference_count = 1;
+		SYS_ADD_FUNCTION(fn);
 	}
-	else
+	
+	if(jit_compiler)
 	{
-		fn = POVFPU_FunctionCnt;
-		POVFPU_FunctionCnt++;
+		// Finally, add code for the JIT compiler: 
+		StringBuffer strbuf;
+		POVFPU_Create_JITC_Code(fn,&strbuf);
+		RefString symb_name;
+		POVFPU_GetJITCSymbol_Name(fn,&symb_name);
+		RefString tmp(strbuf.str());
+		jit_compiler->AddFunction(symb_name,tmp);
+		POVFPU_Functions[fn].fn.jitc_state=2;  // need to call compiler
 	}
-
-	POVFPU_Functions = (FunctionEntry *)POV_REALLOC(POVFPU_Functions, sizeof(FunctionEntry) * POVFPU_FunctionCnt, "fn: FunctionEntry");
-	POVFPU_Functions[fn].fn = *f;
-	POVFPU_Functions[fn].reference_count = 1;
-	SYS_ADD_FUNCTION(fn);
-
+	
 	return fn;
 }
 
@@ -1369,31 +1593,105 @@
 
 DBL POVFPU_RunDefault(FUNCTION fn)
 {
+	return(POVFPU_RunDefault(fn,0));
+}
+
+DBL POVFPU_RunDefault(FUNCTION fn,bool regs_from_ctx)
+{
+#if (DEBUG_DEFAULTCPU == 1)
+	COUNTER instr;
+	Long_To_Counter(POVFPU_Functions[fn].fn.program_size, instr);
+	Add_Counter(stats[Ray_Function_VM_Instruction_Est], stats[Ray_Function_VM_Instruction_Est], instr);
+#endif
+
+	if(!regs_from_ctx)
+	{  Increase_Counter(stats[Ray_Function_VM_Calls]);  }
+
+	// We're lazy: See if we need to compile some functions: 
+	if(POVFPU_Functions[fn].fn.jitc_state)
+	{
+		// Function may not be set when the state says we're "incomplete". 
+		assert(!POVFPU_Functions[fn].fn.jitc_sofunc);
+		
+		int state=POVFPU_Functions[fn].fn.jitc_state;
+		if(!jit_compiler)
+		{
+			// JIT compiler disabled. 
+			POVFPU_Functions[fn].fn.jitc_state=0;
+		}
+		else if(state==2)
+		{
+			// Need to call the JIT compiler. 
+			int npend=jit_compiler->NPendingFunctions();
+			if(npend)
+			{
+				JustInTimeCompiler::CompilerError ce;
+				ce=jit_compiler->Compile();
+				Debug_Info("JIT Compiler (%d functions): %s\n",
+					npend,jit_compiler->CompilerErrorStr(ce));
+				if(ce)
+				{
+					// Compiler failed. 
+					// Remove the pending functions because it has no sense 
+					// to try again. 
+					jit_compiler->DeletePendingFunctions();
+				}
+			}
+			
+			// Try to look up the function. 
+			// (We might have compiled it earlier.)
+			// If we fail, revert back to POV FPU. 
+			RefString symb_name;
+			POVFPU_GetJITCSymbol_Name(fn,&symb_name);
+			POVFPU_Functions[fn].fn.jitc_sofunc=jit_compiler->Lookup(symb_name);
+			if(POVFPU_Functions[fn].fn.jitc_sofunc)
+			{  POVFPU_Functions[fn].fn.jitc_sofunc->aqref();  }
+			POVFPU_Functions[fn].fn.jitc_state=0;
+		}
+		else if(state==1 || state)
+		{
+			// Code generation was not yet done. This may not happen. 
+			Error("OOPS: internal error: fnpovfpu.cpp:%d: state=%d, fn=%d, "
+				"name=%s\n",
+				__LINE__,state,fn,
+				POVFPU_Functions[fn].fn.name);
+		}
+	}
+	
+	if(POVFPU_Functions[fn].fn.jitc_sofunc)
+	{
+		// Use fast FPU (i.e. compiled code): 
+		return (*POVFPU_Functions[fn].fn.jitc_sofunc
+			->FPtr< DBL(*)(FUNCTION,bool) >())(fn,regs_from_ctx);
+	}
+	// Use normal POV FPU. 
+
 	StackFrame *pstack = POVFPU_Current_Context->pstackbase;
 	DBL *dblstack = POVFPU_Current_Context->dblstackbase;
 	unsigned int maxdblstacksize = POVFPU_Current_Context->maxdblstacksize;
 	DBL r0, r1, r2, r3, r4, r5, r6, r7;
-	Instruction *program = NULL;
+	Instruction *program = POVFPU_Functions[fn].fn.program;
 	unsigned int k = 0;
+	
 	unsigned int pc = 0;
-	unsigned int ccr = 0;
-	unsigned int sp = 0;
-	unsigned int psp = 0;
+	unsigned int ccr;
+	unsigned int sp;
+	unsigned int psp;
+	
+	if(regs_from_ctx)
+	{  JITC_RESTORE_STATE(POVFPU_Current_Context);  }
+	else
+	{
+		ccr=0;
+		sp=0;
+		psp=0;
+	}
 
 #if (SUPPORT_INTEGER_INSTRUCTIONS == 1)
+#error Not supported by the JIT compiler. 
 	POV_LONG iA, iB, itemp;
 #endif
 
-#if (DEBUG_DEFAULTCPU == 1)
-	COUNTER instr;
-	Long_To_Counter(POVFPU_Functions[fn].fn.program_size, instr);
-	Add_Counter(stats[Ray_Function_VM_Instruction_Est], stats[Ray_Function_VM_Instruction_Est], instr);
-#endif
-
-	Increase_Counter(stats[Ray_Function_VM_Calls]);
-
-	program = POVFPU_Functions[fn].fn.program;
-
 	while(true)
 	{
 		k = GET_K(program[pc]);
@@ -1494,7 +1792,11 @@
 				continue; // prevent increment of pc
 			OP_SPECIAL_CASE(15,0,2)                     // rts
 				if(psp == 0)
+				{
+					if(regs_from_ctx)
+					{  JITC_SAVE_STATE(POVFPU_Current_Context);  }
 					return r0;
+				}
 				psp--;
 				pc = pstack[psp].pc; // old position, will be incremented
 				fn = pstack[psp].fn;
@@ -1639,4 +1941,441 @@
 #endif
 }
 
+/*****************************************************************************
+*
+* FUNCTION
+*
+*   POVFPU_Create_JITC_Code
+*
+* INPUT
+*
+*   fn - function reference number
+*   
+* OUTPUT
+* 
+*   strbuf - string representation of source code to be compiled
+*   
+* RETURNS
+*
+*   -
+*
+* AUTHOR
+*
+*   Wolfgang Wieser based on POVFPU_RunDefault by Thorsten Froehlich. 
+*   
+* DESCRIPTION
+*
+*   Create JITCompiler - compatible code for function fn and store it in 
+*   passed strbuf. 
+*
+* CHANGES
+*
+*   -
+*
+******************************************************************************/
+
+void POVFPU_Create_JITC_Code(FUNCTION fn,StringBuffer *strbuf)
+{
+	Instruction *program = POVFPU_Functions[fn].fn.program;
+	unsigned int k = 0;
+	unsigned int pc = 0;
+	
+	RefString symb_name;
+	POVFPU_GetJITCSymbol_Name(fn,&symb_name);
+	
+	strbuf->printf("// Function: %s (fn=%u)\n",
+		POVFPU_Functions[fn].fn.name,fn);
+	strbuf->printf("extern \"C\" DBL %s(FUNCTION fn,bool regs_from_ctx);\n",
+		symb_name.str());
+	strbuf->printf("DBL %s(FUNCTION fn,bool regs_from_ctx)\n{\n",
+		symb_name.str());
+	strbuf->printf(
+	"\tStackFrame *pstack = POVFPU_Current_Context->pstackbase;\n"
+	"\tDBL *dblstack = POVFPU_Current_Context->dblstackbase;\n"
+	"\tunsigned int maxdblstacksize = POVFPU_Current_Context->maxdblstacksize;\n"
+	"\tregister DBL r0, r1, r2, r3, r4, r5, r6, r7;\n"
+	"\t//Instruction *program = NULL;\n"
+	"\t//unsigned int k = 0;\n"
+	"\t//unsigned int pc = 0;\n"
+	"\tunsigned int ccr;\n"
+	"\tunsigned int sp;\n"
+	"\tunsigned int psp;\n\n"
+	"\tif(regs_from_ctx)\n"
+	"\t{  JITC_RESTORE_STATE(POVFPU_Current_Context);  }\n"
+	"\telse\n"
+	"\t{\n"
+	"\t\tccr=0;\n"
+	"\t\tsp=0;\n"
+	"\t\tpsp=0;\n"
+	"\t}\n"
+	);
+	
+	while(pc<POVFPU_Functions[fn].fn.program_size)
+	{
+		k = GET_K(program[pc]);
+		switch(GET_OP(program[pc]))
+		{
+			P_OP_MATH_AOP(0,+);           // add   Rs, Rd
+			P_OP_MATH_AOP(1,-);           // sub   Rs, Rd
+			P_OP_MATH_AOP(2,*);           // mul   Rs, Rd
+			P_OP_MATH_AOP(3,/);           // div   Rs, Rd
+			P_OP_MOD_A(4);                // mod   Rs, Rd
+
+			P_OP_ASSIGN_ABOP(5,0,r0);     // move  R0, Rd
+			P_OP_ASSIGN_ABOP(5,1,r1);     // move  R1, Rd
+			P_OP_ASSIGN_ABOP(5,2,r2);     // move  R2, Rd
+			P_OP_ASSIGN_ABOP(5,3,r3);     // move  R3, Rd
+			P_OP_ASSIGN_ABOP(5,4,r4);     // move  R4, Rd
+			P_OP_ASSIGN_ABOP(5,5,r5);     // move  R5, Rd
+			P_OP_ASSIGN_ABOP(5,6,r6);     // move  R6, Rd
+			P_OP_ASSIGN_ABOP(5,7,r7);     // move  R7, Rd
+
+			P_OP_CMP_ABC(6,0,r0);         // cmp   R0, Rd
+			P_OP_CMP_ABC(6,1,r1);         // cmp   R1, Rd
+			P_OP_CMP_ABC(6,2,r2);         // cmp   R2, Rd
+			P_OP_CMP_ABC(6,3,r3);         // cmp   R3, Rd
+			P_OP_CMP_ABC(6,4,r4);         // cmp   R4, Rd
+			P_OP_CMP_ABC(6,5,r5);         // cmp   R5, Rd
+			P_OP_CMP_ABC(6,6,r6);         // cmp   R6, Rd
+			P_OP_CMP_ABC(6,7,r7);         // cmp   R7, Rd
+
+			P_OP_ASSIGN_ABOP(7,0,-r0);    // neg   R0, Rd
+			P_OP_ASSIGN_ABOP(7,1,-r1);    // neg   R1, Rd
+			P_OP_ASSIGN_ABOP(7,2,-r2);    // neg   R2, Rd
+			P_OP_ASSIGN_ABOP(7,3,-r3);    // neg   R3, Rd
+			P_OP_ASSIGN_ABOP(7,4,-r4);    // neg   R4, Rd
+			P_OP_ASSIGN_ABOP(7,5,-r5);    // neg   R5, Rd
+			P_OP_ASSIGN_ABOP(7,6,-r6);    // neg   R6, Rd
+			P_OP_ASSIGN_ABOP(7,7,-r7);    // neg   R7, Rd
+
+			P_OP_ABS_A(8);                // abs   Rs, Rd
+
+			P_OP_MATH_ABCOP(9,0,POVFPU_Consts[k],+);      // addi  k, Rd
+			P_OP_MATH_ABCOP(9,1,POVFPU_Consts[k],-);      // subi  k, Rd
+			P_OP_MATH_ABCOP(9,2,POVFPU_Consts[k],*);      // muli  k, Rd
+			P_OP_MATH_ABCOP(9,3,POVFPU_Consts[k],/);      // divi  k, Rd
+			P_OP_MOD_ABC(9,4,POVFPU_Consts[k]);           // modi  k, Rd
+			P_OP_ASSIGN_ABOP(9,5,POVFPU_Consts[k]);       // loadi k, Rd
+
+			P_OP_CMP_ABC(9,6,POVFPU_Consts[k]);           // cmpi  k, Rs
+
+			P_OP_ASSIGN_ABOP(10,0,ccr == 1);              // seq   Rd
+			P_OP_ASSIGN_ABOP(10,1,ccr != 1);              // sne   Rd
+			P_OP_ASSIGN_ABOP(10,2,ccr == 2);              // slt   Rd
+			P_OP_ASSIGN_ABOP(10,3,ccr >= 1);              // sle   Rd
+			P_OP_ASSIGN_ABOP(10,4,ccr == 0);              // sgt   Rd
+			P_OP_ASSIGN_ABOP(10,5,ccr <= 1);              // sge   Rd
+			P_OP_MATH_ABCOP(10,6,0.0,==);                 // teq   Rd
+			P_OP_MATH_ABCOP(10,7,0.0,!=);                 // tne   Rd
+
+			P_OP_ASSIGN_ABOP(11,0,POVFPU_Globals[k]);     // load  0(k), Rd
+			P_OP_ASSIGN_ABOP(11,1,dblstack[sp+k]);        // load  SP(k), Rd
+
+			P_OP_REVASSIGN_ABOP(12,0,POVFPU_Globals[k]);  // store Rs, 0(k)
+			P_OP_REVASSIGN_ABOP(12,1,dblstack[sp+k]);     // store Rs, SP(k)
+
+			P_OP_SPECIAL(13,0,0,PR(if(ccr == 1)) PR_goto(k)); // beq   k
+			P_OP_SPECIAL(13,1,0,PR(if(ccr != 1)) PR_goto(k)); // bne   k
+			P_OP_SPECIAL(13,2,0,PR(if(ccr == 2)) PR_goto(k)); // blt   k
+			P_OP_SPECIAL(13,3,0,PR(if(ccr >= 1)) PR_goto(k)); // ble   k
+			P_OP_SPECIAL(13,4,0,PR(if(ccr == 0)) PR_goto(k)); // bgt   k  (OK)
+			P_OP_SPECIAL(13,5,0,PR(if(ccr <= 1)) PR_goto(k)); // bge   k
+
+			P_OP_XCC_ABOP(14,0,==);                       // xeq   Rd
+			P_OP_XCC_ABOP(14,1,!=);                       // xne   Rd
+			P_OP_XCC_ABOP(14,2,<);                        // xlt   Rd
+			P_OP_XCC_ABOP(14,3,<=);                       // xle   Rd
+			P_OP_XCC_ABOP(14,4,>);                        // xgt   Rd
+			P_OP_XCC_ABOP(14,5,>=);                       // xge   Rd
+
+			P_OP_SPECIAL(14,6,0,PR(if((r0 == 0.0) && (r0 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R0
+			P_OP_SPECIAL(14,6,1,PR(if((r0 == 0.0) && (r1 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R1
+			P_OP_SPECIAL(14,6,2,PR(if((r0 == 0.0) && (r2 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R2
+			P_OP_SPECIAL(14,6,3,PR(if((r0 == 0.0) && (r3 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R3
+			P_OP_SPECIAL(14,6,4,PR(if((r0 == 0.0) && (r4 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R4
+			P_OP_SPECIAL(14,6,5,PR(if((r0 == 0.0) && (r5 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R5
+			P_OP_SPECIAL(14,6,6,PR(if((r0 == 0.0) && (r6 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R6
+			P_OP_SPECIAL(14,6,7,PR(if((r0 == 0.0) && (r7 == 0.0)) POVFPU_Exception(fn);)); // xdz   R0, R7
+
+			OP_SPECIAL_CASE(15,0,0)                     // jsr   k
+				PR_lbl();
+				PR_direct("\tpstack[psp].pc = (unsigned int)&&lbl_%04d;\n",pc+1);
+				//pstack[psp].fn = fn;
+				PR_nolbl(psp++;
+				if(psp >= MAX_CALL_STACK_SIZE)
+					POVFPU_Exception(fn, "Maximum function evaluation recursion level reached."););
+				PR_goto(k);
+				break;  // continue; // prevent increment of pc
+			OP_SPECIAL_CASE(15,0,1)                     // jmp   k
+				PR_goto(k);
+				break;
+			OP_SPECIAL_CASE(15,0,2)                     // rts
+				PR(if(psp == 0)
+				{
+					if(regs_from_ctx)
+					{  JITC_SAVE_STATE(POVFPU_Current_Context);  }
+					return r0;
+				}
+				psp--;);
+				PR_direct("\tgoto *(void*)pstack[psp].pc;\n");
+				break;
+			OP_SPECIAL_CASE(15,0,3)                     // call  k
+				PR( JITC_SAVE_STATE(POVFPU_Current_Context); );
+				PR_nolbl( r0=POVFPU_RunDefault(k,1); );
+		/*{
+			RefString tmp;
+			POVFPU_GetJITCSymbol_Name(k,&tmp);
+			PR_direct("\tr0 = %s(k,1);\n",tmp.str());
+		}*/
+				PR_nolbl(
+				maxdblstacksize = POVFPU_Current_Context->maxdblstacksize;
+				dblstack = POVFPU_Current_Context->dblstackbase;
+				JITC_RESTORE_STATE(POVFPU_Current_Context););
+				break;  // continue; // prevent increment of pc
+
+			OP_SPECIAL_CASE(15,0,4)                     // sys1  k
+				PR_lbl();
+				PR_direct("\tr0 = %s(r0);\n",POVFPU_Sys1Table_str[k]);
+				break;
+			OP_SPECIAL_CASE(15,0,5)                     // sys2  k
+				PR_lbl();
+				PR_direct("\tr0 = %s(r0,r1);\n",POVFPU_Sys2Table_str[k]);
+				break;
+			OP_SPECIAL_CASE(15,0,6)                     // trap  k
+				PR(r0 = POVFPU_TrapTable[k].fn(&dblstack[sp], fn);
+				maxdblstacksize = POVFPU_Current_Context->maxdblstacksize;
+				dblstack = POVFPU_Current_Context->dblstackbase;);
+				break;
+			OP_SPECIAL_CASE(15,0,7)                     // traps k
+				PR(POVFPU_TrapSTable[k].fn(&dblstack[sp], fn, sp);
+				maxdblstacksize = POVFPU_Current_Context->maxdblstacksize;
+				dblstack = POVFPU_Current_Context->dblstackbase;);
+				break;
+
+			OP_SPECIAL_CASE(15,1,0)                     // grow  k
+				PR(if((unsigned int)((unsigned int)sp + (unsigned int)k) >= (unsigned int)MAX_K)
+				{
+					POVFPU_Exception(fn, "Stack full. Possible infinite recursive function call.");
+				}
+				else if(sp + k >= maxdblstacksize)
+				{
+					maxdblstacksize = POVFPU_Current_Context->maxdblstacksize = 
+						POVFPU_Current_Context->maxdblstacksize + 
+							max(k + 1, (unsigned int)256);
+					dblstack = POVFPU_Current_Context->dblstackbase = 
+						(DBL *)POV_REALLOC(dblstack, sizeof(DBL) * maxdblstacksize, "fn: stack");
+				});
+				break;
+			OP_SPECIAL_CASE(15,1,1)                     // push  k
+				PR(if(sp + k >= maxdblstacksize)
+					POVFPU_Exception(fn, "Function evaluation stack overflow.");
+				sp += k;);
+				break;
+			OP_SPECIAL_CASE(15,1,2)                     // pop   k
+				PR(if(k > sp)
+					POVFPU_Exception(fn, "Function evaluation stack underflow.");
+				sp -= k;);
+				break;
+#if (SUPPORT_INTEGER_INSTRUCTIONS == 1)
+#error NOT SUPPORTED BY JITC. 
+			OP_SPECIAL_CASE(15,1,3)                     // iconv
+				PR(iA = POV_LONG(r0););
+				break;
+			OP_SPECIAL_CASE(15,1,4)                     // fconv
+				PR(r0 = DBL(iA););
+				break;
+
+			OP_SPECIAL_CASE(15,1,5)                     // reserved
+				POVFPU_Exception(fn, "Internal error - reserved function VM opcode found!");
+				break;
+
+			P_OP_INT_MATH_ABOP(15,32,+);                  // add   s, d
+			P_OP_INT_MATH_ABOP(15,33,-);                  // sub   s, d
+			P_OP_INT_MATH_ABOP(15,34,*);                  // mul   s, d
+			P_OP_INT_SPECIAL(15,35,0,iA = iA / iB);       // div   B, A
+			P_OP_INT_SPECIAL(15,35,1,iB = iB / iA);       // div   A, B
+			P_OP_INT_SPECIAL(15,35,2,iA = iA % iB);       // mod   B, A
+			P_OP_INT_SPECIAL(15,35,3,iB = iB % iA);       // mod   A, B
+
+			P_OP_INT_SPECIAL(15,36,0,ccr = (((iB > iA) & 1) << 1) | ((iB == iA) & 1)); // cmp   B, A
+			P_OP_INT_SPECIAL(15,36,1,ccr = (((iA > iB) & 1) << 1) | ((iA == iB) & 1)); // cmp   A, B
+
+			P_OP_INT_SPECIAL(15,36,2,itemp = iA; iA = iB; iB = itemp); // exg   A, B
+
+			P_OP_INT_SPECIAL(15,36,3,iA = iB = 0);        // clr   A, B
+			P_OP_INT_SPECIAL(15,37,0,iA = 0);             // clr   A
+			P_OP_INT_SPECIAL(15,37,1,iB = 0);             // clr   B
+
+			P_OP_INT_SPECIAL(15,37,2,iA = iB);            // move  B, A
+			P_OP_INT_SPECIAL(15,37,3,iB = iA);            // move  A, B
+
+			P_OP_INT_SPECIAL(15,38,0,iA = -iA);           // neg   A
+			P_OP_INT_SPECIAL(15,38,1,iB = -iB);           // neg   B
+
+			P_OP_INT_SPECIAL(15,38,2,iA = abs(iA));       // abs   A
+			P_OP_INT_SPECIAL(15,38,3,iB = abs(iB));       // abs   B
+
+			P_OP_INT_SPECIAL(15,39,0,iA = iA + k);        // addi  k, A
+			P_OP_INT_SPECIAL(15,39,1,iB = iB + k);        // addi  k, B
+			P_OP_INT_SPECIAL(15,39,2,iA = iA - k);        // subi  k, A
+			P_OP_INT_SPECIAL(15,39,3,iB = iB - k);        // subi  k, B
+
+			P_OP_INT_MATH_SHIFT_ABOP(15,40,<<,POV_LONG);     // asl   s, d
+			P_OP_INT_MATH_SHIFT_ABOP(15,41,>>,POV_LONG);     // asr   s, d
+			P_OP_INT_MATH_SHIFT_ABOP(15,42,<<,POV_ULONG);    // lsl   s, d
+			P_OP_INT_MATH_SHIFT_ABOP(15,43,>>,POV_ULONG);    // lsr   s, d
+
+			P_OP_INT_MATH_ABOP(15,44,&);                  // and   s, d
+			P_OP_INT_MATH_ABOP(15,45,|);                  // or    s, d
+			P_OP_INT_MATH_ABOP(15,46,^);                  // xor   s, d
+			P_OP_INT_SPECIAL(15,47,0,iA = !iA);           // not   A, A
+			P_OP_INT_SPECIAL(15,47,1,iA = !iB);           // not   B, A
+			P_OP_INT_SPECIAL(15,47,2,iB = !iA);           // not   A, B
+			P_OP_INT_SPECIAL(15,47,3,iB = !iB);           // not   B, B
+
+			P_OP_INT_SPECIAL(15,48,0,iA = k);             // loadi A
+			P_OP_INT_SPECIAL(15,48,1,iB = k);             // loadi B
+			P_OP_INT_SPECIAL(15,48,2,iA = (iA << 16) | k);// ldhi  A
+			P_OP_INT_SPECIAL(15,48,3,iB = (iB << 16) | k);// ldhi  B
+
+			P_OP_INT_SPECIAL(15,49,0,iA = max(POV_LONG(k), iA)); // max   k, A
+			P_OP_INT_SPECIAL(15,49,1,iB = max(POV_LONG(k), iB)); // max   k, B
+			P_OP_INT_SPECIAL(15,49,2,iA = min(POV_LONG(k), iA)); // min   k, A
+			P_OP_INT_SPECIAL(15,49,3,iB = min(POV_LONG(k), iB)); // min   k, B
+
+			P_OP_INT_SPECIAL(15,50,0,iA = (POV_LONG(iA) << k));  // asl   k, A
+			P_OP_INT_SPECIAL(15,50,1,iB = (POV_LONG(iB) >> k));  // asr   k, B
+			P_OP_INT_SPECIAL(15,50,2,iA = (POV_ULONG(iA) << k)); // lsl   k, A
+			P_OP_INT_SPECIAL(15,50,3,iB = (POV_ULONG(iB) >> k)); // lsr   k, B
+#endif
+			default:                                    // nop
+				break;
+		}
+
+		pc++;
+	}
+	
+	strbuf->printf("}\n");
+}
+
+/*****************************************************************************
+*
+* FUNCTION
+*
+*   POVFPU_GetJITCSymbol_Name
+*
+* INPUT
+*
+*   fn - function reference number
+*   
+* OUTPUT
+* 
+*   dest - stores string representation of symbol name
+*   
+* RETURNS
+*
+*   -
+*
+* AUTHOR
+*
+*   Wolfgang Wieser
+*   
+* DESCRIPTION
+*
+*   Return JIT compiler symbol name associated with specified function. 
+*
+* CHANGES
+*
+*   -
+*
+******************************************************************************/
+
+void POVFPU_GetJITCSymbol_Name(FUNCTION fn,RefString *dest)
+{
+	dest->sprintf(0,"POV_JIT_FPU_%u",fn);
+}
+
+/*****************************************************************************
+*
+* FUNCTION
+*
+*   POVFPU_BasicJITCSetup()
+*
+* INPUT
+*
+*   -
+*   
+* OUTPUT
+* 
+*   -
+*   
+* RETURNS
+*
+*   -
+*
+* AUTHOR
+*
+*   Wolfgang Wieser
+*   
+* DESCRIPTION
+*
+*   Set up JIT compiler (compiler flags, etc). 
+*
+* CHANGES
+*
+*   -
+*
+******************************************************************************/
+
+void POVFPU_BasicJITCSetup()
+{
+	RefString tmp;
+	
+	#if 0
+	tmp.set(
+		"g++ -nostartfiles -shared -x c++ "
+		"-O3 -fno-rtti -fno-exceptions -ffast-math -funit-at-a-time "
+		"-finline-functions -DHAVE_CONFIG_H -pipe -Wno-multichar "
+		"-I. -I/usr/src/film/povray/povray-3.6.1-ww/source "
+		"-I/usr/src/film/povray/povray-3.6.1-ww/source/base "
+		"-I/usr/src/film/povray/povray-3.6.1-ww/unix "
+		"-I/usr/src/film/povray/povray-3.6.1-modified-build "
+		"-I/usr/src/film/povray/povray-3.6.1-modified-build/source "
+		);
+	#else
+	#ifndef JITC_USED_COMPILER
+	#error "Need JITC_USED_COMPILER (should be in conf.h)."
+	#endif
+	tmp.set(
+		JITC_USED_COMPILER " -x c++ " JITC_COMPILER_FLAGS 
+		" -Wno-all -DHAVE_CONFIG_H -nostartfiles -shared "
+		"-I" JITC_COMPILER_SRC "/source "
+		"-I" JITC_COMPILER_SRC "/source/base "
+		"-I" JITC_COMPILER_SRC "/unix "
+		"-I" JITC_COMPILER_BUILD " " JITC_COMPILER_INCS
+		);
+	#endif
+	jit_compiler->SetCmdLine(tmp);
+	
+	tmp.set(
+		"#include \"frame.h\"\n"
+		"#include \"function.h\"\n"
+		"#include \"fnpovfpu.h\"\n"
+		"#include \"fnintern.h\"\n"
+		"\n"
+		"BEGIN_POV_NAMESPACE\n\n"
+		"inline DBL jit_math_int(DBL x)  {  return((int)x);  }\n"
+		"inline DBL jit_math_div(DBL x,DBL y)  {  return((int)(x/y));  }\n"
+		);
+	jit_compiler->SetCodeHead(tmp);
+	
+	tmp.set(
+		"\n"
+		"END_POV_NAMESPACE\n"
+		);
+	jit_compiler->SetCodeTail(tmp);
+	
+	Debug_Info("JIT compiler initialized.\n");
+}
+
 END_POV_NAMESPACE
diff -urN povray-3.6.1/source/fnpovfpu.h povray-3.6.1-ww/source/fnpovfpu.h
--- povray-3.6.1/source/fnpovfpu.h	2004-07-18 12:16:25.000000000 +0200
+++ povray-3.6.1-ww/source/fnpovfpu.h	2004-08-08 17:04:21.000000000 +0200
@@ -119,9 +119,29 @@
 	#if (SYS_FUNCTIONS == 1)
 	DBL *dblstack;
 	#endif
+	
+	// Allows to save the complete state: 
+	/*DBL r0, r1, r2, r3, r4, r5, r6, r7;*/
+	unsigned int ccr;
+	unsigned int sp;
+	unsigned int psp;
 } FPUContext;
 
 
+// I'm not sure if the r# registers need to be saved and restored. 
+// It seems to work well without but upon expeiencing trouble, enable 
+// it again. Then also include the fields in the above FPUContext_Struct. 
+#define JITC_RESTORE_STATE(cctx) \
+	/*r0=cctx->r0;  r1=cctx->r1;  r2=cctx->r2;  r3=cctx->r3;*/ \
+	/*r4=cctx->r4;  r5=cctx->r5;  r6=cctx->r6;  r7=cctx->r7;*/ \
+	ccr=cctx->ccr;  sp=cctx->sp;  psp=cctx->psp;
+
+#define JITC_SAVE_STATE(cctx) \
+	/*cctx->r0=r0;  cctx->r1=r1;  cctx->r2=r2;  cctx->r3=r3;*/ \
+	/*cctx->r4=r4;  cctx->r5=r5;  cctx->r6=r6;  cctx->r7=r7;*/ \
+	cctx->ccr=ccr;  cctx->sp=sp;  cctx->psp=psp;
+
+
 #define OPCODE(i,s,d) ((i << 6) | (s << 3) | d)
 
 #define OPCODE_ADD    OPCODE(0,0,0)
@@ -196,6 +216,12 @@
 
 extern FPUContext *POVFPU_Current_Context;
 
+// Global just-in-time compiler for fast FPU. 
+class JustInTimeCompiler;
+class StringBuffer;
+class RefString;
+extern JustInTimeCompiler *jit_compiler;
+
 void POVFPU_Init();
 void POVFPU_Terminate();
 void POVFPU_Reset();
@@ -212,6 +238,10 @@
 FPUContext *POVFPU_NewContext();
 FPUContext *POVFPU_SwitchContext(FPUContext *context);
 DBL POVFPU_RunDefault(FUNCTION k);
+DBL POVFPU_RunDefault(FUNCTION k,bool regs_from_ctx);  // <-- for JIT compiler
+void POVFPU_Create_JITC_Code(FUNCTION fn,StringBuffer *strbuf);
+void POVFPU_GetJITCSymbol_Name(FUNCTION fn,RefString *dest);
+void POVFPU_BasicJITCSetup();
 
 END_POV_NAMESPACE
 
diff -urN povray-3.6.1/source/fnsyntax.cpp povray-3.6.1-ww/source/fnsyntax.cpp
--- povray-3.6.1/source/fnsyntax.cpp	2004-07-18 12:16:25.000000000 +0200
+++ povray-3.6.1-ww/source/fnsyntax.cpp	2004-08-08 17:04:21.000000000 +0200
@@ -1455,7 +1455,7 @@
 				fprintf(f, "%s", i->variable);
 				break;
 			case OP_CALL:
-				fprintf(f, "fn%d", (int)(i->call.fn));
+				fprintf(f, "fn%d_%s", (int)(i->call.fn),i->call.name);
 				break;
 			case OP_CMP_EQ:
 				fprintf(f, " == ");
diff -urN povray-3.6.1/source/jitcompiler.cpp povray-3.6.1-ww/source/jitcompiler.cpp
--- povray-3.6.1/source/jitcompiler.cpp	1970-01-01 01:00:00.000000000 +0100
+++ povray-3.6.1-ww/source/jitcompiler.cpp	2004-08-08 17:04:21.000000000 +0200
@@ -0,0 +1,418 @@
+/*
+ * jitcompiler.cc - Just-in-time compiler for arbitrary functions. 
+ * 
+ * Copyright (c) 2004 by Wolfgang Wieser
+ * 
+ * This file is put under the POVRay license (povlegal.doc). 
+ * 
+ */
+
+#include "frame.h"
+#include "userio.h"
+#include "jitcompiler.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <assert.h>
+
+BEGIN_POV_NAMESPACE
+
+JustInTimeCompiler::SObject::SObject(const RefString &_so_file) : 
+	so_file(_so_file),
+	func_list()
+{
+	so_hdl=NULL;
+}
+
+JustInTimeCompiler::SObject::~SObject()
+{
+	if(so_hdl)
+	{
+		Debug_Info("JIT compiler: dlclose(%s)\n",so_file.str());
+		dlclose(so_hdl);
+		so_hdl=NULL;
+	}
+	while(!func_list.is_empty())
+	{  delete func_list.poplast();  }
+}
+
+/******************************************************************************/
+
+JustInTimeCompiler::SOFunction &JustInTimeCompiler::SOFunction::operator=(
+	const SOFunction &)
+{
+	abort();
+	return(*this);
+}
+
+JustInTimeCompiler::SOFunction::SOFunction(const RefString &_symb_name) : 
+	symb_name(_symb_name)
+{
+	sobject=NULL;
+	_fptr=NULL;
+	refcnt=0;
+}
+
+JustInTimeCompiler::SOFunction::SOFunction(const SOFunction &) : symb_name()
+{
+	abort();
+}
+
+JustInTimeCompiler::SOFunction::~SOFunction()
+{
+	assert(refcnt==0);
+	sobject=NULL;
+	_fptr=NULL;
+}
+
+/******************************************************************************/
+
+JustInTimeCompiler::CompFuncNode::CompFuncNode(const RefString &_symb_name,
+	const RefString &_func_code) : 
+	LinkedListBase<CompFuncNode>(),
+	symb_name(_symb_name),
+	func_code(_func_code)
+{
+	/* empty */
+}
+
+JustInTimeCompiler::CompFuncNode::~CompFuncNode()
+{
+}
+
+/******************************************************************************/
+
+const char *JustInTimeCompiler::CompilerErrorStr(CompilerError ce)
+{
+	static char tmp[256];
+	
+	const char *err_str=NULL;
+	switch(ce)
+	{
+		case CE_Success:                  return("success");
+		case CE_NothingToCompile:         return("success (nothing to do)");
+		case CE_FailedToCreateTemporary:  err_str="create temporary";  break;
+		case CE_FailedToOpenTemporary:    err_str="open temporary";  break;
+		case CE_FailedToCloseTemporary:   err_str="close temporary";  break;
+		case CE_FailedToUnlinkTemporary:  err_str="unlink temporary";  break;
+		case CE_FailedToExecute:          err_str="execure compiler";  break;
+		case CE_CompilationFailure:       return("compilation failed");
+		case CE_CompilerKilled:           return("compiler killed");
+		case CE_FailedToDLOpen:
+			snprintf(tmp,256,"failed to open shared object: %s\n",dlerror());
+			return(tmp);
+		case CE_FailedToUnlinkOutfile:    err_str="unlink outfile";  break;
+		case CE_LookupFailure:            return("symbol lookup failure");
+	}
+	
+	if(err_str)
+	{
+		snprintf(tmp,256,"failed to %s: %s\n",err_str,strerror(errno));
+		return(tmp);
+	}
+	
+	return("[unknown error]");
+}
+
+
+JustInTimeCompiler::CompilerError JustInTimeCompiler::Compile()
+{
+	RefString out_file;  // stays NULL ref
+	CompilerError ce=_DoCompile(out_file);
+	return(ce);
+}
+
+
+JustInTimeCompiler::CompilerError JustInTimeCompiler::_DoCompile(
+	const RefString &_outfile)
+{
+	if(comp_func_list.is_empty())
+	{  return(CE_NothingToCompile);  }
+	
+	// First, we need a temporary file: 
+	FILE *tfd=NULL;
+	int tfd_n=-1;
+	char tmpfile[]="/tmp/jitcompiler-XXXXXX\0";
+	bool tmp_created=0;
+	bool outfile_created=0;
+	
+	RefString outfile(_outfile);
+	if(!outfile)
+	{  outfile.sprintf(0,"./jit-%d.so",so_serial++);  }
+	
+	CompilerError rv=CE_Success;
+	do {
+		// Open a temporary file where to put the content to be compiled: 
+		tfd_n=mkstemp(tmpfile);
+		if(tfd_n<0)
+		{  rv=CE_FailedToCreateTemporary;  break;  }
+		tmp_created=1;
+		tfd=fdopen(tfd_n,"w");
+		if(!tfd)
+		{  rv=CE_FailedToOpenTemporary;  break;  }
+		tfd_n=-1;  // now handeled via tfd
+		
+		// Write the content there: 
+		// I'm too lazy to check errors here...
+		fprintf(tfd,"/* JIT-Compiler automatically generated code. */\n\n");
+		fprintf(tfd,"/*-- Code head: --*/\n\n");
+		if(code_head.str())
+		{  fprintf(tfd,"%s\n",code_head.str());  }
+		fprintf(tfd,"/*-- Function bodies: --*/\n\n");
+		for(CompFuncNode *i=comp_func_list.first(); i; i=i->next)
+		{  fprintf(tfd,"%s\n",i->func_code.str());  }
+		fprintf(tfd,"/*-- Code tail: --*/\n\n");
+		if(code_tail.str())
+		{  fprintf(tfd,"%s\n",code_tail.str());  }
+		fprintf(tfd,"/*-- EOF --*/\n");
+	} while(0);
+	
+	// Close the temporary file. We will then call the compiler. 
+	if(tfd)
+	{
+		if(fclose(tfd)<0 && !rv)
+		{  rv=CE_FailedToCloseTemporary;  }
+		tfd=NULL;
+	}
+	else if(tfd_n>=0)
+	{
+		close(tfd_n);
+		tfd_n=-1;
+	}
+	
+	// Actually call the compiler: 
+	if(!rv)
+	{
+		// Compose the command line: 
+		RefString cmd;
+		cmd.sprintf(0,"%s %s %s %s %s",
+			cmdline.str() ? cmdline.str() : "",
+			infile_opt.str() ? infile_opt.str() : "",
+			tmpfile,
+			outfile_opt.str() ? outfile_opt.str() : "",
+			outfile.str());
+		
+		// Finally run the compiler: 
+		Debug_Info("JIT compiler: %s\n",cmd.str());
+		int rv=system(cmd.str());
+		if(rv==-1)
+		{  rv=CE_FailedToExecute;  }
+		else if(WIFEXITED(rv))
+		{
+			outfile_created=1;
+			int status=WEXITSTATUS(rv);
+			if(status==127)
+			{  rv=CE_FailedToExecute;  }
+			else if(status)
+			{  rv=CE_CompilationFailure;  }
+		}
+		else if(WIFSIGNALED(rv))
+		{
+			outfile_created=1;
+			rv=CE_CompilerKilled;
+		}
+	}
+	
+	// Remove the temporary file: 
+	if(tmp_created)
+	{
+		// We created the temp file, so delete it. 
+		if(unlink(tmpfile)<0)
+		{
+			if(errno!=ENOENT && !rv)
+			{  rv=CE_FailedToUnlinkTemporary;  }
+		}
+	}
+	
+	// Okay, now load the shared object: 
+	SObject *so=NULL;
+	if(!rv)
+	{
+		Debug_Info("JIT compiler: dlopen(%s)... ",outfile.str());
+		so=new SObject(outfile);
+		so->so_hdl=dlopen(outfile.str(), RTLD_NOW | RTLD_LOCAL );
+		if(!so->so_hdl)
+		{
+			delete so;  so=NULL;
+			rv=CE_FailedToDLOpen;
+		}
+		Debug_Info(so ? "OK\n" : "failed\n");
+	}
+	
+	// Remove output file of compiler: 
+	if(outfile_created)
+	{
+		if(unlink(outfile.str())<0)
+		{
+			if(errno!=ENOENT && !rv)
+			{  rv=CE_FailedToUnlinkOutfile;  }
+		}
+	}
+	
+	if(rv && so)
+	{  delete so;  so=NULL;  }
+	
+	// Function lookup etc. 
+	if(so)
+	{
+		// rv=0 (success) here. 
+		
+		so_list.append(so);   // At the END of the list!
+		
+		// These functions are now compiled. 
+		// Look them up and remove them from the pending list. 
+		int nfail=0;
+		Debug_Info("JIT compiler: DL_Lookup.");
+		while(!comp_func_list.is_empty())
+		{
+			CompFuncNode *cfn=comp_func_list.popfirst();
+			
+			SOFunction *f=new SOFunction(cfn->symb_name);
+			
+			// This cannot handle sybols with NULL pointer. 
+			// On most systems this cannot happen. Otherwise one would 
+			// have to use the dlerror() trick described in the dlopen(3) 
+			// manual page. 
+			f->_fptr=dlsym(so->so_hdl,f->symb_name.str());
+			if(!f->_fptr)
+			{  delete f;  ++nfail;  }
+			else
+			{
+				so->func_list.append(f);
+				f->sobject=so;
+			}
+			Debug_Info(".");
+			
+			delete cfn;
+		}
+		
+		if(nfail)
+		{
+			_RemoveObject(so);  so=NULL;
+			rv=CE_LookupFailure;
+			Debug_Info("%d failed\n",nfail);
+		}
+		else
+		{  Debug_Info("OK\n");  }
+	}
+	
+	return(rv);
+}
+
+
+JustInTimeCompiler::SOFunction *JustInTimeCompiler::_Lookup(
+	const char *symb_name)
+{
+	// Go last-to-first because the user will probably look up 
+	// functions in the just-compiled shared object. 
+	SOFunction *func=NULL;
+	for(SObject *so=so_list.last(); so; so=so->prev)
+	{
+		for(SOFunction *f=so->func_list.first(); f; f=f->next)
+		{
+			if(f->symb_name==symb_name)
+			{  func=f;  goto leave_both;  }
+		}
+	}
+	leave_both:;
+	// This works for func=NULL, too: 
+	Debug_Info("JIT compiler: VM lookup: %s -> %p\n",symb_name,func->fptr());
+	return(func);
+}
+
+
+void JustInTimeCompiler::AddFunction(const RefString &_symb_name,
+	const RefString &_func_code)
+{
+	CompFuncNode *cfn=new CompFuncNode(_symb_name,_func_code);
+	comp_func_list.append(cfn);
+}
+
+void JustInTimeCompiler::AddFunction(const char *_symb_name,
+	const RefString &_func_code)
+{
+	RefString tmp(_symb_name);
+	AddFunction(tmp,_func_code);
+}
+
+
+void JustInTimeCompiler::DeletePendingFunctions()
+{
+	// Delete pending functions: 
+	while(!comp_func_list.is_empty())
+	{  delete comp_func_list.popfirst();  }
+}
+
+
+int JustInTimeCompiler::_RemoveFunction(SOFunction *func)
+{
+	if(!func)  return(0);
+	
+	SObject *so=func->sobject;
+	if(so)
+	{
+		so->func_list.dequeue(func);
+		func->sobject=NULL;
+	}
+	
+	delete func;
+	
+	if(so && so->func_list.is_empty())
+	{
+		delete so_list.dequeue(so);   // <-- will dlclose()
+		return(1);
+	}
+	
+	return(0);
+}
+
+
+void JustInTimeCompiler::_RemoveObject(SObject *so)
+{
+	// Note: _RemoveFunction() will delete the shared object when 
+	//      all functions in it were deleted. 
+	while(!_RemoveFunction(so->func_list.first()));
+}
+
+
+void JustInTimeCompiler::Clear()
+{
+	DeletePendingFunctions();
+	
+	// Delete all functions in all shared objects. 
+	// The shared objects are deleted automatically once all 
+	// associated functions were removed. 
+	while(!so_list.is_empty())
+	{  _RemoveObject(so_list.first());  }
+	
+	// Reset shared object file name serial counter: 
+	so_serial=0;
+}
+
+
+JustInTimeCompiler::JustInTimeCompiler() : 
+	cmdline(),
+	infile_opt(),
+	outfile_opt(),
+	code_head(),
+	code_tail(),
+	comp_func_list(),
+	so_list()
+{
+	so_serial=0;
+	
+	// This is just the default; user should override this. 
+	cmdline.set(
+		"gcc -pipe -nostartfiles -shared -x c++ "
+		"-O2 -fno-rtti -fno-exceptions -ffast-math -funit-at-a-time "
+		"-finline-functions");
+	infile_opt.set(NULL);  // none required
+	outfile_opt.set("-o");
+}
+
+JustInTimeCompiler::~JustInTimeCompiler()
+{
+	Clear();
+}
+
+END_POV_NAMESPACE
diff -urN povray-3.6.1/source/jitcompiler.h povray-3.6.1-ww/source/jitcompiler.h
--- povray-3.6.1/source/jitcompiler.h	1970-01-01 01:00:00.000000000 +0100
+++ povray-3.6.1-ww/source/jitcompiler.h	2004-08-08 17:04:21.000000000 +0200
@@ -0,0 +1,259 @@
+/*
+ * jitcompiler.h - Just-in-time compiler for arbitrary functions. 
+ * 
+ * Copyright (c) 2004 by Wolfgang Wieser
+ * 
+ * This file is put under the POVRay license (povlegal.doc). 
+ * 
+ */
+
+
+#ifndef _JUST_IN_TIME_COMPILER_H_
+#define _JUST_IN_TIME_COMPILER_H_ 1
+
+#include "frame.h"
+
+#include "linkedlist.h"
+#include "refstring.h"
+
+
+BEGIN_POV_NAMESPACE
+
+// JustInTimeCompiler. 
+// -------------------
+// 
+// How it works: 
+// Create a class of type JustInTimeCompiler. This class can be used 
+// to compile funcitons and load them at runtime. It knows about all 
+// the currently loaded shared libraries and active functions and 
+// hence must live as long as you use the associated functions. 
+// 
+// (1) First, set the necessary compiler flags, code head and tail. 
+// (2) Then, add a number of functions you need to get compiled using 
+//     AddFunction(). 
+// (3) Compile these functions into a shared object, load this shared 
+//     object and resolve the symbols. All this is done by Compile(). 
+// (4) Get the compiled function pointers via Lookup(). This returns 
+//     handles for the functions which also allow you to call them. 
+// (5) You may go on with (1) now. 
+//     Alternatively you may also decide that you do not need a certain 
+//     function any longer and call RemoveFunction() on it. If all functions 
+//     in a shared object were deleted, the shared object will be unloaded 
+//     as well. 
+// 
+class JustInTimeCompiler
+{
+	public:
+		enum CompilerError
+		{
+			CE_Success=0,
+			CE_NothingToCompile,          // comp_func_list empty
+			CE_FailedToCreateTemporary,   // mkstemp() failed
+			CE_FailedToOpenTemporary,     // fdopen() failed
+			CE_FailedToCloseTemporary,    // fclose() failed
+			CE_FailedToUnlinkTemporary,   // unlink() failed
+			CE_FailedToExecute,           // failed to execute compiler
+			CE_CompilationFailure,        // compiler exit status !=0
+			CE_CompilerKilled,            // compiler was killed
+			CE_FailedToDLOpen,            // dlopen() failed
+			CE_FailedToUnlinkOutfile,     // unlink() failed on compiler output
+			CE_LookupFailure,             // dlsym() failed
+			// NOTE: 
+			//   CE_NothingToCompile is actually a "success" code. 
+			//   All the other non-success codes mean that no functions 
+			//   or shared objects were loaded. 
+		};
+		
+		// Return string representation of error code. 
+		// This returns a pointer to constant or static data. 
+		static const char *CompilerErrorStr(CompilerError ce);
+		
+		// A function to be compiled: 
+		struct CompFuncNode : LinkedListBase<CompFuncNode>
+		{
+			RefString symb_name;   // symbol name of the function
+			RefString func_code;   // the program source code for the function
+			
+			_CPP_OPERATORS
+			CompFuncNode(const RefString &_symb_name,
+				const RefString &_func_code);
+			~CompFuncNode();
+		};
+		
+		struct SObject;
+		
+		// A function in a shared object: 
+		// List held by associated SObject
+		class SOFunction : LinkedListBase<SOFunction>
+		{
+			friend class JustInTimeCompiler;
+			friend class LinkedList<SOFunction>;
+			private:
+				SObject *sobject;   // back pointer to associated shared object
+				RefString symb_name;  // name of the symbol
+				void *_fptr;   // function pointer as returned by dlsym
+				int refcnt;   // service to the world outside; not touched by JustInTimeCompiler
+				
+				// Do not assign or copy-construct...
+				SOFunction(const SOFunction &);
+				SOFunction &operator=(const SOFunction &);
+				// This is the constructor to be used by our friend, 
+				// the JustInTimeCompiler: 
+				SOFunction(const RefString &_symb_name);
+			public:  _CPP_OPERATORS
+				~SOFunction();
+				
+				// Add/remove references. 
+				inline void aqref()  {  ++refcnt;  }
+				inline bool deref()  {  return(--refcnt<=0);  }
+				
+				// Get the symbol name: 
+				inline const char *SymbNameStr() const
+					{  return(this ? symb_name.str() : NULL);  }
+				
+				// Get the function pointer: 
+				inline void *fptr()  const
+					{  return(this ? _fptr : NULL);  }
+				
+				// This is a template version so that one does not 
+				// need to manually cast the function pointer. 
+				// The argument is just a dummy to avoid having to 
+				// specify the type in <..>. 
+				template<typename FPTR>inline FPTR FPtr(
+					FPTR /*_pattern_dummy*/=NULL) const
+					{  return((FPTR)(fptr()));  }
+		};
+		
+		// A shared object entry node: 
+		struct SObject : LinkedListBase<SObject>
+		{
+			RefString so_file;  // shared object file name
+			void *so_hdl;   // shared object hande (see dlopen())
+			// List of shared functions in this shared object: 
+			LinkedList<SOFunction> func_list;
+			
+			// NOTE: Destructor will dlclose() the object. 
+			_CPP_OPERATORS
+			SObject(const RefString &_so_file);
+			~SObject();
+		};
+		
+	private:
+		// Compiler options: 
+		RefString cmdline;
+		RefString infile_opt;
+		RefString outfile_opt;
+		
+		// Constant code "prefix"/"postfix" to feed into the compiler 
+		// before/after all the user-supplied functions: 
+		RefString code_head;
+		RefString code_tail;
+		
+		// A list of all the functions to be compiled this time: 
+		LinkedList<CompFuncNode> comp_func_list;
+		
+		// A list of all opened shared objects: 
+		LinkedList<SObject> so_list;
+		// Serial number for default shared object names: 
+		int so_serial;
+		
+		// Actually call the compiler and load the produced shared object. 
+		// Return value: See enum above. 
+		// Put compiled binary into outfile which is defaults to 
+		// "./jit-xx.so"  (where xx is constantly increased) if a 
+		// NULL ref is passed. 
+		CompilerError _DoCompile(const RefString &outfile);
+		
+		// Remove object and all functions in it and unload the shared 
+		// object file: 
+		void _RemoveObject(SObject *so);
+		
+		// Remove passed function. 
+		// Return value: 
+		//   0 -> removed
+		//   1 -> removed and deleted SObject (was last function)
+		int _RemoveFunction(SOFunction *func);
+		
+		// Internally used function lookup function: 
+		// Does lookup among the functions _known_ by us and does not 
+		// use dlsym(). 
+		SOFunction *_Lookup(const char *symb_name);
+	public:  _CPP_OPERATORS
+		JustInTimeCompiler();
+		~JustInTimeCompiler();
+		
+		// Cleanup everything: Unload all dynamically loaded objects, 
+		// clear all pending functions, etc. 
+		// Make sure that you do no longer use any of the funcitons 
+		// in these shared objects when calling this. 
+		void Clear();
+		
+		// Set the command line for the compiler call. 
+		// The compiler is called via system(3) using 
+		// "cmdline infile_opt <infile> outfile_opt <outfile>"
+		void SetCmdLine(const RefString &_cmdline)
+			{  cmdline=_cmdline;  }
+		
+		// Set code "head" to be fed into the compiler before 
+		// all the user-supplied functions which we want to compile 
+		// just-in-time. 
+		void SetCodeHead(const RefString &str)
+			{  code_head=str;  }
+		
+		// Set code "tail". Like SetCodeHead() but after all the 
+		// user-supplied functions. 
+		void SetCodeTail(const RefString &str)
+			{  code_tail=str;  }
+		
+		// Add a function to be compiled: 
+		// _symb_name is the symbol name of the function. 
+		// _func_code is the actual source code of the function 
+		//     with all necessary declarations. 
+		void AddFunction(const RefString &_symb_name,
+			const RefString &_func_code);
+		void AddFunction(const char *_symb_name,
+			const RefString &_func_code);
+		
+		// Return number of pending (not-yet-compiled) functions: 
+		int NPendingFunctions() const
+			{  return(comp_func_list.count());  }
+		
+		// Delete all the pending functions: 
+		void DeletePendingFunctions();
+		
+		// Compile all the functions added via AddFunction(). 
+		// Note that you can go on adding functions and compiling them 
+		// just as you like but note that each compilation will 
+		// load another shared object while any number of functions can 
+		// be put into a single shared object. 
+		// Return value: See enum above. 
+		// Note: If the compiler returns success, all the functions in 
+		//       the function list (see AddFunction()) are removed because 
+		//       they were yet compiled. Otherwise, they still stay there. 
+		CompilerError Compile();
+		
+		// After successful compilation, you can look up the functions 
+		// using this template. Be sure to use the correct function 
+		// pointer type. 
+		// This returns a pointer to a class allocated by the 
+		// JustInTimeCompiler or NULL on failure. You need not worry 
+		// about deallocation; just remember that the lifetime is 
+		// limited by the lifetime of the JustInTimeCompiler (or when 
+		// you call RemoveFunction()). 
+		// Only call as often as necessary since this function is slow. 
+		// Functions which were deleted using RemoveFunction() cannot 
+		// be looked up any more (result NULL). 
+		SOFunction *Lookup(const char *symb_name)
+			{  return(_Lookup(symb_name));  }
+		
+		// Remove a function when it is no longer needed. This will make 
+		// the passed SOFunction handle invalid and the function should no 
+		// longer be called. Once all functions associated with a shared 
+		// object are removed, the shared object will be unloaded. 
+		void RemoveFunction(SOFunction *func)
+			{  _RemoveFunction(func);  }
+};
+
+END_POV_NAMESPACE
+
+#endif  /* _JUST_IN_TIME_COMPILER_H_ */
diff -urN povray-3.6.1/source/linkedlist.h povray-3.6.1-ww/source/linkedlist.h
--- povray-3.6.1/source/linkedlist.h	1970-01-01 01:00:00.000000000 +0100
+++ povray-3.6.1-ww/source/linkedlist.h	2004-08-08 17:04:21.000000000 +0200
@@ -0,0 +1,150 @@
+/*
+ * linkedlist.h
+ * Linked list template with little overhead for uses where each list 
+ * element is no no more than one list at any time. 
+ * 
+ * Copyright (c) 2001--2004 by Wolfgang Wieser (wwieser@gmx.de)
+ * 
+ * This is actually a stripped-down version of the linked list from 
+ * HLib-1.0.0 also (c) by Wolfgang Wieser. 
+ * 
+ * This file is put under the POVRay license (povlegal.doc) for use 
+ * within povray. You can find a GPL'ed version in HLib. 
+ * 
+ */
+
+#ifndef _LINKEDLIST_H_
+#define _LINKEDLIST_H_ 1
+
+#include "frame.h"
+
+// This makes sure that operators new and delete use the POV allocation 
+// routines (for correct statistics, etc.): 
+#define _CPP_OPERATORS \
+	void *operator new(size_t s) \
+	{  return(POV_MALLOC(s,"new"));  } \
+	void operator delete(void *ptr) \
+	{  POV_FREE(ptr);  }
+
+BEGIN_POV_NAMESPACE
+
+template<class T> struct LinkedListBase
+{
+	T *prev,*next;
+	
+	enum _LLB_NoInit { LLB_NoInit };
+	
+	// Normal constructor: set prev and next to NULL: 
+	inline LinkedListBase()  {  prev=next=NULL;  }
+	// Special constructor which does NOT set up prev and next: 
+	inline LinkedListBase(_LLB_NoInit)  { }
+	// Destructor no-op...
+	inline ~LinkedListBase()  { }
+};
+
+
+// Ugly macro used so that we can read things more easily.
+#define _LLB LinkedListBase<T>
+
+template<class T> class LinkedList
+{
+	private:
+		T *lfirst,*llast;
+		
+		// Don't use: (use assign_list in rare cases): 
+		inline LinkedList &operator=(const LinkedList &l)
+		{  lfirst=l.lfirst;  llast=l.llast;  return(*this);  }
+		inline LinkedList(const LinkedList &l)
+		{  lfirst=l.lfirst;  llast=l.llast;  }
+	public:  _CPP_OPERATORS
+		inline LinkedList(int * /*failflag*/=NULL)  {  lfirst=llast=NULL;  }
+		// It is your responsibility to properly empty the 
+		// list before destroying it. 
+		inline ~LinkedList()  {  }
+		
+		// Get first and last element of the list (or NULL) 
+		inline T *first()  const  {  return(lfirst);  }
+		inline T *last()   const  {  return(llast);   }
+		
+		inline bool is_empty()  const  {  return(!lfirst);  }
+		
+		// Get next/prev element from passed element. 
+		// May be used if you experience ambiguities using multiple 
+		// inheritance. 
+		inline T *next(T *p)  const  {  return(p->_LLB::next);  }
+		inline T *prev(T *p)  const  {  return(p->_LLB::prev);  }
+		inline const T *next(const T *p)  const  {  return(p->_LLB::next);  }
+		inline const T *prev(const T *p)  const  {  return(p->_LLB::prev);  }
+		
+		// Insert p at the beginning of the list: 
+		inline void insert(T *p)
+		{
+			if(!p)  return;
+			p->_LLB::next=lfirst;
+			p->_LLB::prev=NULL;
+			//if(lfirst)  lfirst->_LLB::prev=p;
+			//else  llast=p;
+			(lfirst ? lfirst->_LLB::prev : llast)=p;
+			lfirst=p;
+		}
+		
+		// Append p to the end of the list: 
+		inline void append(T *p)
+		{
+			if(!p)  return;
+			p->_LLB::prev=llast;
+			p->_LLB::next=NULL;
+			//if(llast)  llast->_LLB::next=p;
+			//else  lfirst=p;
+			(llast ? llast->_LLB::next : lfirst)=p;
+			llast=p;
+		}
+		
+		// Dequeues element p (and returns p). 
+		inline T *dequeue(T *p)
+		{
+			if(!p)  return(p);
+			if(p==lfirst)  lfirst=lfirst->_LLB::next;
+			else  p->_LLB::prev->_LLB::next=p->_LLB::next;
+			if(p==llast)  llast=llast->_LLB::prev;
+			else  p->_LLB::next->_LLB::prev=p->_LLB::prev;
+			p->_LLB::next=p->_LLB::prev=NULL;
+			return(p);
+		}
+		
+		// Dequeue first/last element and return it (or NULL): 
+		inline T *popfirst()
+		{
+			if(!lfirst)  return(lfirst);
+			T *p=lfirst;
+			lfirst=lfirst->_LLB::next;
+			if(lfirst)  lfirst->_LLB::prev=NULL;
+			else  llast=NULL;
+			p->_LLB::next=NULL;
+			return(p);
+		}
+		inline T *poplast()
+		{
+			if(!llast)  return(llast);
+			T *p=llast;
+			llast=llast->_LLB::prev;
+			if(llast)  llast->_LLB::next=NULL;
+			else  lfirst=NULL;
+			p->_LLB::prev=NULL;
+			return(p);
+		}
+		
+		// Cound the elements in the list: 
+		inline int count()  const
+		{
+			int cnt=0;
+			for(T *i=lfirst; i; i=i->_LLB::next,cnt++);
+			return(cnt);
+		}
+};
+
+#undef _LLB
+
+END_POV_NAMESPACE
+
+#endif  /* _LINKEDLIST_H_ */
diff -urN povray-3.6.1/source/refstring.cpp povray-3.6.1-ww/source/refstring.cpp
--- povray-3.6.1/source/refstring.cpp	1970-01-01 01:00:00.000000000 +0100
+++ povray-3.6.1-ww/source/refstring.cpp	2004-08-08 17:04:21.000000000 +0200
@@ -0,0 +1,244 @@
+/*
+ * refstring.cpp
+ * Reference-counting string class. 
+ * 
+ * Copyright (c) 2001--2004 by Wolfgang Wieser (wwieser@gmx.de)
+ * 
+ * This is actually a stripped-down version of the implementation from 
+ * HLib-1.0.0 also (c) by Wolfgang Wieser. 
+ * 
+ * This file is put under the POVRay license (povlegal.doc) for use 
+ * within povray. You can find a GPL'ed version in HLib. 
+ * 
+ */
+
+#include "refstring.h"
+#include <stdarg.h>
+#include <assert.h>
+
+BEGIN_POV_NAMESPACE
+
+// Allocation wrappers: 
+static inline void *LMalloc(size_t x)
+{
+	if(x) return(POV_MALLOC(x,"string"));
+	return(NULL);
+}
+
+static inline void *LFree(void *x)
+{
+	if(x) POV_FREE(x);
+	return(NULL);
+}
+
+static inline void *LRealloc(void *ptr,size_t l)
+{
+	if(!ptr)  return(LMalloc(l));
+	if(!l)  return(LFree(ptr));
+	return(POV_REALLOC(ptr,l,"string"));
+}
+
+
+// Internal layout: 
+//                +---ref-pointer---+
+// [bytes -4...-1][bytes 0...3|bit00][bytes 4...n]
+// [string length][ref counter|sflag][string data]
+// sflag: size flag: 1 -> string has a string length field of type 
+//                        size_t before *ref. 
+//                   0 -> no string length field (0-terminated)
+// ref counter: NOTE: the counter always is decreased/increased 
+//                    by 2 NOT by 1 (as the first bit is the size 
+//                    flag). Using 2 inc/decrement is easier than 
+//                    messing around with bitmasks. 
+
+void RefString::_setup_constr(int *failflag,const char *str_to_copy,
+	const size_t *lenptr)
+{
+	ref=NULL;
+	int failed=_copy(str_to_copy,lenptr);  // returns 0 or -1. 
+	
+	if(failflag)
+	{  *failflag+=failed;  }   // failed<0 -> failflag decreased. 
+	else if(failed)
+	{  abort();  }
+}
+
+
+// Allocate a reference. A size flag is allocated if sflag!=0. 
+// Return value: pointer to the reference counter or NULL. 
+// The ref counter is set up to ONE (i.e. 2 or 3 depending on 
+// sflag), the size flag (if present) to datalen. 
+int *RefString::_alloc(size_t datalen,int sflag)
+{
+	size_t alloclen=datalen+sizeof(*ref);
+	if(sflag)
+	{  alloclen+=sizeof(size_t);  }
+	char *nref=(char*)LMalloc(alloclen);
+	if(nref)
+	{
+		if(sflag)
+		{
+			*((size_t*)nref)=datalen;
+			nref+=sizeof(size_t);
+			*((int*)nref)=3;  // sflag is set
+		}
+		else
+		{  *((int*)nref)=2;  }  // sflag not set
+	}
+	return((int*)nref);
+}
+
+
+// lenptr: NULL -> create string without length info 
+//       !=NULL -> read *lenptr for string length and create string 
+//                 with length info entry (set size flag). 
+int RefString::_copy(const char *str_to_copy,const size_t *lenptr)
+{
+	assert(!ref);
+	
+	if(str_to_copy)
+	{
+		size_t str_len = lenptr ? (*lenptr) : (strlen(str_to_copy)+1);
+		// Allocate data and set up reference counter and size field: 
+		ref=_alloc(str_len,lenptr ? 1 : 0);
+		if(!ref)
+		{  return(-1);  }
+		
+		// Copy string: 
+		memcpy((char*)(ref+1),str_to_copy,str_len);
+	}
+	return(0);
+}
+
+
+bool RefString::operator==(const RefString &b) const
+{
+	// First, the fast path: if it is the same ref, then also 
+	// the same string: 
+	if(b.ref==ref)  return(true);
+	// The case that both refs were NULL was dealed with above. 
+	// See if they are of the same type: 
+	int ot=stype();
+	if(ot!=b.stype())  return(false);
+	// Okay, neither ref is NULL here (same type!). 
+	if(ot)   // data string (with size flag)
+	{
+		// Okay, first check size: 
+		size_t ol=_rlength();
+		if(ol!=b._rlength())  return(false);
+		return(!memcmp(_str(),b._str(),ol));
+	}
+	// '\0'-terminated string; no size flag. 
+	return(!strcmp(_str(),b._str()));
+}
+
+
+bool RefString::operator==(const char *b) const
+{
+	// If not '\0'-terminated, return 0: 
+	if(stype()==1)  return(false);
+	// First, the fast path: if it is the same pointer, 
+	// then also the same string: 
+	const char *a=str();
+	if(a==b)  return(true);
+	// The case that both were NULL was dealed with above. 
+	if(!a || !b)  return(false);
+	return(!strcmp(a,b));
+}
+
+
+void RefString::_destroy()
+{
+	//if(ref)  // <- checked by caller
+	{
+		assert(ref && (*ref==0 || *ref==1));
+		// Now, free the string...
+		// If the size flag is set, we must go back sizeof(size_t) 
+		// bytes, else *ref is the right pointer. 
+		// NOTE: MAY NOT look at size because it may have been zeroed. 
+		LFree(_sflag() ? (int*)(((size_t*)ref)-1) : ref);
+		//ref=NULL;  // <- done by caller. 
+	}
+}
+
+int RefString::vsprintf(size_t maxlen,const char *fmt,va_list ap)
+{
+	// Get rid of old stuff: 
+	_deref();
+	
+	// First, we must get the length of the string in fmt,...
+	const int prealloc=64;
+	char buf[prealloc];
+	int rv=vsnprintf(buf,prealloc,fmt,ap);
+	#if TESTING
+	if(rv<0)
+	{  fprintf(stderr,"refstringw.cc:%d: vsnprintf() not C99 conform."
+		" Please upgrade your libc.\n",__LINE__);  abort();  }
+	#endif
+	
+	size_t dlen=rv;  // (without trailing '\0')
+	// The length of the string in fmt,... is dlen. 
+	// First, allocate the needed bytes: 
+	int trunc=0;
+	if(maxlen && dlen>=maxlen)  // (dlen without NUL, maxlen with NUL char)
+	{  dlen=maxlen-1;  ++trunc;  }
+	ref=_alloc(dlen+1,0);   // +1 for terminating '\0'
+	if(!ref)
+	{  return(-1);  }
+	if(rv<prealloc)  // okay.
+	{
+		// Whole string fits into prealloc buf. Simply copy. 
+		memcpy(_str(),buf,dlen);  // okay. 
+	}
+	else
+	{
+		// Must re-format the string. 
+		int rv2=vsnprintf(_str(),dlen+1,fmt,ap);
+		assert(rv==rv2);
+	}
+	*(_str()+dlen)='\0';  // to be sure...
+	return(trunc);
+}
+
+
+int RefString::sprintf(size_t maxlen,const char *fmt,...)
+{
+	va_list ap;
+	va_start(ap,fmt);
+	int rv=vsprintf(maxlen,fmt,ap);
+	va_end(ap);
+	return(rv);
+}
+
+//------------------------------------------------------------------------------
+
+void StringBuffer::printf(const char *fmt,...)
+{
+	// Well, this implementation is not the quickest but 
+	// this is probably not speed-critical here. 
+	va_list ap;
+	va_start(ap,fmt);
+	RefString tmp;
+	tmp.vsprintf(0,fmt,ap);
+	va_end(ap);
+	
+	size_t l=tmp.len();
+	if(len+l+1>asize)
+	{
+		do
+		{  asize=asize ? asize*2 : 64;  }
+		while(len+l+1>asize);
+		buf=(char*)LRealloc(buf,asize);
+	}
+	
+	strcpy(buf+len,tmp.str());
+	len+=l;
+}
+
+
+StringBuffer::~StringBuffer()
+{
+	buf=(char*)LFree(buf);
+}
+
+END_POV_NAMESPACE
diff -urN povray-3.6.1/source/refstring.h povray-3.6.1-ww/source/refstring.h
--- povray-3.6.1/source/refstring.h	1970-01-01 01:00:00.000000000 +0100
+++ povray-3.6.1-ww/source/refstring.h	2004-08-08 17:04:21.000000000 +0200
@@ -0,0 +1,241 @@
+/*
+ * refstring.h
+ * Reference-counting string class. 
+ * 
+ * Copyright (c) 2001--2004 by Wolfgang Wieser (wwieser@gmx.de)
+ * 
+ * This is actually a stripped-down version of the implementation from 
+ * HLib-1.0.0 also (c) by Wolfgang Wieser. 
+ * 
+ * This file is put under the POVRay license (povlegal.doc) for use 
+ * within povray. You can find a GPL'ed version in HLib. 
+ * 
+ */
+
+#ifndef _REFSTRING_H_
+#define _REFSTRING_H_ 1
+
+#include "linkedlist.h"
+
+BEGIN_POV_NAMESPACE
+
+class RefString
+{
+	private:
+		// Pointer to ref counter. 
+		// NOTE: lowest bit of ref counter is size flag! 
+		//       ref counter is always increased/decreased by 2 NOT by 1. 
+		// String begins at (ref+1). 
+		int *ref;
+		
+		// Returns size flag. 
+		// ONLY CALL IF ref!=NULL. 
+		inline int _sflag() const
+		{  return((*ref) & 1);  }
+		
+		// Returns pointer to string. 
+		// ONLY CALL IF ref!=NULL. 
+		inline char *_str() const
+		{  return(((char*)(ref+1)));  }
+		
+		// Reads length from (size_t*)ref-1. 
+		// ONLY CALL IF ref!=NULL and _sflag()==1. 
+		inline size_t _rlength() const
+		{  return(*(((size_t*)ref)-1));  }
+		
+		// Dereference string: 
+		inline void _deref()
+		{
+			if(!ref)  return;
+			// NOTE: lowest bit is size flag!
+			(*ref)-=2;
+			if(*ref<=1)  _destroy();
+			ref=NULL;
+		}
+		inline void _addref()   // Reference string: 
+		{  if(ref)  (*ref)+=2;  }
+		
+		int *_alloc(size_t datalen,int sflag);
+		int _copy(const char *str,const size_t *lenptr);
+		void _setup_constr(int *failflag,const char *str_to_copy,const size_t *lenptr);
+		void _destroy();
+		
+		// This function makes a private copy of the string. 
+		// If _deref() is called first to get rid of old string. 
+		// Nothing is done if the reference is NULL of the ref 
+		// count is 1 (this instance is the only user of the string). 
+		// Return value: 
+		//   0 -> success 
+		//  -1 -> allocation failed (string then contains NULL reference). 
+		// [Implementer's NOTE: *ref=0,1 -> 0 references (never happens); 
+		//  ref=2,3 -> 1 reference; both cases no need to copy as we're 
+		//  the exclusive user.]
+		// [CURRENTLY UNUSED]
+		int _detach()
+		{  return(!ref ? 0 : (*ref<=3 ? 0 : (_sflag() ? 
+			set(_str(),_rlength()) : set(_str()))));  }
+		// Re-allocation function; longer docu: see implementation. 
+		int _realloc(size_t newlen,int sflag,int wcopy);
+		
+	public:  _CPP_OPERATORS
+		// Set up a NULL reference (use set() and deref() later)
+		// (int *failflag not needed as it never fails; just kept for 
+		// style reasons.)
+		explicit RefString(int * =NULL)  {  ref=NULL;  }
+		// Creation constructor: 
+		// str_to_copy is the string to be copied into the RefString. 
+		// Data for that string is allocated and the reference set up. 
+		// The first variant expects a '\0'-terminated string and creates 
+		//    a RefString able to contain '\0'-terminated strings, thus 
+		//    one without a size field. 
+		// The second variant is the 8-bit-clean data variant. The 
+		//    RefString also allocates a size field and thus the string 
+		//    does not have to be '\0'-terminated and may contain any 
+		//    number of NUL-chars. (len is the size of the data to be 
+		//    copied from passed buffer, NOT the upper limit of the string 
+		//    length.) 
+		// NOTE: You may set str_to_copy to NULL which has the same effect 
+		//       as using the plain RefString() constructor above. 
+		RefString(const char *str_to_copy,int *failflag=NULL)
+			{  _setup_constr(failflag,str_to_copy,NULL);  }
+		RefString(const char *str_to_copy,size_t len,int *failflag=NULL)
+			{  _setup_constr(failflag,str_to_copy,&len);  }
+		// Copy constructor: 
+		RefString(const RefString &src)
+			{  ref=(int*)(src.ref);  _addref();  }
+		// Assignment (operator and method): 
+		// (You cannot assign a const char!) 
+		void set(const RefString &src)
+			{  _deref();  ref=(int*)(src.ref);  _addref();  }
+		RefString &operator=(const RefString &src)
+			{  set(src);  return(*this);  }
+		// Destructor (destroys just this reference): 
+		~RefString()
+			{  _deref();  }
+		
+		// Get the string stored in the RefString: 
+		// It is (of course) NOT copied. 
+		const char *str() const
+			{  return(ref ? _str() : NULL);  }
+		operator const char*() const  {  return(str());  }
+		
+		// Get the length of the stored string. This either returns 
+		// the length as saved in the size field (if the string is one 
+		// with size field) or calls strlen(). 
+		// If strlen() is called, len() returns the length without the 
+		// terminating '\0', and len0() with the terminating NUL char. 
+		// If no string is stored (NULL reference), length 0 is returned. 
+		size_t len() const
+			{  return(ref ? (_sflag() ? _rlength() : strlen(_str())) : 0);  }
+		size_t len0() const
+			{  return(ref ? (_sflag() ? _rlength() : (strlen(_str())+1)) : 0);  }
+		
+		// Returns string type: 
+		//  -1 -> NULL reference 
+		//   0 -> normal '\0'-termiated string (sflag=0)
+		//   1 -> data string (with size field)
+		int stype() const
+			{  return(ref ? _sflag() : -1);  }
+		
+		// Comparing strings: 
+		bool operator==(const RefString &b) const;
+		bool operator!=(const RefString &b) const
+			{  return(!operator==(b));  }
+		
+		// This works only for '\0'-terminated RefStrings: 
+		// operator== is always 0 and != always 1 if the 
+		// RefString is not '\0'-terminated. 
+		bool operator==(const char *b) const;
+		bool operator!=(const char *b) const
+			{  return(!operator==(b));  }
+		
+		// This returns true, if the passed string is actually 
+		// the same string because they share the same reference. 
+		bool IsSameRef(const RefString &b) const
+			{  return(b.ref==ref);  }
+		
+		// This is true if this is a NULL-ref: 
+		bool operator!() const  {  return(!ref);  }
+		// This is true if this is not a NULL-ref: 
+		operator bool() const  {  return(ref);  }
+		
+		// Simply dereference the string. This RefString will then 
+		// just contain a NULL pointer (str() will return NULL). 
+		// deref() has the same effect as set(NULL). 
+		void deref()  {  _deref();  }
+		
+		// How many refs exist to the string? 
+		// Returns 0 for NULL reference. 
+		int nrefs()
+			{  return(ref ? ((*ref)>>2) : 0);  }
+		
+		// This works like operator=() but with strings to be copied. 
+		// First, dereferences the currently used string, then 
+		// it assignes the new string. 
+		// The first variant (without length spec) creates a 
+		// '\0'-terminated string reference, the second one (with length 
+		// specification) expects str_to_copy to conatain >length< bytes 
+		// of data and allocates an 8-bit-clean string of the specified 
+		// size. (See also constructor.) 
+		// Return value: 
+		//   0 -> success
+		//  -1 -> memory allocation failed (string now NULL). 
+		// set(NULL) has the same effect as deref(). 
+		int set(const char *str_to_copy)
+			{  _deref();  return(_copy(str_to_copy,NULL));  }
+		int set(const char *str_to_copy,size_t length)
+			{  _deref();  return(_copy(str_to_copy,&length));  }
+		
+		// Like snprintf() on RefString. The passed format string and 
+		// args are formatted into the string. deref() is called before, 
+		// so printf() will not append to the string but act like set().
+		// maxlen is an upper limit for the final string length (including 
+		// the terminating '\0'-char; set to 0 for 'unlimited'). 
+		// The string is first formatted into a 64 bytes prealloc buffer 
+		// via vsnprintf() to see how long it will get. If less that 64 
+		// bytes, the result is simply copied otherwise it is re-formatted 
+		// using vsnprintf() again. 
+		// Return value: 
+		//  1 -> string was truncated (due to maxlen)
+		//  0 -> success
+		// -1 -> allocation failure (ref now NULL)
+		// The new string is always a '\0'-terminated string without 
+		// size field. 
+		int sprintf(size_t maxlen,const char *fmt,...)
+			__attribute__ ((__format__ (__printf__, 3, 4)));
+		// Version for va_list: 
+		int vsprintf(size_t maxlen,const char *fmt,va_list ap);
+};
+
+
+// Simple string buffer to accumulate a longer text. 
+class StringBuffer
+{
+	private:
+		char *buf;
+		size_t asize;
+		size_t len;
+		
+		// Do not use these: 
+		StringBuffer(const StringBuffer &){}
+		StringBuffer &operator=(const StringBuffer &){return(*this);}
+	public:  _CPP_OPERATORS
+		StringBuffer()
+			{  buf=NULL;  asize=len=0;  }
+		~StringBuffer();
+		
+		// Get string: 
+		const char *str() const
+			{  return(buf);  }
+		
+		// Get the length of the string: 
+		size_t length() const
+			{  return(len);  }
+		
+		// Append to buffer: 
+		void printf(const char *fmt,...);
+};
+
+END_POV_NAMESPACE
+
+#endif  /* _REFSTRING_H_ */
diff -urN povray-3.6.1/unix/Makefile.am povray-3.6.1-ww/unix/Makefile.am
--- povray-3.6.1/unix/Makefile.am	2004-07-18 14:10:10.000000000 +0200
+++ povray-3.6.1-ww/unix/Makefile.am	2004-08-08 17:04:21.000000000 +0200
@@ -56,6 +56,8 @@
   -I$(top_builddir)/source \
   @INCZ@ @INCPNG@ @INCTIFF@ @INCJPEG@
 
+AM_LDFLAGS = -rdynamic
+
 # Libraries to link with.
 # libtiff and libpng must come before libz.
 LDADD = \
