Here's the latest iteration of my patch to pre-allocate and re-use Frame objects. It doesn't yet pass all tests, but it appears to help performance:

without:

Test interpreted: 100k loops calling self's foo 100 times
  2.523000   0.000000   2.523000 (  2.524000)
  1.902000   0.000000   1.902000 (  1.902000)
  2.043000   0.000000   2.043000 (  2.043000)
  1.974000   0.000000   1.974000 (  1.974000)
  2.163000   0.000000   2.163000 (  2.163000)
  2.203000   0.000000   2.203000 (  2.203000)
  2.220000   0.000000   2.220000 (  2.220000)
  2.217000   0.000000   2.217000 (  2.217000)
  2.164000   0.000000   2.164000 (  2.164000)
  2.284000   0.000000   2.284000 (  2.284000)

with:

Test interpreted: 100k loops calling self's foo 100 times
  2.065000   0.000000   2.065000 (  2.064000)
  1.692000   0.000000   1.692000 (  1.692000)
  1.914000   0.000000   1.914000 (  1.914000)
  1.884000   0.000000   1.884000 (  1.885000)
  1.879000   0.000000   1.879000 (  1.879000)
  1.877000   0.000000   1.877000 (  1.877000)
  1.872000   0.000000   1.872000 (  1.873000)
  1.872000   0.000000   1.872000 (  1.872000)
  1.870000   0.000000   1.870000 (  1.870000)
  1.906000   0.000000   1.906000 (  1.906000)

It does pass a large number of tests; I think there's only a bit more work needed to get it passing everything, and it seems like it could be a reasonable win.

- Charlie
Index: src/org/jruby/runtime/ThreadContext.java
===================================================================
--- src/org/jruby/runtime/ThreadContext.java    (revision 3914)
+++ src/org/jruby/runtime/ThreadContext.java    (working copy)
@@ -122,6 +122,10 @@
         // TOPLEVEL self and a few others want a top-level scope.  We create 
this one right
         // away and then pass it into top-level parse so it ends up being the 
top level.
         pushScope(new DynamicScope(new LocalStaticScope(null), null));
+            
+        for (int i = 0; i < frameStack.length; i++) {
+            frameStack[i] = new Frame();
+        }
     }
     
     CallType lastCallType;
@@ -193,6 +197,10 @@
             
             System.arraycopy(frameStack, 0, newFrameStack, 0, 
frameStack.length);
             
+            for (int i = frameStack.length; i < newSize; i++) {
+                newFrameStack[i] = new Frame();
+            }
+            
             frameStack = newFrameStack;
         }
     }
@@ -288,26 +296,48 @@
     
     //////////////////// FRAME MANAGEMENT ////////////////////////
     private void pushFrameCopy() {
-        pushFrame(getCurrentFrame().duplicate());
+        Frame currentFrame = getCurrentFrame();
+        Frame frame = frameStack[++frameIndex];
+        if (frame.isShared()) {
+            frame = frameStack[frameIndex] = new Frame();
+        }
+        frame.updateFrame(currentFrame);
+        expandFramesIfNecessary();
     }
     
+    private void pushFrame(Frame frame) {
+        frameStack[++frameIndex] = frame;
+        expandFramesIfNecessary();
+    }
+    
     private void pushCallFrame(RubyModule clazz, String name, 
                                IRubyObject self, IRubyObject[] args, int req, 
Block block, Object jumpTarget) {
-        pushFrame(new Frame(clazz, self, name, args, req, block, 
getPosition(), jumpTarget));        
+        pushFrame(clazz, name, self, args, req, block, jumpTarget);        
     }
