I noticed this evening we don't cache literal floats in either the interpreter or the compiler, but I could not remember why. I've attached a patch that fixes this, but does anyone remember if there's a reason why we couldn't cache floats? Are they mutable or something?

- Charlie
>From c4a8d4b5c6625762f003d0debe54a659bb9a333e Mon Sep 17 00:00:00 2001
From: Charles Nutter <[email protected]>
Date: Sat, 21 Feb 2009 02:40:22 -0600
Subject: [PATCH] Add Float caching to compiler and interpreter. Passes all 
tests, improves performance, but I feel like I didn't do it before on purpose...

---
 src/org/jruby/ast/FloatNode.java                   |    8 +++++-
 src/org/jruby/ast/executable/AbstractScript.java   |   25 ++++++++++++++++++++
 src/org/jruby/compiler/CacheCompiler.java          |    2 +
 src/org/jruby/compiler/impl/BaseBodyCompiler.java  |    5 +---
 .../compiler/impl/InheritedCacheCompiler.java      |   25 ++++++++++++++++++++
 5 files changed, 60 insertions(+), 5 deletions(-)

diff --git a/src/org/jruby/ast/FloatNode.java b/src/org/jruby/ast/FloatNode.java
index ee8b914..7b8fc20 100644
--- a/src/org/jruby/ast/FloatNode.java
+++ b/src/org/jruby/ast/FloatNode.java
@@ -47,6 +47,7 @@ import org.jruby.runtime.builtin.IRubyObject;
  */
 public class FloatNode extends Node implements ILiteralNode {
     private double value;
+    private RubyFloat rubyFloat;
     
     public FloatNode(ISourcePosition position, double value) {
         super(position);
@@ -68,6 +69,11 @@ public class FloatNode extends Node implements ILiteralNode {
     public double getValue() {
         return value;
     }
+
+    public RubyFloat getRubyFloat(Ruby runtime) {
+        if (rubyFloat == null) rubyFloat = RubyFloat.newFloat(runtime, value);
+        return rubyFloat;
+    }
     
     /**
      * Sets the value
@@ -83,6 +89,6 @@ public class FloatNode extends Node implements ILiteralNode {
     
     @Override
     public IRubyObject interpret(Ruby runtime, ThreadContext context, 
IRubyObject self, Block aBlock) {
-        return RubyFloat.newFloat(runtime, value);
+        return getRubyFloat(runtime);
     }
 }
diff --git a/src/org/jruby/ast/executable/AbstractScript.java 
b/src/org/jruby/ast/executable/AbstractScript.java
index f73a21e..d0098db 100644
--- a/src/org/jruby/ast/executable/AbstractScript.java
+++ b/src/org/jruby/ast/executable/AbstractScript.java
@@ -9,6 +9,7 @@ import java.math.BigInteger;
 import java.util.Arrays;
 import org.jruby.Ruby;
 import org.jruby.RubyFixnum;
+import org.jruby.RubyFloat;
 import org.jruby.RubyModule;
 import org.jruby.RubyRegexp;
 import org.jruby.RubyString;
@@ -250,6 +251,25 @@ public abstract class AbstractScript implements Script {
         return fixnum;
     }
 
+    public static final double NUMBERED_FLOAT_COUNT = 10;
+
+    public final RubyFloat getFloat0(Ruby runtime, double value) {return 
getFloat(runtime, 0, value);}
+    public final RubyFloat getFloat1(Ruby runtime, double value) {return 
getFloat(runtime, 1, value);}
+    public final RubyFloat getFloat2(Ruby runtime, double value) {return 
getFloat(runtime, 2, value);}
+    public final RubyFloat getFloat3(Ruby runtime, double value) {return 
getFloat(runtime, 3, value);}
+    public final RubyFloat getFloat4(Ruby runtime, double value) {return 
getFloat(runtime, 4, value);}
+    public final RubyFloat getFloat5(Ruby runtime, double value) {return 
getFloat(runtime, 5, value);}
+    public final RubyFloat getFloat6(Ruby runtime, double value) {return 
getFloat(runtime, 6, value);}
+    public final RubyFloat getFloat7(Ruby runtime, double value) {return 
getFloat(runtime, 7, value);}
+    public final RubyFloat getFloat8(Ruby runtime, double value) {return 
getFloat(runtime, 8, value);}
+    public final RubyFloat getFloat9(Ruby runtime, double value) {return 
getFloat(runtime, 9, value);}
+
+    public final RubyFloat getFloat(Ruby runtime, int index, double value) {
+        RubyFloat flote = flotes[index];
+        if (flote == null) return flotes[index] = RubyFloat.newFloat(runtime, 
value);
+        return flote;
+    }
+
     public final RubyRegexp getRegexp(Ruby runtime, int index, String pattern, 
int options) {
         RubyRegexp regexp = regexps[index];
         if (regexp == null) {
@@ -332,6 +352,10 @@ public abstract class AbstractScript implements Script {
         fixnums = new RubyFixnum[size];
     }
 
+    public final void initFloats(int size) {
+        flotes = new RubyFloat[size];
+    }
+
     public final void initRegexps(int size) {
         regexps = new RubyRegexp[size];
     }
@@ -522,6 +546,7 @@ public abstract class AbstractScript implements Script {
     public RubySymbol[] symbols;
     public ByteList[] byteLists;
     public RubyFixnum[] fixnums;
+    public RubyFloat[] flotes;
     public RubyRegexp[] regexps;
     public BigInteger[] bigIntegers;
     public String filename;
diff --git a/src/org/jruby/compiler/CacheCompiler.java 
b/src/org/jruby/compiler/CacheCompiler.java
index d10e1a8..4cbc01c 100644
--- a/src/org/jruby/compiler/CacheCompiler.java
+++ b/src/org/jruby/compiler/CacheCompiler.java
@@ -24,6 +24,8 @@ public interface CacheCompiler {
     public void cacheSymbol(BaseBodyCompiler method, String symbol);
     
     public void cacheFixnum(BaseBodyCompiler method, long value);
+
+    public void cacheFloat(BaseBodyCompiler method, double value);
     
     public void cacheBigInteger(BaseBodyCompiler method, BigInteger bigint);
 
diff --git a/src/org/jruby/compiler/impl/BaseBodyCompiler.java 
b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
index befb8f6..6b37bc1 100644
--- a/src/org/jruby/compiler/impl/BaseBodyCompiler.java
+++ b/src/org/jruby/compiler/impl/BaseBodyCompiler.java
@@ -443,10 +443,7 @@ public abstract class BaseBodyCompiler implements 
BodyCompiler {
     }
 
     public void createNewFloat(double value) {
-        loadRuntime();
-        method.ldc(new Double(value));
-
-        invokeRuby("newFloat", sig(RubyFloat.class, params(Double.TYPE)));
+        script.getCacheCompiler().cacheFloat(this, value);
     }
 
     public void createNewFixnum(long value) {
diff --git a/src/org/jruby/compiler/impl/InheritedCacheCompiler.java 
b/src/org/jruby/compiler/impl/InheritedCacheCompiler.java
index 043612a..7eb3faf 100644
--- a/src/org/jruby/compiler/impl/InheritedCacheCompiler.java
+++ b/src/org/jruby/compiler/impl/InheritedCacheCompiler.java
@@ -12,6 +12,7 @@ import java.util.List;
 import java.util.Map;
 import org.jruby.Ruby;
 import org.jruby.RubyFixnum;
+import org.jruby.RubyFloat;
 import org.jruby.RubyModule;
 import org.jruby.RubyRegexp;
 import org.jruby.RubyString;
@@ -47,11 +48,13 @@ public class InheritedCacheCompiler implements 
CacheCompiler {
     Map<BigInteger, String> bigIntegers = new HashMap<BigInteger, String>();
     Map<String, Integer> symbolIndices = new HashMap<String, Integer>();
     Map<Long, Integer> fixnumIndices = new HashMap<Long, Integer>();
+    Map<Double, Integer> floatIndices = new HashMap<Double, Integer>();
     int inheritedSymbolCount = 0;
     int inheritedStringCount = 0;
     int inheritedRegexpCount = 0;
     int inheritedBigIntegerCount = 0;
     int inheritedFixnumCount = 0;
+    int inheritedFloatCount = 0;
     int inheritedConstantCount = 0;
     int inheritedBlockBodyCount = 0;
     int inheritedBlockCallbackCount = 0;
@@ -213,6 +216,20 @@ public class InheritedCacheCompiler implements 
CacheCompiler {
         }
     }
 
+    public void cacheFloat(BaseBodyCompiler method, double value) {
+        Integer index = floatIndices.get(value);
+        if (index == null) {
+            index = new Integer(inheritedFloatCount++);
+            floatIndices.put(value, index);
+        }
+
+        method.loadThis();
+        method.loadRuntime();
+        method.method.pushInt(index.intValue());
+        method.method.ldc(value);
+        method.method.invokevirtual(scriptCompiler.getClassname(), "getFloat", 
sig(RubyFloat.class, Ruby.class, int.class, double.class));
+    }
+
     public void cacheConstant(BaseBodyCompiler method, String constantName) {
         method.loadThis();
         method.loadThreadContext();
@@ -405,6 +422,14 @@ public class InheritedCacheCompiler implements 
CacheCompiler {
             initMethod.invokevirtual(scriptCompiler.getClassname(), 
"initFixnums", sig(void.class, params(int.class)));
         }
 
+        // generate fixnums initialization code
+        size = inheritedFloatCount;
+        if (size != 0) {
+            initMethod.aload(0);
+            initMethod.pushInt(size);
+            initMethod.invokevirtual(scriptCompiler.getClassname(), 
"initFloats", sig(void.class, params(int.class)));
+        }
+
         // generate constants initialization code
         size = inheritedConstantCount;
         if (size != 0) {
-- 
1.6.0.2


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email

Reply via email to