org.jruby.runtime.Frame Maven / Gradle / Ivy
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2001-2004 Jan Arne Petersen
* Copyright (C) 2002 Benoit Cerrina
* Copyright (C) 2002-2004 Anders Bengtsson
* Copyright (C) 2004-2007 Thomas E Enebo
* Copyright (C) 2006 Charles O Nutter
* Copyright (C) 2006 Miguel Covarrubias
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/
package org.jruby.runtime;
import org.jruby.RubyModule;
import org.jruby.runtime.builtin.IRubyObject;
/**
* A Frame holds per-call information that needs to persist outside the
* execution of a given method. Currently a frame holds the following:
*
* - The class against which this method is being invoked. This is usually
* (always?) the class of "self" within this call.
* - The current "self" for the call.
* - The name of the method being invoked during this frame, used for
* backtraces and "super" invocations.
* - The block passed to this invocation. If the given code body can't
* accept a block, it will be Block.NULL_BLOCK.
* - Whether this is the frame used for a binding-related call like eval. This
* is used to determine where to terminate evaled code's backtrace.
* - The current visibility for methods defined during this call. Starts out
* as PUBLIC by default (in most cases) and can be modified by appropriate
* Kernel.public/private/protected calls.
* - The jump target marker for non-local returns.
*
* Frames are allocated for all Ruby methods (in compatibility mode, default)
* and for some core methods. In general, a frame is required for a method to
* show up in a backtrace, and so some methods only use frame for backtrace
* information (so-called "backtrace frames").
*
* @see ThreadContext
*/
public final class Frame {
/** The class against which this call is executing. */
private RubyModule klazz;
/** The 'self' for this frame. */
private IRubyObject self;
/** The name of the method being invoked in this frame. */
private String name;
/**
* The block that was passed in for this frame (as either a block or a &block argument).
* The frame captures the block for super/zsuper, but also for Proc.new (with no arguments)
* and also for block_given?. Both of those methods needs access to the block of the
* previous frame to work.
*/
private Block block = Block.NULL_BLOCK;
/** The current visibility for anything defined under this frame */
private Visibility visibility = Visibility.PUBLIC;
/** The target for non-local jumps, like return from a block */
private int jumpTarget;
/** backref **/
private IRubyObject backRef;
/** lastline **/
private IRubyObject lastLine;
/** whether this frame has been captured into a binding **/
private boolean captured;
/**
* Empty constructor, since Frame objects are pre-allocated and updated
* when needed.
*/
public Frame() {
}
/**
* Copy constructor, since Frame objects are pre-allocated and updated
* when needed.
*/
private Frame(Frame frame) {
assert frame.block != null : "Block uses null object pattern. It should NEVER be null";
this.self = frame.self;
this.name = frame.name;
this.klazz = frame.klazz;
this.block = frame.block;
this.visibility = frame.visibility;
this.jumpTarget = frame.jumpTarget;
}
/**
* Update the frame with just filename and line, used for top-level frames
* and method.
*
* @param fileName The file where the calling method is located
* @param line The line number in the calling method where the call is made
*/
public void updateFrame() {
updateFrame(null, null, null, Block.NULL_BLOCK, 0);
}
/**
* Update the frame with caller information and method name, so it will
* show up correctly in call stacks.
*
* @param name The name of the method being called
* @param fileName The file of the calling method
* @param line The line number of the call to this method
*/
public void updateFrame(String name) {
this.name = name;
}
/**
* Update the frame based on information from another frame. Used for
* cloning frames (for blocks, usually) and when entering class bodies.
*
* @param frame The frame whose data to duplicate in this frame
*/
public void updateFrame(Frame frame) {
assert frame.block != null : "Block uses null object pattern. It should NEVER be null";
this.self = frame.self;
this.name = frame.name;
this.klazz = frame.klazz;
this.block = frame.block;
this.visibility = frame.visibility;
this.jumpTarget = frame.jumpTarget;
}
/**
* Update the frame based on the given values.
*
* @param klazz The class against which the method is being called
* @param self The 'self' for the method
* @param name The name under which the method is being invoked
* @param block The block passed to the method
* @param fileName The filename of the calling method
* @param line The line number where the call is being made
* @param jumpTarget The target for non-local jumps (return in block)
*/
public void updateFrame(RubyModule klazz, IRubyObject self, String name,
Block block, int jumpTarget) {
assert block != null : "Block uses null object pattern. It should NEVER be null";
this.self = self;
this.name = name;
this.klazz = klazz;
this.block = block;
this.visibility = Visibility.PUBLIC;
this.jumpTarget = jumpTarget;
}
/**
* Update the frame based on the given values.
*
* @param klazz The class against which the method is being called
* @param self The 'self' for the method
* @param name The name under which the method is being invoked
* @param block The block passed to the method
* @param fileName The filename of the calling method
* @param line The line number where the call is being made
* @param jumpTarget The target for non-local jumps (return in block)
*/
public void updateFrameForEval(IRubyObject self, int jumpTarget) {
this.self = self;
this.name = null;
this.visibility = Visibility.PRIVATE;
this.jumpTarget = jumpTarget;
}
/**
* Clear the frame, as when the call completes. Clearing prevents cached
* frames from holding references after the call is done.
*/
public Frame clear() {
this.self = null;
this.klazz = null;
this.block = Block.NULL_BLOCK;
this.backRef = null;
this.lastLine = null;
return this;
}
/**
* Clone this frame.
*
* @return A new frame with duplicate information to the target frame
*/
public Frame duplicate() {
return new Frame(this);
}
/**
* Clone this frame for use in backtraces only (avoiding long-lived
* references to other elements.
*
* @return A new frame with identical backtrace information to this frame
*/
public Frame duplicateForBacktrace() {
Frame backtraceFrame = new Frame();
backtraceFrame.name = name;
return backtraceFrame;
}
/**
* Get the jump target for non-local returns in this frame.
*
* @return The jump target for non-local returns
*/
public int getJumpTarget() {
return jumpTarget;
}
/**
* Return class that we are calling against
*
* @return The class we are calling against
*/
public RubyModule getKlazz() {
return klazz;
}
/**
* Set the class we are calling against.
*
* @param klazz the new class
*/
public void setKlazz(RubyModule klazz) {
this.klazz = klazz;
}
/**
* Set the method name associated with this frame
*
* @param name the new name
*/
public void setName(String name) {
this.name = name;
}
/**
* Get the method name associated with this frame
*
* @return the method name
*/
public String getName() {
return name;
}
/**
* Get the self associated with this frame
*
* @return The self for the frame
*/
public IRubyObject getSelf() {
return self;
}
/**
* Set the self associated with this frame
*
* @param self The new value of self
*/
public void setSelf(IRubyObject self) {
this.self = self;
}
/**
* Get the visibility at the time of this frame
*
* @return The visibility
*/
public Visibility getVisibility() {
return visibility;
}
/**
* Change the visibility associated with this frame
*
* @param visibility The new visibility
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
/**
* Retrieve the block associated with this frame.
*
* @return The block of this frame or NULL_BLOCK if no block given
*/
public Block getBlock() {
return block;
}
public IRubyObject getBackRef(IRubyObject nil) {
IRubyObject backRef = this.backRef;
return backRef == null ? nil : backRef;
}
public IRubyObject setBackRef(IRubyObject backRef) {
return this.backRef = backRef;
}
public IRubyObject getLastLine(IRubyObject nil) {
IRubyObject lastLine = this.lastLine;
return lastLine == null ? nil : lastLine;
}
public IRubyObject setLastLine(IRubyObject lastLine) {
return this.lastLine = lastLine;
}
public void setCaptured(boolean captured) {
this.captured = captured;
}
public Frame capture() {
captured = true;
return this;
}
public boolean isCaptured() {
return captured;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append(klazz);
if (name != null) sb.append(" in ").append(name);
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy