Skip to content

Commit

Permalink
Merge pull request #6457 [embed] refactor (JSR223) exception wrapping
Browse files Browse the repository at this point in the history
  • Loading branch information
kares committed Mar 1, 2021
2 parents 52c21a2 + be4658a commit 552e8a1
Show file tree
Hide file tree
Showing 24 changed files with 705 additions and 1,062 deletions.
8 changes: 7 additions & 1 deletion core/src/main/java/org/jruby/embed/EmbedEvalUnit.java
Expand Up @@ -31,6 +31,7 @@

import org.jruby.ast.Node;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.scope.ManyVarsDynamicScope;

/**
Expand All @@ -54,5 +55,10 @@ public interface EmbedEvalUnit extends JavaEmbedUtils.EvalUnit {
*
* @return scope to refer local variables.
*/
public ManyVarsDynamicScope getScope();
DynamicScope getLocalVarScope();

@Deprecated
default ManyVarsDynamicScope getScope() {
return (ManyVarsDynamicScope) getLocalVarScope();
}
}
27 changes: 14 additions & 13 deletions core/src/main/java/org/jruby/embed/ScriptingContainer.java
Expand Up @@ -184,9 +184,9 @@ public class ScriptingContainer implements EmbedRubyInstanceConfigAdapter {
private final Map<String, String[]> basicProperties;
private final LocalContextScope scope;
private final LocalContextProvider provider;
private final EmbedRubyRuntimeAdapter runtimeAdapter = new EmbedRubyRuntimeAdapterImpl(this);
private final EmbedRubyObjectAdapter objectAdapter = new EmbedRubyObjectAdapterImpl(this);
private final EmbedRubyInterfaceAdapter interfaceAdapter = new EmbedRubyInterfaceAdapterImpl(this);
private final EmbedRubyRuntimeAdapter runtimeAdapter;
private final EmbedRubyObjectAdapter objectAdapter;
private final EmbedRubyInterfaceAdapter interfaceAdapter;

/**
* Constructs a ScriptingContainer with a default values.
Expand Down Expand Up @@ -225,8 +225,7 @@ public ScriptingContainer(LocalContextScope scope, LocalVariableBehavior behavio
}

/**
* Constructs a ScriptingContainer with a specified local context scope,
* local variable behavior and laziness.
* Constructs a ScriptingContainer with a specified local context scope, local variable behavior and laziness.
*
* @param scope is one of a local context scope defined by {@link LocalContextScope}
* @param behavior is one of a local variable behavior defined by {@link LocalVariableBehavior}
Expand All @@ -235,16 +234,18 @@ public ScriptingContainer(LocalContextScope scope, LocalVariableBehavior behavio
* get as many variables/constants as possible from Ruby runtime.
*/
public ScriptingContainer(LocalContextScope scope, LocalVariableBehavior behavior, boolean lazy) {
this(scope, behavior, lazy, true); // wrapping exceptions due backwards compatibility
}

public ScriptingContainer(LocalContextScope scope, LocalVariableBehavior behavior, boolean lazy, boolean wrapExceptions) {
this.provider = getProviderInstance(scope, behavior, lazy);
this.scope = scope;
try {
initRubyInstanceConfig();
}
catch (RaiseException ex) {
// TODO this seems useless - except that we get a Java stack trace
throw new RuntimeException(ex);
}
initRubyInstanceConfig();
basicProperties = getBasicProperties();

runtimeAdapter = new EmbedRubyRuntimeAdapterImpl(this, wrapExceptions);
objectAdapter = new EmbedRubyObjectAdapterImpl(this, wrapExceptions);
interfaceAdapter = new EmbedRubyInterfaceAdapterImpl(this);
}

static LocalContextProvider getProviderInstance(LocalContextScope scope, LocalVariableBehavior behavior, boolean lazy) {
Expand Down Expand Up @@ -1575,7 +1576,7 @@ public <T> T callSuper(Object receiver, Object[] args, Block block, Class<T> ret
* @return an instance of requested Java type
*/
public <T> T runRubyMethod(Class<T> returnType, Object receiver, String methodName, Object... args) {
return objectAdapter.runRubyMethod(returnType, receiver, methodName, null, args);
return objectAdapter.runRubyMethod(returnType, receiver, methodName, Block.NULL_BLOCK, args);
}

/**
Expand Down
24 changes: 10 additions & 14 deletions core/src/main/java/org/jruby/embed/internal/BiVariableMap.java
Expand Up @@ -44,6 +44,7 @@
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.variable.BiVariable;
import org.jruby.embed.variable.VariableInterceptor;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.scope.ManyVarsDynamicScope;
import static org.jruby.util.StringSupport.EMPTY_STRING_ARRAY;
Expand Down Expand Up @@ -230,11 +231,7 @@ public Object get(Object receiver, Object key) {
}

private RubyObject getReceiverObject(final Object receiver) {
if ( receiver instanceof RubyObject ) return (RubyObject) receiver;
//if ( receiver instanceof IRubyObject ) {
// return (RubyObject) ( (IRubyObject) receiver ).getRuntime().getTopSelf();
//}
return getTopSelf();
return receiver instanceof RubyObject ? (RubyObject) receiver : getTopSelf();
}

private RubyObject getTopSelf() {
Expand Down Expand Up @@ -330,16 +327,15 @@ public Object put(String key, Object value) {
public Object put(Object receiver, String key, Object value) {
checkKey(key);
final RubyObject robj = getReceiverObject(receiver);
final String name = key.intern();
BiVariable var = getVariable(robj, name);
BiVariable var = getVariable(robj, key);
Object oldValue = null;
if ( var != null ) { // updates
oldValue = var.getJavaObject();
var.setJavaObject(robj.getRuntime(), value);
}
else { // creates new value
var = VariableInterceptor.getVariableInstance(provider.getLocalVariableBehavior(), robj, name, value);
if ( var != null ) update(name, var);
var = VariableInterceptor.getVariableInstance(provider.getLocalVariableBehavior(), robj, key, value);
if ( var != null ) update(key, var);
}
return oldValue;
}
Expand All @@ -353,7 +349,7 @@ public Object put(Object receiver, String key, Object value) {
public String[] getLocalVarNames() {
if ( variables == null ) return EMPTY_STRING_ARRAY;

List<String> localVarNames = new ArrayList<String>();
List<String> localVarNames = new ArrayList<>(variables.size());
for ( final BiVariable var : variables ) {
if ( var.getType() == BiVariable.Type.LocalVariable ) {
localVarNames.add( var.getName() );
Expand All @@ -371,7 +367,7 @@ public String[] getLocalVarNames() {
public IRubyObject[] getLocalVarValues() {
if ( variables == null ) return IRubyObject.NULL_ARRAY;

List<IRubyObject> localVarValues = new ArrayList<IRubyObject>();
List<IRubyObject> localVarValues = new ArrayList<>(variables.size());
for ( final BiVariable var : variables ) {
if ( var.getType() == BiVariable.Type.LocalVariable ) {
localVarValues.add( var.getRubyObject() );
Expand All @@ -380,8 +376,8 @@ public IRubyObject[] getLocalVarValues() {
return localVarValues.toArray( new IRubyObject[ localVarValues.size() ] );
}

void inject(final ManyVarsDynamicScope scope, final int depth, final IRubyObject receiver) {
VariableInterceptor.inject(this, provider.getRuntime(), scope, depth, receiver);
void inject(final DynamicScope scope) {
VariableInterceptor.inject(this, scope);
}

void retrieve(final IRubyObject receiver) {
Expand Down Expand Up @@ -425,7 +421,7 @@ public Object removeFrom(final Object receiver, final Object key) {
checkKey(key);
final RubyObject robj = getReceiverObject(receiver);
for ( int i = 0; i < size(); i++ ) {
if ( ((String) key).equals( varNames.get(i) ) ) {
if ( key.equals( varNames.get(i) ) ) {
final BiVariable var = variables.get(i);
if ( var.isReceiverIdentical(robj) ) {
varNames.remove(i);
Expand Down
45 changes: 0 additions & 45 deletions core/src/main/java/org/jruby/embed/internal/CallMethodType.java

This file was deleted.

41 changes: 20 additions & 21 deletions core/src/main/java/org/jruby/embed/internal/EmbedEvalUnitImpl.java
Expand Up @@ -39,6 +39,8 @@
import org.jruby.embed.EvalFailedException;
import org.jruby.embed.ScriptingContainer;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.DynamicScope;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.scope.ManyVarsDynamicScope;
Expand All @@ -57,18 +59,17 @@ public class EmbedEvalUnitImpl implements EmbedEvalUnit {

private final ScriptingContainer container;
private final Node node;
private final ManyVarsDynamicScope scope;
private final DynamicScope scope;
private final Script script;

public EmbedEvalUnitImpl(ScriptingContainer container, Node node, ManyVarsDynamicScope scope) {
this(container, node, scope, null);
}
private final boolean wrapExceptions;

public EmbedEvalUnitImpl(ScriptingContainer container, Node node, ManyVarsDynamicScope scope, Script script) {
EmbedEvalUnitImpl(ScriptingContainer container, Node node, DynamicScope scope, Script script, boolean wrapExceptions) {
this.container = container;
this.node = node;
this.scope = scope;
this.script = script;
this.wrapExceptions = wrapExceptions;
}

/**
Expand All @@ -86,7 +87,7 @@ public Node getNode() {
*
* @return a scope to refer local variables
*/
public ManyVarsDynamicScope getScope() {
public DynamicScope getLocalVarScope() {
return scope;
}

Expand All @@ -101,13 +102,13 @@ public IRubyObject run() {
}
final Ruby runtime = container.getProvider().getRuntime();
final BiVariableMap vars = container.getVarMap();
final boolean sharing_variables = isSharingVariables();
final boolean sharing_variables = isSharingVariables(container);

// Keep reference to current context to prevent it being collected.
final ThreadContext threadContext = runtime.getCurrentContext();
final ThreadContext context = runtime.getCurrentContext();
if (sharing_variables) {
vars.inject(scope, 0, null);
threadContext.pushScope(scope);
vars.inject(scope);
context.pushScope(scope);
}
try {
final IRubyObject ret;
Expand All @@ -126,18 +127,17 @@ public IRubyObject run() {
// handle exits as simple script termination
if ( e.getException() instanceof RubySystemExit ) {
return ((RubySystemExit) e.getException()).status();
};
throw new EvalFailedException(e.getMessage(), e);
}
catch (StackOverflowError soe) {
throw runtime.newSystemStackError("stack level too deep", soe);
}
if (wrapExceptions) throw new EvalFailedException(e.getMessage(), e);
throw e;
}
catch (Throwable e) {
throw new EvalFailedException(e);
catch (Exception e) {
if (wrapExceptions) throw new EvalFailedException(e);
Helpers.throwException(e); return null; // never returns
}
finally {
if (sharing_variables) {
threadContext.popScope();
context.popScope();
}
vars.terminate();
/* Below lines doesn't work. Neither does classCache.flush(). How to clear cache?
Expand All @@ -147,10 +147,9 @@ public IRubyObject run() {
}
}

private boolean isSharingVariables() {
static boolean isSharingVariables(ScriptingContainer container) {
final Object sharing = container.getAttribute(AttributeName.SHARING_VARIABLES);
if ( sharing != null && sharing instanceof Boolean &&
((Boolean) sharing).booleanValue() == false ) {
if ( sharing instanceof Boolean && ((Boolean) sharing).booleanValue() == false ) {
return false;
}
return true;
Expand Down
Expand Up @@ -32,7 +32,6 @@
import org.jruby.Ruby;
import org.jruby.RubyNil;
import org.jruby.embed.EmbedRubyInterfaceAdapter;
import org.jruby.embed.InvokeFailedException;
import org.jruby.embed.ScriptingContainer;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.javasupport.JavaUtil;
Expand Down Expand Up @@ -73,16 +72,7 @@ public <T> T getInstance(Object receiver, Class<T> clazz) {
IRubyObject rubyReceiver = JavaUtil.convertJavaToRuby(runtime, receiver);
obj = JavaEmbedUtils.rubyToJava(runtime, rubyReceiver, clazz);
}
final String name = clazz.getName();
final ClassLoader loader = obj.getClass().getClassLoader();
try {
@SuppressWarnings("unchecked")
Class<T> klass = (Class<T>) Class.forName(name, true, loader);
return klass.cast(obj);
}
catch (ClassNotFoundException e) {
throw new InvokeFailedException(e);
}
return clazz.cast(obj);
}

}

0 comments on commit 552e8a1

Please sign in to comment.