-
-    private void pushFrame() {
-        pushFrame(new Frame(getPosition()));
+    
+    private void pushFrame(RubyModule clazz, String name, 
+                               IRubyObject self, IRubyObject[] args, int req, 
Block block, Object jumpTarget) {
+        Frame frame = frameStack[++frameIndex];
+        if (frame.isShared()) {
+            frame = frameStack[frameIndex] = new Frame();
+        }
+        frame.updateFrame(clazz, self, name, args, req, block, getPosition(), 
jumpTarget);
+        expandFramesIfNecessary();
     }
     
-    private void pushFrame(Frame frame) {
-        frameStack[++frameIndex] = frame;
+    private void pushFrame() {
+        Frame frame = frameStack[++frameIndex];
+        if (frame.isShared()) {
+            frame = frameStack[frameIndex] = new Frame();
+        }
+        frame.updateFrame(getPosition());
         expandFramesIfNecessary();
     }
     
     private void popFrame() {
         Frame frame = (Frame)frameStack[frameIndex];
-        frameStack[frameIndex--] = null;
+        //frameStack[frameIndex--] = null;
+        frameIndex--;
         
         setPosition(frame.getPosition());
     }
Index: src/org/jruby/runtime/Block.java
===================================================================
--- src/org/jruby/runtime/Block.java    (revision 3914)
+++ src/org/jruby/runtime/Block.java    (working copy)
@@ -126,6 +126,9 @@
         this.iterNode = iterNode;
         this.self = self;
         this.frame = frame;
+        if (this.frame != null) {
+            this.frame.setShared(true);
+        }
         this.visibility = visibility;
         this.klass = klass;
         this.cref = cref;
Index: src/org/jruby/runtime/Frame.java
===================================================================
--- src/org/jruby/runtime/Frame.java    (revision 3914)
+++ src/org/jruby/runtime/Frame.java    (working copy)
@@ -80,7 +80,7 @@
      * and also for block_given?.  Both of those methods needs access to the 
block of the 
      * previous frame to work.
      */ 
-    private final Block block;
+    private Block block;
     
     /**
      * Does this delimit a frame where an eval with binding occurred.  Used 
for stack traces.
@@ -93,6 +93,16 @@
     private Visibility visibility = Visibility.PUBLIC;
     
     private Object jumpTarget;
+    
+    private boolean shared = false;
+    
+    public boolean isShared() {
+        return shared;
+    }
+    
+    public void setShared(boolean shared) {
+        this.shared = shared;
+    }
 
     public Object getJumpTarget() {
         return jumpTarget;
@@ -101,17 +111,35 @@
     public void setJumpTarget(Object jumpTarget) {
         this.jumpTarget = jumpTarget;
     }
-
     /**
      * The location in source where this block/method invocation is happening
      */
-    private final ISourcePosition position;
+    private ISourcePosition position;
 
-    public Frame(ISourcePosition position) {
-        this(null, null, null, IRubyObject.NULL_ARRAY, 0, Block.NULL_BLOCK, 
position, null); 
+    public void updateFrame(ISourcePosition position) {
+        updateFrame(null, null, null, IRubyObject.NULL_ARRAY, 0, 
Block.NULL_BLOCK, position, null); 
     }
 
-    public Frame(RubyModule klazz, IRubyObject self, String name,
+    public void updateFrame(Frame frame) {
+        assert frame.block != null : "Block uses null object pattern.  It 
should NEVER be null";
+        
+        if (frame.args.length != 0) {
+            args = new IRubyObject[frame.args.length];
+            System.arraycopy(frame.args, 0, args, 0, frame.args.length);
+        } else {
+               args = frame.args;
+        }
+
+        this.self = frame.self;
+        this.requiredArgCount = frame.requiredArgCount;
+        this.name = frame.name;
+        this.klazz = frame.klazz;
+        this.position = frame.position;
+        this.block = frame.block;
+        this.jumpTarget = frame.jumpTarget;
+    }
+
+    public void updateFrame(RubyModule klazz, IRubyObject self, String name,
                  IRubyObject[] args, int requiredArgCount, Block block, 
ISourcePosition position, Object jumpTarget) {
         assert block != null : "Block uses null object pattern.  It should 
NEVER be null";
 
@@ -124,6 +152,14 @@
         this.block = block;
         this.jumpTarget = jumpTarget;
     }
+    
+    public Frame duplicate() {
+        Frame newFrame = new Frame();
+        
+        newFrame.updateFrame(this);
+        
+        return newFrame;
+    }
 
     /** Getter for property args.
      * @return Value of property args.
@@ -250,18 +286,6 @@
         return block;
     }
 
-    public Frame duplicate() {
-        IRubyObject[] newArgs;
-        if (args.length != 0) {
-            newArgs = new IRubyObject[args.length];
-            System.arraycopy(args, 0, newArgs, 0, args.length);
-        } else {
-               newArgs = args;
-        }
-
-        return new Frame(klazz, self, name, newArgs, requiredArgCount, block, 
position, jumpTarget);
-    }
-
     /* (non-Javadoc)
      * @see java.lang.Object#toString()
      */

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

    http://xircles.codehaus.org/manage_email

Reply via email to