Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions core/src/main/java/org/jruby/embed/AttributeName.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,29 @@ public enum AttributeName {
*/
SHARING_VARIABLES("org.jruby.embed.sharing.variables"),

/**
* A key used in an attribute map to turn on/off sharing of instance variables.
* Default is false, which means instance variables are not accessible via the
* embedding interface. If set to true, and {@link #SHARING_VARIABLES} is also
* true, instance variables of an object become accessible via the BiVariableMap
* interface when
* <ul>
* <li>a method on that object has been called from Java
* <li>that object is returned from a method call
* <li>that object is returned by the evaluation of a script
* </ul>
* <p>
* Note that enabling this option will prevent those objects from being garbage
* collected. Therefore, if this feature is enabled, the user becomes
* responsible for removing unused objects' instance variables from the
* BiVariableMap once they are no longer needed. Otherwise, <i>memory
* leaks will be expected</i>.
* <p>
* This attribute can be set using a System property,
* org.jruby.embed.sharing.instance.variables.
*/
SHARING_INSTANCE_VARIABLES("org.jruby.embed.sharing.instance.variables"),

/**
* A key used in an attribute map to turn on/off clearing variables.
* This attribute is for JSR223 only.
Expand Down
14 changes: 13 additions & 1 deletion core/src/main/java/org/jruby/embed/internal/BiVariableMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@

import org.jruby.Ruby;
import org.jruby.RubyObject;
import org.jruby.embed.AttributeName;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.variable.BiVariable;
import org.jruby.embed.variable.InstanceVariable;
import org.jruby.embed.variable.VariableInterceptor;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.builtin.IRubyObject;
Expand Down Expand Up @@ -335,7 +337,9 @@ public Object put(Object receiver, String key, Object value) {
}
else { // creates new value
var = VariableInterceptor.getVariableInstance(provider.getLocalVariableBehavior(), robj, key, value);
if ( var != null ) update(key, var);
// for consistency, do not inject instance variables when they wouldn't be retrieverd from Ruby
if (var != null && (isSharingInstanceVariables() || !(var instanceof InstanceVariable)))
update(key, var);
}
return oldValue;
}
Expand Down Expand Up @@ -573,6 +577,14 @@ public boolean isLazy() {
return lazy;
}

public boolean isSharingInstanceVariables() {
final Object sharing = provider.getAttributeMap().get(AttributeName.SHARING_INSTANCE_VARIABLES);
if ( sharing instanceof Boolean && ((Boolean) sharing).booleanValue() == true ) {
return true;
}
return false;
}

@Override
public String toString() {
final StringBuilder str = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ public static void retrieve(LocalVariableBehavior behavior, BiVariableMap map, R
PersistentLocalVariable.retrieve(receiver, map);
// continues to the default case
default:
InstanceVariable.retrieve(receiver, map);
if (map.isSharingInstanceVariables())
InstanceVariable.retrieve(receiver, map);
GlobalVariable.retrieve(receiver, map);
ClassVariable.retrieve(receiver, map);
Constant.retrieve(receiver, map);
Expand Down Expand Up @@ -200,7 +201,7 @@ public static void tryLazyRetrieval(LocalVariableBehavior behavior, BiVariableMa
default:
if (GlobalVariable.isValidName(key)) {
GlobalVariable.retrieveByKey(receiver.getRuntime(), map, (String)key);
} else if (InstanceVariable.isValidName(key)) {
} else if (InstanceVariable.isValidName(key) && map.isSharingInstanceVariables()) {
InstanceVariable.retrieveByKey((RubyObject) receiver,map, (String)key);
} else if (ClassVariable.isValidName(key)) {
ClassVariable.retrieveByKey((RubyObject)receiver, map, (String)key);
Expand Down
Loading