Skip to content

Commit

Permalink
Showing 78 changed files with 738 additions and 372 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
@@ -1391,7 +1391,7 @@ public synchronized void reify(String classDumpDir, boolean useChildLoader) {
switch (methodEntry.getValue().getArity().getValue()) {
case 0:
signature = sig(IRubyObject.class);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);

m.aload(0);
@@ -1426,7 +1426,7 @@ public synchronized void reify(String classDumpDir, boolean useChildLoader) {
int rubyIndex = baseIndex;

signature = sig(methodSignature[0], params);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC | ACC_VARARGS, javaMethodName, signature, null, null);
m = new SkinnyMethodAdapter(cw, ACC_PUBLIC, javaMethodName, signature, null, null);
generateMethodAnnotations(methodAnnos, m, parameterAnnos);

m.getstatic(javaPath, "ruby", ci(Ruby.class));
6 changes: 5 additions & 1 deletion core/src/main/java/org/jruby/RubyRange.java
Original file line number Diff line number Diff line change
@@ -659,7 +659,11 @@ public IRubyObject max(ThreadContext context, Block block) {
if (!(begin instanceof RubyInteger)) {
throw context.runtime.newTypeError("cannot exclude end value with non Integer begin value");
}
rangeEnd = RubyFixnum.newFixnum(context.runtime, ((RubyInteger) end).getLongValue() - 1);
if (end instanceof RubyFixnum) {
rangeEnd = RubyFixnum.newFixnum(context.runtime, ((RubyFixnum)end).getLongValue() - 1);
} else {
rangeEnd = end.callMethod(context, "-", RubyFixnum.one(context.runtime));
}
} else {
rangeEnd = end;
}
75 changes: 63 additions & 12 deletions core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java
Original file line number Diff line number Diff line change
@@ -167,6 +167,7 @@ public RubyBigDecimal(Ruby runtime, RubyClass klass) {
this.isNaN = false;
this.infinitySign = 0;
this.zeroSign = 0;
this.value = BigDecimal.ZERO;
}

public RubyBigDecimal(Ruby runtime, BigDecimal value) {
@@ -499,26 +500,49 @@ private static RubyBigDecimal newInstance(Ruby runtime, IRubyObject recv, RubyBi
return new RubyBigDecimal(runtime, (RubyClass) recv, new BigDecimal(arg.getBigIntegerValue(), mathContext));
}

private final static Pattern NUMBER_PATTERN = Pattern.compile("^([+-]?\\d*\\.?\\d*([eE][+-]?)?\\d*).*");
private final static Pattern NUMBER_PATTERN = Pattern.compile("^([+-]?\\d*\\.?\\d*([eE]?)([+-]?\\d*)).*");

private static RubyBigDecimal newInstance(ThreadContext context, IRubyObject recv, IRubyObject arg, MathContext mathContext) {
String strValue = arg.convertToString().toString().trim();

switch ( strValue.length() > 2 ? strValue.charAt(0) : ' ' ) { // do not case length == 1
case 'N' :
if ( "NaN".equals(strValue) ) return newNaN(context.runtime);
case 'I' :
if ( "Infinity".equals(strValue) ) return newInfinity(context.runtime, 1);
case '-' :
if ( "-Infinity".equals(strValue) ) return newInfinity(context.runtime, -1);
case '+' :
if ( "+Infinity".equals(strValue) ) return newInfinity(context.runtime, +1);
int sign = 1;
if(strValue.length() > 0) {
switch (strValue.charAt(0)) {
case '_' :
return newZero(context.runtime, 1); // leading "_" are not allowed
case 'N' :
if ( "NaN".equals(strValue) ) return newNaN(context.runtime);
break;
case 'I' :
if ( "Infinity".equals(strValue) ) return newInfinity(context.runtime, 1);
break;
case '-' :
if ( "-Infinity".equals(strValue) ) return newInfinity(context.runtime, -1);
sign = -1;
break;
case '+' :
if ( "+Infinity".equals(strValue) ) return newInfinity(context.runtime, +1);
break;
}
}

// Convert String to Java understandable format (for BigDecimal).
strValue = strValue.replaceFirst("[dD]", "E"); // 1. MRI allows d and D as exponent separators
strValue = strValue.replaceAll("_", ""); // 2. MRI allows underscores anywhere
strValue = NUMBER_PATTERN.matcher(strValue).replaceFirst("$1"); // 3. MRI ignores the trailing junk

Matcher matcher = NUMBER_PATTERN.matcher(strValue);
strValue = matcher.replaceFirst("$1"); // 3. MRI ignores the trailing junk

String exp = matcher.group(2);
if(!exp.isEmpty()) {
String expValue = matcher.group(3);
if (expValue.isEmpty() || expValue.equals("-") || expValue.equals("+")) {
strValue = strValue.concat("0"); // 4. MRI allows 1E, 1E-, 1E+
} else if (isExponentOutOfRange(expValue)) {
// Handle infinity (Integer.MIN_VALUE + 1) < expValue < Integer.MAX_VALUE
return newInfinity(context.runtime, sign);
}
}

BigDecimal decimal;
try {
@@ -531,11 +555,38 @@ private static RubyBigDecimal newInstance(ThreadContext context, IRubyObject rec
}

// MRI behavior: -0 and +0 are two different things
if (decimal.signum() == 0) return newZero(context.runtime, strValue.matches("^\\s*-.*") ? -1 : 1);
if (decimal.signum() == 0) return newZero(context.runtime, sign);

return new RubyBigDecimal(context.runtime, (RubyClass) recv, decimal);
}

private static boolean isExponentOutOfRange(final String expValue) {
int num = 0;
int sign = 1;
final int len = expValue.length();
final char ch = expValue.charAt(0);
if (ch == '-') {
sign = -1;
} else if (ch != '+') {
num = '0' - ch;
}
int i = 1;
final int max = (sign == 1) ? -Integer.MAX_VALUE : Integer.MIN_VALUE + 1;
final int multmax = max / 10;
while (i < len) {
int d = expValue.charAt(i++) - '0';
if (num < multmax) {
return true;
}
num *= 10;
if (num < (max + d)) {
return true;
}
num -= d;
}
return false;
}

@Deprecated
public static RubyBigDecimal newInstance(IRubyObject recv, IRubyObject[] args) {
final ThreadContext context = recv.getRuntime().getCurrentContext();
Original file line number Diff line number Diff line change
@@ -238,7 +238,7 @@ public IRubyObject callNoProtocol(ThreadContext context, IRubyObject self, RubyM

@Override
public DynamicMethod dup() {
return new CompiledIRMethod(variable, specific, specificArity, method, visibility, implementationClass, hasKwargs);
return new CompiledIRMethod(variable, specific, specificArity, method, getVisibility(), implementationClass, hasKwargs);
}

public String getFile() {
Original file line number Diff line number Diff line change
@@ -103,11 +103,6 @@ public void setVisibility(Visibility visibility) {
delegate.setVisibility(visibility);
}

@Override
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik) {
delegate.setNativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik);
}

@Override
public void setIsBuiltin(boolean isBuiltin) {
delegate.setIsBuiltin(isBuiltin);
@@ -153,11 +148,6 @@ protected RubyModule getProtectedClass() {
return delegate.getProtectedClass();
}

@Override
public NativeCall getNativeCall() {
return delegate.getNativeCall();
}

@Override
public RubyModule getImplementationClass() {
return delegate.getImplementationClass();
@@ -208,11 +198,6 @@ public Object getHandle() {
return delegate.getHandle(); //To change body of overridden methods use File | Settings | File Templates.
}

@Override
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik, boolean java) {
delegate.setNativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik, java); //To change body of overridden methods use File | Settings | File Templates.
}

@Override
public DynamicMethod dup() {
return new ProfilingDynamicMethod(delegate.dup());
Original file line number Diff line number Diff line change
@@ -55,14 +55,12 @@ public abstract class DynamicMethod {
protected RubyModule implementationClass;
/** The "protected class" used for calculating protected access. */
protected RubyModule protectedClass;
/** The visibility of this method. */
protected Visibility visibility;
/** The visibility of this method. This is the ordinal of the Visibility enum value. */
private byte visibility;
/** The serial number for this method object, to globally identify it */
protected long serialNumber;
/** Flags for builtin, notimpl, etc */
protected byte flags;
/** Single-arity native call */
protected NativeCall nativeCall;
/** The simple, base name this method was defined under. May be null.*/
protected String name;
/** An arbitrarily-typed "method handle" for use by compilers and call sites */
@@ -108,7 +106,7 @@ protected DynamicMethod() {
}

protected void init(RubyModule implementationClass, Visibility visibility) {
this.visibility = visibility;
this.visibility = (byte)visibility.ordinal();
this.implementationClass = implementationClass;
// TODO: Determine whether we should perhaps store non-singleton class
// in the implementationClass
@@ -241,7 +239,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klaz
* @return true if the call would not violate visibility; false otherwise
*/
public boolean isCallableFrom(IRubyObject caller, CallType callType) {
switch (visibility) {
switch (Visibility.values()[visibility]) {
case PUBLIC:
return true;
case PRIVATE:
@@ -324,7 +322,7 @@ public void setImplementationClass(RubyModule implClass) {
* @return The visibility of this method
*/
public Visibility getVisibility() {
return visibility;
return Visibility.values()[visibility];
}

/**
@@ -333,7 +331,7 @@ public Visibility getVisibility() {
* @param visibility The visibility of this method
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
this.visibility = (byte)visibility.ordinal();
}

/**
@@ -452,40 +450,6 @@ public String toString() {
}
}

/**
* Set the single-arity NativeCall for this method. All signatures for the
* non-single-arity getNativeCall will also be set to this value.
*
* @param nativeTarget native method target
* @param nativeName native method name
* @param nativeReturn native method return
* @param nativeSignature native method arguments
* @param statik static?
* @param java plain Java method?
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik, boolean java) {
this.nativeCall = new NativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik, java);
}


/**
* Set the single-arity NativeCall for this method. All signatures for the
* non-single-arity getNativeCall will also be set to this value.
*
* @param nativeTarget native method target
* @param nativeName native method name
* @param nativeReturn native method return
* @param nativeSignature native method arguments
* @param statik static?
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik) {
setNativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik, false);
}

public NativeCall getNativeCall() {
return this.nativeCall;
}

/**
* Returns true if this method is backed by native (i.e. Java) code.
*
Original file line number Diff line number Diff line change
@@ -187,7 +187,7 @@ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule claz

@Override
public DynamicMethod dup() {
return new HandleMethod(implementationClass, visibility, targetsGenerator, signature, builtin, notImplemented, parameterDesc);
return new HandleMethod(implementationClass, getVisibility(), targetsGenerator, signature, builtin, notImplemented, parameterDesc);
}

@Override
Original file line number Diff line number Diff line change
@@ -273,7 +273,7 @@ protected void promoteToFullBuild(ThreadContext context) {

@Override
public DynamicMethod dup() {
return new InterpretedIRMethod(method, visibility, implementationClass);
return new InterpretedIRMethod(method, getVisibility(), implementationClass);
}

public String getClassName(ThreadContext context) {
Original file line number Diff line number Diff line change
@@ -36,14 +36,17 @@

/**
*/
public abstract class JavaMethod extends DynamicMethod implements Cloneable, MethodArgs2 {
public abstract class JavaMethod extends DynamicMethod implements Cloneable, MethodArgs2, NativeCallMethod {
protected Arity arity = Arity.OPTIONAL;
private String javaName;
private boolean isSingleton;
protected StaticScope staticScope;
private String parameterDesc;
private String[] parameterList;

/** Single-arity native call */
protected NativeCall nativeCall;

private static final String[] ONE_REQ = new String[] { "q" };
private static final String[] TWO_REQ = new String[] { "q", "q" };
private static final String[] THREE_REQ = new String[] { "q", "q", "q" };
@@ -238,6 +241,28 @@ public String[] getParameterList() {
return parameterList;
}

/**
* @see NativeCallMethod#setNativeCall(Class, String, Class, Class[], boolean, boolean)
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik, boolean java) {
this.nativeCall = new NativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik, java);
}


/**
* @see NativeCallMethod#setNativeCall(Class, String, Class, Class[], boolean)
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik) {
setNativeCall(nativeTarget, nativeName, nativeReturn, nativeSignature, statik, false);
}

/**
* @see NativeCallMethod#getNativeCall()
*/
public NativeCall getNativeCall() {
return this.nativeCall;
}

protected static IRubyObject raiseArgumentError(JavaMethod method, ThreadContext context, String name, int given, int min, int max) {
Arity.raiseArgumentError(context.runtime, name, given, min, max);
throw new AssertionError("expected to throw ArgumentError"); // never reached
Original file line number Diff line number Diff line change
@@ -341,7 +341,7 @@ protected void dupBox(MixedModeIRMethod orig) {

@Override
public DynamicMethod dup() {
MixedModeIRMethod x = new MixedModeIRMethod(method, visibility, implementationClass);
MixedModeIRMethod x = new MixedModeIRMethod(method, getVisibility(), implementationClass);
x.box = box;

return x;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.jruby.internal.runtime.methods;


/**
* Created by headius on 8/1/15.
*/
public interface NativeCallMethod {
/**
* Set the single-arity NativeCall for this method. All signatures for the
* non-single-arity getNativeCall will also be set to this value.
*
* @param nativeTarget native method target
* @param nativeName native method name
* @param nativeReturn native method return
* @param nativeSignature native method arguments
* @param statik static?
* @param java plain Java method?
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik, boolean java);

/**
* Set the single-arity NativeCall for this method. All signatures for the
* non-single-arity getNativeCall will also be set to this value.
*
* @param nativeTarget native method target
* @param nativeName native method name
* @param nativeReturn native method return
* @param nativeSignature native method arguments
* @param statik static?
*/
public void setNativeCall(Class nativeTarget, String nativeName, Class nativeReturn, Class[] nativeSignature, boolean statik);

/**
* Get the NativeCall for the method, if available.
*
* @return a NativeCall if the method has a native representation.
*/
public DynamicMethod.NativeCall getNativeCall();
}
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
*
* @author enebo
*/
public class IRWriterAnalzer implements IRWriterEncoder {
public class IRWriterAnalyzer implements IRWriterEncoder {
private int currentOffsetId = 0;
private final Map<String, Integer> offsetIds = new HashMap<String, Integer>();

Original file line number Diff line number Diff line change
@@ -37,14 +37,14 @@ public class IRWriterStream implements IRWriterEncoder, IRPersistenceValues {
// FIXME: Allocate direct and use one per thread?
private final ByteBuffer buf = ByteBuffer.allocate(TWO_MEGS);
private final OutputStream stream;
private final IRWriterAnalzer analyzer;
private final IRWriterAnalyzer analyzer;

int headersOffset = -1;
int poolOffset = -1;

public IRWriterStream(OutputStream stream) {
this.stream = stream;
this.analyzer = new IRWriterAnalzer();
this.analyzer = new IRWriterAnalyzer();
}

public IRWriterStream(File file) throws FileNotFoundException {
39 changes: 0 additions & 39 deletions core/src/main/java/org/jruby/ir/persistence/util/FileIO.java

This file was deleted.

8 changes: 5 additions & 3 deletions core/src/main/java/org/jruby/ir/targets/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -422,11 +422,13 @@ static MethodHandle buildNativeHandle(InvokeSite site, DynamicMethod method, boo
MethodHandle mh = null;
SmartBinder binder = null;

if (method.getNativeCall() != null) {
if (method instanceof NativeCallMethod) {
NativeCallMethod nativeMethod = (NativeCallMethod)method;
DynamicMethod.NativeCall nativeCall = nativeMethod.getNativeCall();

int nativeArgCount = getNativeArgCount(method, method.getNativeCall());
int nativeArgCount = getNativeArgCount(method, nativeCall);

DynamicMethod.NativeCall nc = method.getNativeCall();
DynamicMethod.NativeCall nc = nativeCall;

if (nc.isJava()) {
// not supported yet, use DynamicMethod.call
3 changes: 0 additions & 3 deletions spec/truffle/tags/language/constants_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions test/mri/excludes/TestBigDecimal.rb
Original file line number Diff line number Diff line change
@@ -23,9 +23,7 @@
exclude :test_limit, "needs investigation"
exclude :test_marshal, "needs investigation"
exclude :test_new, "needs investigation"
exclude :test_not_equal, "needs investigation"

exclude :test_power, "needs investigation"
exclude :test_power_of_finite_with_zero, "needs investigation"
exclude :test_power_of_nan, "needs investigation"
exclude :test_power_of_negative_infinity, "needs investigation"
1 change: 0 additions & 1 deletion test/mri/excludes/TestBigMath.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
exclude :test_log, "fails with DomainError (#2148)"
exclude :test_sqrt, "needs investigation"
1 change: 1 addition & 0 deletions test/mri/ruby/test_range.rb
Original file line number Diff line number Diff line change
@@ -69,6 +69,7 @@ def test_max
assert_equal(2, (1..2).max)
assert_equal(nil, (2..1).max)
assert_equal(1, (1...2).max)
assert_equal(18446744073709551615, (0...2**64).max)

assert_equal(2.0, (1.0..2.0).max)
assert_equal(nil, (2.0..1.0).max)
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@
package org.jruby.truffle.nodes.cast;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
@@ -86,6 +87,7 @@ public int cmpBignum(RubyBasicObject value, Object receiver, Object other) {
return BignumNodes.getBigIntegerValue(value).signum();
}

@TruffleBoundary
@Specialization(guards = "isNil(nil)")
public int cmpNil(Object nil, Object receiver, Object other) {
throw new RaiseException(
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.constants;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;

import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

@NodeChildren({
@NodeChild(value = "module", type = RubyNode.class),
@NodeChild(value = "name", type = RubyNode.class) })
public abstract class AbstractLookupConstantNode extends RubyNode {

public AbstractLookupConstantNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public abstract RubyConstant executeLookupConstant(VirtualFrame frame, Object module, String name);

}
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@

@NodeChildren({
@NodeChild("module"), @NodeChild("name"),
@NodeChild(value = "lookupConstantNode", type = LookupConstantNode.class, executeWith = { "module", "name" })
@NodeChild(value = "lookupConstantNode", type = AbstractLookupConstantNode.class, executeWith = { "module", "name" })
})
public abstract class GetConstantNode extends RubyNode {

@@ -40,7 +40,7 @@ public GetConstantNode(RubyContext context, SourceSection sourceSection) {
}

public abstract RubyNode getModule();
public abstract LookupConstantNode getLookupConstantNode();
public abstract AbstractLookupConstantNode getLookupConstantNode();

public abstract Object executeGetConstant(VirtualFrame frame, Object module, String name);

Original file line number Diff line number Diff line change
@@ -20,7 +20,6 @@
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.runtime.LexicalScope;
@@ -29,29 +28,18 @@
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyModule;

/**
* Caches {@link ModuleOperations#lookupConstant}
* and checks visibility.
* The {@link LexicalScope} is constant here.
* No {@link LexicalScope} is considered.
*/
@NodeChildren({ @NodeChild("module"), @NodeChild("name") })
public abstract class LookupConstantNode extends RubyNode {
public abstract class LookupConstantNode extends AbstractLookupConstantNode {

private final LexicalScope lexicalScope;

public LookupConstantNode(RubyContext context, SourceSection sourceSection, LexicalScope lexicalScope) {
public LookupConstantNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.lexicalScope = lexicalScope;
}

public LexicalScope getLexicalScope() {
return lexicalScope;
}

public abstract RubyConstant executeLookupConstant(VirtualFrame frame, Object module, String name);

@Specialization(guards = {
"isRubyModule(module)",
"module == cachedModule",
@@ -103,11 +91,11 @@ protected boolean guardName(String name, String cachedName, ConditionProfile sam
}

protected RubyConstant doLookup(RubyBasicObject module, String name) {
return ModuleOperations.lookupConstant(getContext(), lexicalScope, module, name);
return ModuleOperations.lookupConstant(getContext(), LexicalScope.NONE, module, name);
}

protected boolean isVisible(RubyBasicObject module, RubyConstant constant) {
return constant == null || constant.isVisibleTo(getContext(), lexicalScope, module);
return constant == null || constant.isVisibleTo(getContext(), LexicalScope.NONE, module);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.constants;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node.Child;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ConditionProfile;
import com.oracle.truffle.api.utilities.ValueProfile;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.nodes.lexical.GetLexicalScopeNode;
import org.jruby.truffle.nodes.objects.GetCurrentMethodNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.methods.InternalMethod;

/**
* Caches {@link ModuleOperations#lookupConstant}
* and checks visibility.
* The {@link LexicalScope} is derived from the current method.
*/
public abstract class LookupConstantWithLexicalScopeNode extends AbstractLookupConstantNode {

@Child GetLexicalScopeNode getLexicalScopeNode = new GetLexicalScopeNode(getContext(), getSourceSection());

public LookupConstantWithLexicalScopeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Specialization(guards = {
"isRubyModule(module)",
"module == cachedModule",
"getLexicalScope(frame) == cachedLexicalScope",
"guardName(name, cachedName, sameNameProfile)"
}, assumptions = "getUnmodifiedAssumption(cachedModule)", limit = "getCacheLimit()")
protected RubyConstant lookupConstant(VirtualFrame frame, RubyBasicObject module, String name,
@Cached("module") RubyBasicObject cachedModule,
@Cached("name") String cachedName,
@Cached("getLexicalScope(frame)") LexicalScope cachedLexicalScope,
@Cached("doLookup(cachedModule, cachedName, cachedLexicalScope)") RubyConstant constant,
@Cached("isVisible(cachedModule, constant, cachedLexicalScope)") boolean isVisible,
@Cached("createBinaryProfile()") ConditionProfile sameNameProfile) {
if (!isVisible) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameErrorPrivateConstant(module, name, this));
}
return constant;
}

public Assumption getUnmodifiedAssumption(RubyBasicObject module) {
return ModuleNodes.getModel(module).getUnmodifiedAssumption();
}

@Specialization(guards = "isRubyModule(module)")
protected RubyConstant lookupConstantUncached(VirtualFrame frame, RubyBasicObject module, String name) {
LexicalScope lexicalScope = getLexicalScope(frame);
CompilerDirectives.transferToInterpreter();
RubyConstant constant = doLookup(module, name, lexicalScope);
boolean isVisible = isVisible(module, constant, lexicalScope);

if (!isVisible) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameErrorPrivateConstant(module, name, this));
}
return constant;
}

@Specialization(guards = "!isRubyModule(module)")
protected RubyConstant lookupNotModule(Object module, String name) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeErrorIsNotA(module.toString(), "class/module", this));
}

protected LexicalScope getLexicalScope(VirtualFrame frame) {
return getLexicalScopeNode.getLexicalScope(frame);
}

protected boolean guardName(String name, String cachedName, ConditionProfile sameNameProfile) {
// This is likely as for literal constant lookup the name does not change and Symbols always return the same String.
if (sameNameProfile.profile(name == cachedName)) {
return true;
} else {
return name.equals(cachedName);
}
}

protected RubyConstant doLookup(RubyBasicObject module, String name, LexicalScope lexicalScope) {
return ModuleOperations.lookupConstant(getContext(), lexicalScope, module, name);
}

protected boolean isVisible(RubyBasicObject module, RubyConstant constant, LexicalScope lexicalScope) {
return constant == null || constant.isVisibleTo(getContext(), lexicalScope, module);
}

}
Original file line number Diff line number Diff line change
@@ -12,10 +12,10 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.literal.LiteralNode;
import org.jruby.truffle.runtime.ConstantReplacer;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -26,13 +26,21 @@ public class ReadConstantNode extends RubyNode {
private final String name;
@Child private GetConstantNode getConstantNode;

public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, LexicalScope lexicalScope) {
public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
this(context, sourceSection, name, receiver, false);
}

public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver, boolean considerLexicalScope) {
super(context, sourceSection);

this.name = ConstantReplacer.replacementName(sourceSection, name);
this.getConstantNode =
GetConstantNodeGen.create(context, sourceSection, receiver, new LiteralNode(context, sourceSection, this.name),
LookupConstantNodeGen.create(context, sourceSection, lexicalScope, null, null));
final AbstractLookupConstantNode lookupConstantNode;
if (considerLexicalScope) {
lookupConstantNode = LookupConstantWithLexicalScopeNodeGen.create(context, sourceSection, null, null);
} else {
lookupConstantNode = LookupConstantNodeGen.create(context, sourceSection, null, null);
}
this.getConstantNode = GetConstantNodeGen.create(context, sourceSection, receiver, new LiteralNode(context, sourceSection, this.name), lookupConstantNode);
}

@Override
Original file line number Diff line number Diff line change
@@ -140,8 +140,8 @@ private static void addMethod(RubyBasicObject module, RubyRootNode rootNode, Lis
visibility = Visibility.PRIVATE;
}

final InternalMethod method = new InternalMethod(rootNodeCopy.getSharedMethodInfo(), name, module, visibility, false,
Truffle.getRuntime().createCallTarget(rootNodeCopy), null);
final InternalMethod method = new InternalMethod(rootNodeCopy.getSharedMethodInfo(), name, module, visibility, LexicalScope.NONE,
false, Truffle.getRuntime().createCallTarget(rootNodeCopy), null);

ModuleNodes.getModel(module).addMethod(null, method.withVisibility(visibility).withName(name));
}
@@ -157,7 +157,7 @@ private static RubyRootNode makeGenericMethod(RubyContext context, MethodDetails

final Arity arity = new Arity(required, optional, method.rest());

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, LexicalScope.NONE, arity, methodDetails.getIndicativeName(), false, null, true);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, arity, methodDetails.getIndicativeName(), false, null, true);

final List<RubyNode> argumentsNodes = new ArrayList<>();

Original file line number Diff line number Diff line change
@@ -435,17 +435,22 @@ public Object encodingMap(VirtualFrame frame) {
final Object externalTuple = getContext().makeTuple(frame, newTupleNode, createString("external"), indexLookup(encodings, defaultExternalEncoding));
lookupTableWriteNode.call(frame, ret, "[]=", null, getSymbol("EXTERNAL"), externalTuple);

final Encoding localeEncoding = getContext().getRuntime().getEncodingService().getLocaleEncoding();
final Encoding localeEncoding = getLocaleEncoding();
final Object localeTuple = getContext().makeTuple(frame, newTupleNode, createString("locale"), indexLookup(encodings, localeEncoding));
lookupTableWriteNode.call(frame, ret, "[]=", null, getSymbol("LOCALE"), localeTuple);

final Encoding filesystemEncoding = getContext().getRuntime().getEncodingService().getLocaleEncoding();
final Encoding filesystemEncoding = getLocaleEncoding();
final Object filesystemTuple = getContext().makeTuple(frame, newTupleNode, createString("filesystem"), indexLookup(encodings, filesystemEncoding));
lookupTableWriteNode.call(frame, ret, "[]=", null, getSymbol("FILESYSTEM"), filesystemTuple);

return ret;
}

@TruffleBoundary
private Encoding getLocaleEncoding() {
return getContext().getRuntime().getEncodingService().getLocaleEncoding();
}

@TruffleBoundary
public Object indexLookup(RubyBasicObject[] encodings, Encoding encoding) {
// TODO (nirvdrum 25-Mar-15): Build up this lookup table in RubyEncoding as we register encodings.
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection;
@@ -114,6 +115,7 @@ public BacktraceNode(RubyContext context, SourceSection sourceSection) {
readCustomBacktrace = new ReadHeadObjectFieldNode("@custom_backtrace");
}

@TruffleBoundary
@Specialization
public Object backtrace(RubyBasicObject exception) {
if (readCustomBacktrace.isSet(exception)) {
16 changes: 16 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/FiberNodes.java
Original file line number Diff line number Diff line change
@@ -9,19 +9,23 @@
*/
package org.jruby.truffle.nodes.core;

import java.util.Deque;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ControlFlowException;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.SingleValueCastNode;
import org.jruby.truffle.nodes.cast.SingleValueCastNodeGen;
import org.jruby.truffle.nodes.core.FiberNodesFactory.FiberTransferNodeFactory;
import org.jruby.truffle.nodes.methods.UnsupportedOperationBehavior;
import org.jruby.truffle.nodes.objects.Allocator;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.control.ReturnException;
@@ -38,6 +42,18 @@ public static RubyFiber.FiberFields getFields(RubyBasicObject fiber) {
return getFields(((RubyFiber) fiber));
}

public static LexicalScope getLexicalScopeStack(RubyContext context) {
final RubyBasicObject currentThread = context.getThreadManager().getCurrentThread();
final RubyBasicObject currentFiber = ThreadNodes.getFiberManager(currentThread).getCurrentFiber();
return FiberNodes.getFields(currentFiber).lexicalScopeStack;
}

public static void setLexicalScopeStack(RubyContext context, LexicalScope lexicalScope) {
final RubyBasicObject currentThread = context.getThreadManager().getCurrentThread();
final RubyBasicObject currentFiber = ThreadNodes.getFiberManager(currentThread).getCurrentFiber();
FiberNodes.getFields(currentFiber).lexicalScopeStack = lexicalScope;
}

public static RubyBasicObject newRootFiber(RubyBasicObject thread, FiberManager fiberManager, ThreadManager threadManager) {
assert RubyGuards.isRubyThread(thread);
RubyContext context = thread.getContext();
Original file line number Diff line number Diff line change
@@ -539,9 +539,9 @@ public Object evalNoBindingCached(
cachedRootNode.getRootNode().getSharedMethodInfo().getName(),
getContext().getCoreLibrary().getObjectClass(),
Visibility.PUBLIC,
RubyArguments.getMethod(parentFrame.getArguments()).getLexicalScope(),
false,
cachedCallTarget,
parentFrame);
cachedCallTarget, parentFrame);

return callNode.call(frame, RubyArguments.pack(
method,
@@ -889,6 +889,7 @@ public int hash(boolean value) {
return Boolean.valueOf(value).hashCode();
}

@TruffleBoundary
@Specialization
public int hash(RubyBasicObject self) {
// TODO(CS 8 Jan 15) we shouldn't use the Java class hierarchy like this - every class should define it's
@@ -1969,6 +1970,7 @@ private RubyBasicObject finishFormat(ByteList format, PackResult result) {
return string;
}

@TruffleBoundary
protected CallTarget compileFormat(RubyBasicObject format) {
assert RubyGuards.isRubyString(format);

Original file line number Diff line number Diff line change
@@ -310,6 +310,7 @@ public RubyBasicObject toProcUncached(RubyBasicObject methodObject) {
null);
}

@TruffleBoundary
protected CallTarget method2proc(RubyBasicObject methodObject) {
// translate to something like:
// lambda { |same args list| method.call(args) }
Original file line number Diff line number Diff line change
@@ -406,7 +406,7 @@ public RubyBasicObject generateAccessor(VirtualFrame frame, RubyBasicObject modu
final String indicativeName = name + "(attr_" + (isGetter ? "reader" : "writer") + ")";

final CheckArityNode checkArity = new CheckArityNode(getContext(), sourceSection, arity);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, LexicalScope.NONE, arity, indicativeName, false, null, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, arity, indicativeName, false, null, false);

final SelfNode self = new SelfNode(getContext(), sourceSection);
final RubyNode accessInstanceVariable;
@@ -419,7 +419,7 @@ public RubyBasicObject generateAccessor(VirtualFrame frame, RubyBasicObject modu
final RubyNode sequence = SequenceNode.sequence(getContext(), sourceSection, checkArity, accessInstanceVariable);
final RubyRootNode rootNode = new RubyRootNode(getContext(), sourceSection, null, sharedMethodInfo, sequence);
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
final InternalMethod method = new InternalMethod(sharedMethodInfo, accessorName, module, visibility, false, callTarget, null);
final InternalMethod method = new InternalMethod(sharedMethodInfo, accessorName, module, visibility, LexicalScope.NONE, false, callTarget, null);

getModel(module).addMethod(this, method);
return nil();
@@ -897,7 +897,7 @@ public abstract static class ConstGetNode extends CoreMethodNode {
public ConstGetNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
this.getConstantNode = GetConstantNodeGen.create(context, sourceSection, null, null,
LookupConstantNodeGen.create(context, sourceSection, LexicalScope.NONE, null, null));
LookupConstantNodeGen.create(context, sourceSection, null, null));
}

@CreateCast("name")
@@ -1104,7 +1104,10 @@ private RubyBasicObject defineMethod(RubyBasicObject module, String name, RubyBa

final CallTarget modifiedCallTarget = ProcNodes.getCallTargetForLambdas(proc);
final SharedMethodInfo info = ProcNodes.getSharedMethodInfo(proc).withName(name);
final InternalMethod modifiedMethod = new InternalMethod(info, name, module, Visibility.PUBLIC, false, modifiedCallTarget, ProcNodes.getDeclarationFrame(proc));
final InternalMethod modifiedMethod = new InternalMethod(info, name, module, Visibility.PUBLIC,
ProcNodes.getMethod(proc).getLexicalScope(),
false, modifiedCallTarget,
ProcNodes.getDeclarationFrame(proc));

return addMethod(module, name, modifiedMethod);
}
@@ -1342,11 +1345,11 @@ public RubyBasicObject nesting() {
final List<RubyBasicObject> modules = new ArrayList<>();

InternalMethod method = RubyCallStack.getCallingMethod(getContext());
LexicalScope lexicalScope = method == null ? null : method.getSharedMethodInfo().getLexicalScope();
LexicalScope lexicalScope = method == null ? null : method.getLexicalScope();
RubyBasicObject object = getContext().getCoreLibrary().getObjectClass();

while (lexicalScope != null) {
final RubyBasicObject enclosing = lexicalScope.getLiveModule();
final RubyBasicObject enclosing = lexicalScope.getModule();
if (enclosing == object)
break;
modules.add(enclosing);
Original file line number Diff line number Diff line change
@@ -84,6 +84,7 @@ protected Object clock_gettime_realtime(int clock_id, RubyBasicObject unit) {
return timeToUnit(time, unit);
}

@TruffleBoundary
@Specialization(guards = { "isThreadCPUTime(clock_id)", "isRubySymbol(unit)" })
protected Object clock_gettime_thread_cputime(int clock_id, RubyBasicObject unit,
@Cached("getLibCClockGetTime()") LibCClockGetTime libCClockGetTime) {
Original file line number Diff line number Diff line change
@@ -76,6 +76,7 @@ public PushNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject push(RubyBasicObject self, final Object value) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -102,6 +103,7 @@ public RubyNode coerceToBoolean(RubyNode nonBlocking) {
return BooleanCastWithDefaultNodeGen.create(getContext(), getSourceSection(), false, nonBlocking);
}

@TruffleBoundary
@Specialization(guards = "!nonBlocking")
public Object popBlocking(RubyBasicObject self, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -114,6 +116,7 @@ public Object block() throws InterruptedException {
});
}

@TruffleBoundary
@Specialization(guards = "nonBlocking")
public Object popNonBlock(RubyBasicObject self, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -187,6 +190,7 @@ public EmptyNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public boolean empty(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -202,6 +206,7 @@ public SizeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public int size(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -217,6 +222,7 @@ public ClearNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject clear(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
Original file line number Diff line number Diff line change
@@ -640,6 +640,7 @@ public ToSNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject toS(RubyBasicObject regexp) {
return createString(((org.jruby.RubyString) org.jruby.RubyRegexp.newRegexp(getContext().getRuntime(), getSource(regexp), getRegex(regexp).getOptions()).to_s()).getByteList());
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
@@ -107,6 +108,7 @@ public SetMaxNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public int setMax(RubyBasicObject self, int newCapacity) {
if (newCapacity <= 0) {
@@ -136,6 +138,7 @@ public MaxNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public int max(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -178,6 +181,7 @@ public Boolean block() throws InterruptedException {
return self;
}

@TruffleBoundary
@Specialization(guards = "nonBlocking")
public RubyBasicObject pushNonBlock(RubyBasicObject self, final Object value, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -221,6 +225,7 @@ public Object block() throws InterruptedException {
});
}

@TruffleBoundary
@Specialization(guards = "nonBlocking")
public Object popNonBlock(RubyBasicObject self, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -243,6 +248,7 @@ public EmptyNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public boolean empty(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
@@ -273,6 +279,7 @@ public ClearNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject clear(RubyBasicObject self) {
final BlockingQueue<Object> queue = getQueue(self);
Original file line number Diff line number Diff line change
@@ -1477,6 +1477,7 @@ public LstripBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isSingleByteOptimizable(string)")
public Object lstripBangSingleByte(RubyBasicObject string) {
// Taken from org.jruby.RubyString#lstrip_bang19 and org.jruby.RubyString#singleByteLStrip.
@@ -1501,6 +1502,7 @@ public Object lstripBangSingleByte(RubyBasicObject string) {
return nil();
}

@TruffleBoundary
@Specialization(guards = "!isSingleByteOptimizable(string)")
public Object lstripBang(RubyBasicObject string) {
// Taken from org.jruby.RubyString#lstrip_bang19 and org.jruby.RubyString#multiByteLStrip.
@@ -1615,6 +1617,7 @@ public RstripBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isSingleByteOptimizable(string)")
public Object rstripBangSingleByte(RubyBasicObject string) {
// Taken from org.jruby.RubyString#rstrip_bang19 and org.jruby.RubyString#singleByteRStrip19.
@@ -1640,6 +1643,7 @@ public Object rstripBangSingleByte(RubyBasicObject string) {
return nil();
}

@TruffleBoundary
@Specialization(guards = "!isSingleByteOptimizable(string)")
public Object rstripBang(RubyBasicObject string) {
// Taken from org.jruby.RubyString#rstrip_bang19 and org.jruby.RubyString#multiByteRStrip19.
@@ -1687,6 +1691,7 @@ public SwapcaseBangNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject swapcaseSingleByte(RubyBasicObject string) {
// Taken from org.jruby.RubyString#swapcase_bang19.
@@ -1747,6 +1752,7 @@ public RubyBasicObject dumpAsciiCompatible(RubyBasicObject string) {
return result;
}

@TruffleBoundary
@Specialization(guards = "!isAsciiCompatible(string)")
public RubyBasicObject dump(RubyBasicObject string) {
// Taken from org.jruby.RubyString#dump
@@ -1887,6 +1893,11 @@ public Object squeezeBang(VirtualFrame frame, RubyBasicObject string, Object...
for (int i = 0; i < args.length; i++) {
otherStrings[i] = toStrNode.executeToStr(frame, args[i]);
}
return performSqueezeBang(string, otherStrings);
}

@TruffleBoundary
private Object performSqueezeBang(RubyBasicObject string, RubyBasicObject[] otherStrings) {

RubyBasicObject otherStr = otherStrings[0];
Encoding enc = checkEncoding(string, getCodeRangeable(otherStr), this);
Original file line number Diff line number Diff line change
@@ -227,8 +227,8 @@ protected RubyBasicObject createProc(RubyBasicObject symbol) {
.getCallNode().getEncapsulatingSourceSection();

final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(
sourceSection, null, Arity.NO_ARGUMENTS, getString(symbol),
true, null, false);
sourceSection, Arity.NO_ARGUMENTS, getString(symbol), true,
null, false);

final RubyRootNode rootNode = new RubyRootNode(
getContext(), sourceSection,
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
@@ -377,6 +378,7 @@ public InitializeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isRubyProc(block)")
public RubyBasicObject initialize(RubyBasicObject thread, Object[] arguments, RubyBasicObject block) {
ThreadNodes.initialize(thread, getContext(), this, arguments, block);
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
@@ -97,6 +98,7 @@ public InternalSetGMTNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public boolean internalSetGMT(RubyBasicObject time, boolean isGMT) {
if (isGMT) {
Original file line number Diff line number Diff line change
@@ -494,10 +494,6 @@ public Object appendArray(Object store, int index, RubyBasicObject array) {

@Override
public Object appendValue(Object store, int index, Object value) {
if (index >= ((Object[]) store).length) {
new Exception().printStackTrace();
}

((Object[]) store)[index] = value;
return store;
}
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.FrameDescriptor;
@@ -2578,7 +2579,7 @@ public MaxBlock(RubyContext context) {
frameDescriptor = new FrameDescriptor();
frameSlot = frameDescriptor.addFrameSlot("maximum_memo");

sharedMethodInfo = new SharedMethodInfo(sourceSection, null, Arity.NO_ARGUMENTS, "max", false, null, false);
sharedMethodInfo = new SharedMethodInfo(sourceSection, Arity.NO_ARGUMENTS, "max", false, null, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(
context, sourceSection, null, sharedMethodInfo,
@@ -2680,7 +2681,7 @@ public MinBlock(RubyContext context) {
frameDescriptor = new FrameDescriptor();
frameSlot = frameDescriptor.addFrameSlot("minimum_memo");

sharedMethodInfo = new SharedMethodInfo(sourceSection, null, Arity.NO_ARGUMENTS, "min", false, null, false);
sharedMethodInfo = new SharedMethodInfo(sourceSection, Arity.NO_ARGUMENTS, "min", false, null, false);

callTarget = Truffle.getRuntime().createCallTarget(new RubyRootNode(
context, sourceSection, null, sharedMethodInfo,
@@ -2830,6 +2831,7 @@ public Object pack(VirtualFrame frame, RubyBasicObject array, Object format) {
return ruby(frame, "pack(format.to_str)", "format", format);
}

@TruffleBoundary
protected CallTarget compileFormat(RubyBasicObject format) {
assert RubyGuards.isRubyString(format);
try {
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.nodes.exceptions;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
@@ -33,18 +34,23 @@ public Object execute(VirtualFrame frame) {
try {
return body.execute(frame);
} catch (RaiseException e) {
final Object rubyException = e.getRubyException();

for (String line : Backtrace.DISPLAY_FORMATTER.format(getContext(), (RubyBasicObject) rubyException, ExceptionNodes.getBacktrace((RubyBasicObject) rubyException))) {
System.err.println(line);
}

System.exit(1);
handleException(e);
} catch (ThreadExitException e) {
// Ignore
}

return nil();
}

@TruffleBoundary
private void handleException(RaiseException e) {
final Object rubyException = e.getRubyException();

for (String line : Backtrace.DISPLAY_FORMATTER.format(getContext(), (RubyBasicObject) rubyException, ExceptionNodes.getBacktrace((RubyBasicObject) rubyException))) {
System.err.println(line);
}

System.exit(1);
}

}
Original file line number Diff line number Diff line change
@@ -1715,7 +1715,7 @@ public static GetIntegerConstantNode create(RubyContext context, SourceSection s
return GetIntegerConstantNodeGen.create(
context, sourceSection, null, module,
GetConstantNodeGen.create(context, sourceSection, null, null,
LookupConstantNodeGen.create(context, sourceSection, LexicalScope.NONE, null, null)),
LookupConstantNodeGen.create(context, sourceSection, null, null)),
ToIntNodeGen.create(context, sourceSection, null),
IntegerCastNodeGen.create(context, sourceSection, null));
}
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.nodes.globals;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
@@ -32,6 +33,7 @@ public GetFromThreadLocalNode(RubyContext context, SourceSection sourceSection)
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public Object get(ThreadLocalObject threadLocal) {
return threadLocal.get();
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.lexical;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.GetCurrentMethodNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.methods.InternalMethod;

/**
* Find the RubyModule enclosing us lexically.
*/
public class GetLexicalScopeModuleNode extends RubyNode {

@Child GetCurrentMethodNode getCurrentMethodNode = new GetCurrentMethodNode(getContext(), getSourceSection());

public GetLexicalScopeModuleNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
return executeRubyBasicObject(frame);
}

@Override
public RubyBasicObject executeRubyBasicObject(VirtualFrame frame) {
final InternalMethod method = getCurrentMethodNode.getCurrentMethod(frame);
return method.getLexicalScope().getModule();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.lexical;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.GetCurrentMethodNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.methods.InternalMethod;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

public class GetLexicalScopeNode extends RubyNode {

public static GetLexicalScopeNode create(RubyContext context, SourceSection sourceSection) {
return new GetLexicalScopeNode(context, sourceSection);
}

@Child GetCurrentMethodNode getCurrentMethodNode = new GetCurrentMethodNode(getContext(), getSourceSection());

public GetLexicalScopeNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
final InternalMethod method = getCurrentMethodNode.getCurrentMethod(frame);
return method.getLexicalScope();
}

public LexicalScope getLexicalScope(VirtualFrame frame) {
return (LexicalScope) execute(frame);
}

}
Original file line number Diff line number Diff line change
@@ -12,7 +12,10 @@
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.FiberNodes;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.methods.SharedMethodInfo;
@@ -37,7 +40,8 @@ public MethodDefinitionNode(RubyContext context, SourceSection sourceSection, St
}

public InternalMethod executeMethod(VirtualFrame frame) {
return new InternalMethod(sharedMethodInfo, name, null, null, false, callTarget, frame.materialize());
final LexicalScope lexicalScope = FiberNodes.getLexicalScopeStack(getContext());
return new InternalMethod(sharedMethodInfo, name, null, null, lexicalScope, false, callTarget, frame.materialize());
}

@Override
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.objects;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.utilities.ValueProfile;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.methods.InternalMethod;

public class GetCurrentMethodNode extends RubyNode {

private final ValueProfile profileCurrentMethod = ValueProfile.createIdentityProfile();

public GetCurrentMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@Override
public Object execute(VirtualFrame frame) {
return profileCurrentMethod.profile(RubyArguments.getMethod(frame.getArguments()));
}

public InternalMethod getCurrentMethod(VirtualFrame frame) {
return (InternalMethod) execute(frame);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -9,12 +9,8 @@
*/
package org.jruby.truffle.nodes.objects;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.FiberNodes;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.nodes.methods.MethodDefinitionNode;
import org.jruby.truffle.runtime.LexicalScope;
@@ -23,21 +19,25 @@
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.methods.InternalMethod;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.source.SourceSection;

/**
* Open a module and execute a method in it - probably to define new methods.
*/
public class OpenModuleNode extends RubyNode {

@Child private RubyNode definingModule;
@Child private MethodDefinitionNode definitionMethod;
final protected LexicalScope lexicalScope;
@Child private IndirectCallNode callModuleDefinitionNode;

public OpenModuleNode(RubyContext context, SourceSection sourceSection, RubyNode definingModule, MethodDefinitionNode definitionMethod, LexicalScope lexicalScope) {
public OpenModuleNode(RubyContext context, SourceSection sourceSection, RubyNode definingModule, MethodDefinitionNode definitionMethod) {
super(context, sourceSection);
this.definingModule = definingModule;
this.definitionMethod = definitionMethod;
this.lexicalScope = lexicalScope;
callModuleDefinitionNode = Truffle.getRuntime().createIndirectCallNode();
}

@@ -48,11 +48,18 @@ public Object execute(VirtualFrame frame) {
// TODO(CS): cast
final RubyBasicObject module = (RubyBasicObject) definingModule.execute(frame);

lexicalScope.setLiveModule(module);
ModuleNodes.getModel(lexicalScope.getParent().getLiveModule()).addLexicalDependent(module);
final LexicalScope oldLexicalScope = FiberNodes.getLexicalScopeStack(getContext());
final LexicalScope newLexicalScope = new LexicalScope(oldLexicalScope, module);

final InternalMethod definition = definitionMethod.executeMethod(frame).withDeclaringModule(module);
return callModuleDefinitionNode.call(frame, definition.getCallTarget(), RubyArguments.pack(definition, definition.getDeclarationFrame(), module, null, new Object[]{}));
ModuleNodes.getModel(oldLexicalScope.getModule()).addLexicalDependent(module);
FiberNodes.setLexicalScopeStack(getContext(), newLexicalScope);
try {
final InternalMethod definition = definitionMethod.executeMethod(frame).withDeclaringModule(module);
final Object[] frameArguments = RubyArguments.pack(definition, definition.getDeclarationFrame(), module, null, new Object[] {});
return callModuleDefinitionNode.call(frame, definition.getCallTarget(), frameArguments);
} finally {
FiberNodes.setLexicalScopeStack(getContext(), oldLexicalScope);
}
}

}
Original file line number Diff line number Diff line change
@@ -12,38 +12,39 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class ReadClassVariableNode extends RubyNode {

private final String name;
private final LexicalScope lexicalScope;

public ReadClassVariableNode(RubyContext context, SourceSection sourceSection, String name, LexicalScope lexicalScope) {
public ReadClassVariableNode(RubyContext context, SourceSection sourceSection, String name) {
super(context, sourceSection);
this.name = name;
this.lexicalScope = lexicalScope;
}

public static RubyBasicObject resolveTargetModule(LexicalScope lexicalScope) {
// MRI logic: ignore lexical scopes (cref) referring to singleton classes
while (RubyGuards.isRubyClass(lexicalScope.getLiveModule()) && ModuleNodes.getModel((lexicalScope.getLiveModule())).isSingleton()) {
while (RubyGuards.isRubyClass(lexicalScope.getModule()) && ModuleNodes.getModel((lexicalScope.getModule())).isSingleton()) {
lexicalScope = lexicalScope.getParent();
}
return lexicalScope.getLiveModule();
return lexicalScope.getModule();
}

@Override
public Object execute(VirtualFrame frame) {
CompilerDirectives.transferToInterpreter();

final LexicalScope lexicalScope = RubyArguments.getMethod(frame.getArguments()).getLexicalScope();
final RubyBasicObject module = resolveTargetModule(lexicalScope);

assert RubyGuards.isRubyModule(module);
@@ -60,6 +61,7 @@ public Object execute(VirtualFrame frame) {

@Override
public Object isDefined(VirtualFrame frame) {
final LexicalScope lexicalScope = RubyArguments.getMethod(frame.getArguments()).getLexicalScope();
final RubyBasicObject module = resolveTargetModule(lexicalScope);

final Object value = ModuleOperations.lookupClassVariable(module, name);
Original file line number Diff line number Diff line change
@@ -12,22 +12,22 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class WriteClassVariableNode extends RubyNode {

private final String name;
private final LexicalScope lexicalScope;
@Child private RubyNode rhs;

public WriteClassVariableNode(RubyContext context, SourceSection sourceSection, String name, LexicalScope lexicalScope, RubyNode rhs) {
public WriteClassVariableNode(RubyContext context, SourceSection sourceSection, String name, RubyNode rhs) {
super(context, sourceSection);
this.name = name;
this.lexicalScope = lexicalScope;
this.rhs = rhs;
}

@@ -37,6 +37,7 @@ public Object execute(VirtualFrame frame) {

final Object rhsValue = rhs.execute(frame);

final LexicalScope lexicalScope = RubyArguments.getMethod(frame.getArguments()).getLexicalScope();
final RubyBasicObject module = ReadClassVariableNode.resolveTargetModule(lexicalScope);

ModuleOperations.setClassVariable(module, name, rhsValue, this);
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
@@ -82,6 +83,7 @@ public Object encodingConverterPrimitiveConvert(RubyBasicObject encodingConverte
return primitiveConvertHelper(encodingConverter, StringNodes.getByteList(source), source, target, offset, size, options);
}

@TruffleBoundary
private Object primitiveConvertHelper(RubyBasicObject encodingConverter, ByteList inBytes, RubyBasicObject source,
RubyBasicObject target, int offset, int size, int options) {
// Taken from org.jruby.RubyConverter#primitive_convert.
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.*;
@@ -197,8 +198,28 @@ public int fill(VirtualFrame frame, RubyBasicObject ioBuffer, RubyBasicObject io
count = left(frame, ioBuffer);
}

int bytesRead;
int bytesRead = performFill(fd, readBuffer, count);

if (bytesRead > 0) {
// Detect if another thread has updated the buffer
// and now there isn't enough room for this data.
if (bytesRead > left(frame, ioBuffer)) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().internalError("IO buffer overrun", this));
}
final int used = getUsed(ioBuffer);
final ByteList storage = ByteArrayNodes.getBytes(getStorage(ioBuffer));
System.arraycopy(readBuffer, 0, storage.getUnsafeBytes(), storage.getBegin() + used, bytesRead);
storage.setRealSize(used + bytesRead);
setUsed(ioBuffer, used + bytesRead);
}

return bytesRead;
}

@TruffleBoundary
private int performFill(int fd, byte[] readBuffer, int count) {
int bytesRead;
while (true) {
bytesRead = posix().read(fd, readBuffer, count);

@@ -223,21 +244,6 @@ public int fill(VirtualFrame frame, RubyBasicObject ioBuffer, RubyBasicObject io
break;
}
}

if (bytesRead > 0) {
// Detect if another thread has updated the buffer
// and now there isn't enough room for this data.
if (bytesRead > left(frame, ioBuffer)) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().internalError("IO buffer overrun", this));
}
final int used = getUsed(ioBuffer);
final ByteList storage = ByteArrayNodes.getBytes(getStorage(ioBuffer));
System.arraycopy(readBuffer, 0, storage.getUnsafeBytes(), storage.getBegin() + used, bytesRead);
storage.setRealSize(used + bytesRead);
setUsed(ioBuffer, used + bytesRead);
}

return bytesRead;
}

Original file line number Diff line number Diff line change
@@ -186,6 +186,7 @@ public boolean connectPipe(VirtualFrame frame, RubyBasicObject lhs, RubyBasicObj
return true;
}

@TruffleBoundary
private void newOpenFd(int newFd) {
final int FD_CLOEXEC = 1;

@@ -378,8 +379,8 @@ public IOReopenPrimitiveNode(RubyContext context, SourceSection sourceSection) {
resetBufferingNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@Specialization
public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject io) {
@TruffleBoundary
private void performReopen(RubyBasicObject file, RubyBasicObject io) {
final int fd = getDescriptor(file);
final int fdOther = getDescriptor(io);

@@ -395,6 +396,11 @@ public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject i
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}
setMode(file, mode);
}

@Specialization
public Object reopen(VirtualFrame frame, RubyBasicObject file, RubyBasicObject io) {
performReopen(file, io);

resetBufferingNode.call(frame, io, "reset_buffering", null);

@@ -413,8 +419,8 @@ public IOReopenPathPrimitiveNode(RubyContext context, SourceSection sourceSectio
resetBufferingNode = DispatchHeadNodeFactory.createMethodCall(context);
}

@Specialization(guards = "isRubyString(path)")
public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyBasicObject path, int mode) {
@TruffleBoundary
public void performReopenPath(RubyBasicObject file, RubyBasicObject path, int mode) {
int fd = getDescriptor(file);
final String pathString = StringNodes.getString(path);

@@ -449,6 +455,11 @@ public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyBasicObje
throw new RaiseException(getContext().getCoreLibrary().errnoError(posix().errno(), this));
}
setMode(file, newMode);
}

@Specialization(guards = "isRubyString(path)")
public Object reopenPath(VirtualFrame frame, RubyBasicObject file, RubyBasicObject path, int mode) {
performReopenPath(file, path, mode);

resetBufferingNode.call(frame, file, "reset_buffering", null);

@@ -464,8 +475,9 @@ public IOWritePrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(string)")
public int write(VirtualFrame frame, RubyBasicObject file, RubyBasicObject string) {
public int write(RubyBasicObject file, RubyBasicObject string) {
final int fd = getDescriptor(file);

final ByteList byteList = StringNodes.getByteList(string);
@@ -559,8 +571,9 @@ public AcceptNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public int accept(VirtualFrame frame, RubyBasicObject io) {
public int accept(RubyBasicObject io) {
final int fd = getDescriptor(io);

final int[] addressLength = {16};
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.rubinius;

import com.kenai.jffi.MemoryIO;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.ImportStatic;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
@@ -256,6 +257,7 @@ public long getAtOffsetULL(RubyBasicObject pointer, int offset, int type) {
return PointerNodes.getPointer(pointer).getLongLong(offset);
}

@TruffleBoundary
@Specialization(guards = "type == TYPE_STRING")
public RubyBasicObject getAtOffsetString(RubyBasicObject pointer, int offset, int type) {
return createString(PointerNodes.getPointer(pointer).getString(offset));
@@ -304,6 +306,7 @@ public RubyBasicObject readNullPointer(RubyBasicObject pointer) {
return StringNodes.createEmptyString(getContext().getCoreLibrary().getStringClass());
}

@TruffleBoundary
@Specialization(guards = "!isNullPointer(pointer)")
public RubyBasicObject readStringToNull(RubyBasicObject pointer) {
return createString(MemoryIO.getInstance().getZeroTerminatedByteArray(PointerNodes.getPointer(pointer).address()));
Original file line number Diff line number Diff line change
@@ -858,6 +858,7 @@ public int getaddrinfoNil(RubyBasicObject hostName, RubyBasicObject serviceName,
return getaddrinfoString(createString("0.0.0.0"), serviceName, hintsPointer, resultsPointer);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = {"isRubyString(hostName)", "isRubyString(serviceName)", "isRubyPointer(hintsPointer)", "isRubyPointer(resultsPointer)"})
public int getaddrinfoString(RubyBasicObject hostName, RubyBasicObject serviceName, RubyBasicObject hintsPointer, RubyBasicObject resultsPointer) {
return nativeSockets().getaddrinfo(
@@ -867,6 +868,7 @@ public int getaddrinfoString(RubyBasicObject hostName, RubyBasicObject serviceNa
PointerNodes.getPointer(resultsPointer));
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = {"isRubyString(hostName)", "isNil(serviceName)", "isRubyPointer(hintsPointer)", "isRubyPointer(resultsPointer)"})
public int getaddrinfo(RubyBasicObject hostName, RubyBasicObject serviceName, RubyBasicObject hintsPointer, RubyBasicObject resultsPointer) {
return nativeSockets().getaddrinfo(
@@ -885,6 +887,7 @@ public ConnectNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyPointer(address)")
public int connect(int socket, RubyBasicObject address, int address_len) {
return nativeSockets().connect(socket, PointerNodes.getPointer(address), address_len);
@@ -899,6 +902,7 @@ public FreeAddrInfoNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyPointer(addrInfo)")
public RubyBasicObject freeaddrinfo(RubyBasicObject addrInfo) {
nativeSockets().freeaddrinfo(PointerNodes.getPointer(addrInfo));
@@ -914,6 +918,7 @@ public GetNameInfoNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = {"isRubyPointer(sa)", "isRubyPointer(host)", "isRubyPointer(serv)"})
public int getnameinfo(RubyBasicObject sa, int salen, RubyBasicObject host, int hostlen, RubyBasicObject serv, int servlen, int flags) {
return nativeSockets().getnameinfo(
@@ -935,6 +940,7 @@ public SocketNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public int getnameinfo(int domain, int type, int protocol) {
return nativeSockets().socket(domain, type, protocol);
@@ -949,6 +955,7 @@ public SetSockOptNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyPointer(optionValue)")
public int setsockopt(int socket, int level, int optionName, RubyBasicObject optionValue, int optionLength) {
return nativeSockets().setsockopt(socket, level, optionName, PointerNodes.getPointer(optionValue), optionLength);
@@ -963,6 +970,7 @@ public BindNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyPointer(address)")
public int bind(int socket, RubyBasicObject address, int addressLength) {
return nativeSockets().bind(socket, PointerNodes.getPointer(address), addressLength);
@@ -977,6 +985,7 @@ public ListenNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization
public int listen(int socket, int backlog) {
return nativeSockets().listen(socket, backlog);
@@ -991,6 +1000,7 @@ public GetHostNameNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = "isRubyPointer(name)")
public int getHostName(RubyBasicObject name, int nameLength) {
return nativeSockets().gethostname(PointerNodes.getPointer(name), nameLength);
@@ -1005,6 +1015,7 @@ public GetPeerNameNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = {"isRubyPointer(address)", "isRubyPointer(addressLength)"})
public int getPeerName(int socket, RubyBasicObject address, RubyBasicObject addressLength) {
return nativeSockets().getpeername(socket, PointerNodes.getPointer(address), PointerNodes.getPointer(addressLength));
@@ -1019,6 +1030,7 @@ public GetSockNameNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CompilerDirectives.TruffleBoundary
@Specialization(guards = {"isRubyPointer(address)", "isRubyPointer(addressLength)"})
public int getSockName(int socket, RubyBasicObject address, RubyBasicObject addressLength) {
return nativeSockets().getsockname(socket, PointerNodes.getPointer(address), PointerNodes.getPointer(addressLength));
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@

package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
@@ -32,9 +33,14 @@ public Object execute(VirtualFrame frame) {
final FrameSlot slot = callerFrame.getFrameDescriptor().findFrameSlot("$_");
try {
final ThreadLocalObject threadLocalObject = (ThreadLocalObject) callerFrame.getObject(slot);
return threadLocalObject.get();
return getThreadLocal(threadLocalObject);
} catch (FrameSlotTypeException e) {
throw new UnsupportedOperationException(e);
}
}

@TruffleBoundary
private static Object getThreadLocal(ThreadLocalObject threadLocalObject) {
return threadLocalObject.get();
}
}
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.HiddenKey;
@@ -165,6 +166,7 @@ public StatStatPrimitiveNode(RubyContext context, SourceSection sourceSection) {
writeStatNode = new WriteHeadObjectFieldNode(STAT_IDENTIFIER);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(path)")
public int stat(RubyBasicObject rubyStat, RubyBasicObject path) {
final FileStat stat = posix().allocateStat();
@@ -196,6 +198,7 @@ public StatFStatPrimitiveNode(RubyContext context, SourceSection sourceSection)
writeStatNode = new WriteHeadObjectFieldNode(STAT_IDENTIFIER);
}

@TruffleBoundary
@Specialization
public int fstat(RubyBasicObject rubyStat, int fd) {
final FileStat stat = posix().allocateStat();
@@ -220,6 +223,7 @@ public StatLStatPrimitiveNode(RubyContext context, SourceSection sourceSection)
writeStatNode = new WriteHeadObjectFieldNode(STAT_IDENTIFIER);
}

@TruffleBoundary
@Specialization(guards = "isRubyString(path)")
public int lstat(RubyBasicObject rubyStat, RubyBasicObject path) {
final FileStat stat = posix().allocateStat();
Original file line number Diff line number Diff line change
@@ -590,6 +590,7 @@ public StringToFPrimitiveNode(RubyContext context, SourceSection sourceSection)
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public Object stringToF(RubyBasicObject string) {
try {
Original file line number Diff line number Diff line change
@@ -299,6 +299,7 @@ public TimeSetNSecondsPrimitiveNode(RubyContext context, SourceSection sourceSec
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public long timeSetNSeconds(RubyBasicObject time, int nanoseconds) {
TimeNodes.setDateTime(time, TimeNodes.getDateTime(time).withMillisOfSecond(nanoseconds / 1_000_000));
Original file line number Diff line number Diff line change
@@ -339,6 +339,7 @@ public TimesNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@TruffleBoundary
@Specialization
public RubyBasicObject times() {
// Copied from org/jruby/RubyProcess.java - see copyright and license information there
Original file line number Diff line number Diff line change
@@ -11,13 +11,13 @@

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.constants.ReadConstantNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.literal.LiteralNode;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

@@ -32,8 +32,7 @@ public ReadTimeZoneNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
hashNode = DispatchHeadNodeFactory.createMethodCall(context);
envNode = new ReadConstantNode(context, sourceSection, "ENV",
new LiteralNode(context, sourceSection, getContext().getCoreLibrary().getObjectClass()),
LexicalScope.NONE);
new LiteralNode(context, sourceSection, getContext().getCoreLibrary().getObjectClass()));
TZ = createString("TZ");
}

23 changes: 7 additions & 16 deletions truffle/src/main/java/org/jruby/truffle/runtime/LexicalScope.java
Original file line number Diff line number Diff line change
@@ -9,40 +9,31 @@
*/
package org.jruby.truffle.runtime;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class LexicalScope {
public static final LexicalScope NONE = null;

private final LexicalScope parent;
@CompilationFinal private RubyBasicObject liveModule;
private final RubyBasicObject module;

public LexicalScope(LexicalScope parent, RubyBasicObject liveModule) {
assert liveModule == null || RubyGuards.isRubyModule(liveModule);
public LexicalScope(LexicalScope parent, RubyBasicObject module) {
assert RubyGuards.isRubyModule(module);
this.parent = parent;
this.liveModule = liveModule;
}

public LexicalScope(LexicalScope parent) {
this(parent, null);
this.module = module;
}

public LexicalScope getParent() {
return parent;
}

public RubyBasicObject getLiveModule() {
return liveModule;
}

public void setLiveModule(RubyBasicObject liveModule) {
this.liveModule = liveModule;
public RubyBasicObject getModule() {
return module;
}

@Override
public String toString() {
return " :: " + liveModule + (parent == null ? "" : parent.toString());
return " :: " + module + (parent == null ? "" : parent.toString());
}
}
Original file line number Diff line number Diff line change
@@ -90,7 +90,7 @@ public static Map<String, RubyConstant> getAllConstants(RubyBasicObject module)
public static RubyConstant lookupConstant(RubyContext context, LexicalScope lexicalScope, RubyBasicObject module, String name) {
CompilerAsserts.neverPartOfCompilation();

assert lexicalScope == null || lexicalScope.getLiveModule() == module;
assert lexicalScope == null || lexicalScope.getModule() == module;
assert RubyGuards.isRubyModule(module);

RubyConstant constant;
@@ -110,7 +110,7 @@ public static RubyConstant lookupConstant(RubyContext context, LexicalScope lexi
}

while (lexicalScope != context.getRootLexicalScope()) {
constant = ModuleNodes.getModel(lexicalScope.getLiveModule()).getConstants().get(name);
constant = ModuleNodes.getModel(lexicalScope.getModule()).getConstants().get(name);

if (constant != null) {
return constant;
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ public boolean isVisibleTo(RubyContext context, LexicalScope lexicalScope, RubyB
CompilerAsserts.neverPartOfCompilation();

assert RubyGuards.isRubyModule(module);
assert lexicalScope == null || lexicalScope.getLiveModule() == module;
assert lexicalScope == null || lexicalScope.getModule() == module;

if (!isPrivate) {
return true;
@@ -58,7 +58,7 @@ public boolean isVisibleTo(RubyContext context, LexicalScope lexicalScope, RubyB
// Look in lexical scope
if (lexicalScope != null) {
while (lexicalScope != context.getRootLexicalScope()) {
if (lexicalScope.getLiveModule() == declaringModule) {
if (lexicalScope.getModule() == declaringModule) {
return true;
}
lexicalScope = lexicalScope.getParent();
20 changes: 19 additions & 1 deletion truffle/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -17,15 +17,18 @@
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.frame.FrameInstance.FrameAccess;
import com.oracle.truffle.api.instrument.Probe;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.tools.CoverageTracker;

import jnr.ffi.LibraryLoader;
import jnr.posix.POSIX;
import jnr.posix.POSIXFactory;

import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.Ruby;
@@ -57,6 +60,7 @@
import org.jruby.truffle.runtime.subsystems.*;
import org.jruby.truffle.translator.NodeWrapper;
import org.jruby.truffle.translator.TranslatorDriver;
import org.jruby.truffle.translator.TranslatorDriver.ParserContext;
import org.jruby.util.ByteList;
import org.jruby.util.cli.Options;

@@ -363,11 +367,25 @@ public Object execute(Source source, Encoding defaultEncoding, TranslatorDriver.
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);

final InternalMethod method = new InternalMethod(rootNode.getSharedMethodInfo(), rootNode.getSharedMethodInfo().getName(),
getCoreLibrary().getObjectClass(), Visibility.PUBLIC, false, callTarget, parentFrame);
getCoreLibrary().getObjectClass(), Visibility.PUBLIC, getLexicalScope(parserContext, self, parentFrame), false, callTarget, parentFrame);

return callTarget.call(RubyArguments.pack(method, parentFrame, self, null, new Object[]{}));
}

private LexicalScope getLexicalScope(ParserContext parserContext, Object self, MaterializedFrame parentFrame) {
final InternalMethod parentMethod = parentFrame == null ? null : RubyArguments.getMethod(parentFrame.getArguments());
LexicalScope lexicalScope;
if (parentMethod != null && parentMethod.getLexicalScope() != null) {
lexicalScope = parentMethod.getLexicalScope();
} else {
lexicalScope = getRootLexicalScope();
}
if (parserContext == TranslatorDriver.ParserContext.MODULE) {
lexicalScope = new LexicalScope(lexicalScope, (RubyBasicObject) self);
}
return lexicalScope;
}

public long getNextObjectID() {
// TODO(CS): We can theoretically run out of long values

Original file line number Diff line number Diff line change
@@ -12,11 +12,14 @@
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.core.FiberNodes;
import org.jruby.truffle.nodes.core.ThreadNodes;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.subsystems.FiberManager;
import org.jruby.truffle.runtime.subsystems.ThreadManager;

import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

@@ -34,6 +37,9 @@ public static class FiberFields {
public final boolean isRootFiber;
// we need 2 slots when the FiberManager sends the kill message and there is another message unprocessed
public final BlockingQueue<FiberNodes.FiberMessage> messageQueue = new LinkedBlockingQueue<>(2);

public LexicalScope lexicalScopeStack;

public volatile RubyBasicObject lastResumedByFiber = null;
public volatile boolean alive = true;
public volatile Thread thread;
@@ -42,6 +48,7 @@ public FiberFields(RubyBasicObject rubyThread, boolean isRootFiber) {
assert RubyGuards.isRubyThread(rubyThread);
this.rubyThread = rubyThread;
this.isRootFiber = isRootFiber;
this.lexicalScopeStack = rubyThread.getContext().getRootLexicalScope();
}
}

Original file line number Diff line number Diff line change
@@ -190,7 +190,7 @@ public void include(Node currentNode, RubyBasicObject module) {

// We need to include the module ancestors in reverse order for a given inclusionPoint
ModuleChain inclusionPoint = this;
Stack<RubyBasicObject> modulesToInclude = new Stack<>();
Deque<RubyBasicObject> modulesToInclude = new ArrayDeque<>();
for (RubyBasicObject ancestor : ModuleNodes.getModel(module).ancestors()) {
if (ModuleOperations.includesModule(rubyModuleObject, ancestor)) {
if (isIncludedModuleBeforeSuperClass(ancestor)) {
@@ -216,7 +216,7 @@ public void include(Node currentNode, RubyBasicObject module) {
newVersion();
}

public void performIncludes(ModuleChain inclusionPoint, Stack<RubyBasicObject> moduleAncestors) {
public void performIncludes(ModuleChain inclusionPoint, Deque<RubyBasicObject> moduleAncestors) {
while (!moduleAncestors.isEmpty()) {
RubyBasicObject mod = moduleAncestors.pop();
assert RubyGuards.isRubyModule(mod);
Original file line number Diff line number Diff line change
@@ -12,9 +12,11 @@
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.nodes.Node;

import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.core.RubyBasicObject;

/**
@@ -28,19 +30,21 @@ public class InternalMethod {

private final RubyBasicObject declaringModule;
private final Visibility visibility;
private LexicalScope lexicalScope;
private final boolean undefined;

private final CallTarget callTarget;
private final MaterializedFrame declarationFrame;

public InternalMethod(SharedMethodInfo sharedMethodInfo, String name,
RubyBasicObject declaringModule, Visibility visibility, boolean undefined,
CallTarget callTarget, MaterializedFrame declarationFrame) {
RubyBasicObject declaringModule, Visibility visibility, LexicalScope lexicalScope,
boolean undefined, CallTarget callTarget, MaterializedFrame declarationFrame) {
assert declaringModule == null || RubyGuards.isRubyModule(declaringModule);
this.sharedMethodInfo = sharedMethodInfo;
this.declaringModule = declaringModule;
this.name = name;
this.visibility = visibility;
this.lexicalScope = lexicalScope;
this.undefined = undefined;
this.callTarget = callTarget;
this.declarationFrame = declarationFrame;
@@ -62,6 +66,10 @@ public Visibility getVisibility() {
return visibility;
}

public LexicalScope getLexicalScope() {
return lexicalScope;
}

public boolean isUndefined() {
return undefined;
}
@@ -80,28 +88,28 @@ public InternalMethod withDeclaringModule(RubyBasicObject newDeclaringModule) {
if (newDeclaringModule == declaringModule) {
return this;
} else {
return new InternalMethod(sharedMethodInfo, name, newDeclaringModule, visibility, undefined, callTarget, declarationFrame);
return new InternalMethod(sharedMethodInfo, name, newDeclaringModule, visibility, lexicalScope, undefined, callTarget, declarationFrame);
}
}

public InternalMethod withName(String newName) {
if (newName.equals(name)) {
return this;
} else {
return new InternalMethod(sharedMethodInfo, newName, declaringModule, visibility, undefined, callTarget, declarationFrame);
return new InternalMethod(sharedMethodInfo, newName, declaringModule, visibility, lexicalScope, undefined, callTarget, declarationFrame);
}
}

public InternalMethod withVisibility(Visibility newVisibility) {
if (newVisibility == visibility) {
return this;
} else {
return new InternalMethod(sharedMethodInfo, name, declaringModule, newVisibility, undefined, callTarget, declarationFrame);
return new InternalMethod(sharedMethodInfo, name, declaringModule, newVisibility, lexicalScope, undefined, callTarget, declarationFrame);
}
}

public InternalMethod undefined() {
return new InternalMethod(sharedMethodInfo, name, declaringModule, visibility, true, callTarget, declarationFrame);
return new InternalMethod(sharedMethodInfo, name, declaringModule, visibility, lexicalScope, true, callTarget, declarationFrame);
}

public boolean isVisibleTo(Node currentNode, RubyBasicObject callerClass) {
Original file line number Diff line number Diff line change
@@ -20,20 +20,18 @@
public class SharedMethodInfo {

private final SourceSection sourceSection;
private final LexicalScope lexicalScope;
private final Arity arity;
/** The original name of the method. Does not change when aliased. */
private final String name;
private final boolean isBlock;
private final org.jruby.ast.Node parseTree;
private final boolean alwaysSplit;

public SharedMethodInfo(SourceSection sourceSection, LexicalScope lexicalScope, Arity arity, String name, boolean isBlock, Node parseTree, boolean alwaysSplit) {
public SharedMethodInfo(SourceSection sourceSection, Arity arity, String name, boolean isBlock, Node parseTree, boolean alwaysSplit) {
assert sourceSection != null;
assert name != null;

this.sourceSection = sourceSection;
this.lexicalScope = lexicalScope;
this.arity = arity;
this.name = name;
this.isBlock = isBlock;
@@ -45,10 +43,6 @@ public SourceSection getSourceSection() {
return sourceSection;
}

public LexicalScope getLexicalScope() {
return lexicalScope;
}

public Arity getArity() {
return arity;
}
@@ -70,7 +64,7 @@ public boolean shouldAlwaysSplit() {
}

public SharedMethodInfo withName(String newName) {
return new SharedMethodInfo(sourceSection, lexicalScope, arity, newName, isBlock, parseTree, alwaysSplit);
return new SharedMethodInfo(sourceSection, arity, newName, isBlock, parseTree, alwaysSplit);
}

@Override
Original file line number Diff line number Diff line change
@@ -95,6 +95,7 @@ public void initializeCurrentThread(RubyBasicObject thread) {
currentThread.set(thread);
}

@TruffleBoundary
public RubyBasicObject getCurrentThread() {
return currentThread.get();
}
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.joni.NameEntry;
import org.joni.Regex;
import org.joni.Syntax;
@@ -52,6 +53,7 @@
import org.jruby.truffle.nodes.exceptions.*;
import org.jruby.truffle.nodes.exceptions.RescueNode;
import org.jruby.truffle.nodes.globals.*;
import org.jruby.truffle.nodes.lexical.GetLexicalScopeModuleNode;
import org.jruby.truffle.nodes.literal.LiteralNode;
import org.jruby.truffle.nodes.literal.RangeLiteralNodeGen;
import org.jruby.truffle.nodes.literal.StringLiteralNode;
@@ -841,21 +843,16 @@ public RubyNode visitCaseNode(org.jruby.ast.CaseNode node) {
}

private RubyNode openModule(SourceSection sourceSection, RubyNode defineOrGetNode, String name, Node bodyNode) {
LexicalScope newLexicalScope = environment.pushLexicalScope();
try {
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, newLexicalScope, Arity.NO_ARGUMENTS, name, false, bodyNode, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, Arity.NO_ARGUMENTS, name, false, bodyNode, false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParseEnvironment(),
environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, name, false, null);
final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(context, environment, environment.getParseEnvironment(),
environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, name, false, null);

final ModuleTranslator classTranslator = new ModuleTranslator(currentNode, context, this, newEnvironment, source);
final ModuleTranslator classTranslator = new ModuleTranslator(currentNode, context, this, newEnvironment, source);

final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(sourceSection, name, bodyNode);
final MethodDefinitionNode definitionMethod = classTranslator.compileClassNode(sourceSection, name, bodyNode);

return new OpenModuleNode(context, sourceSection, defineOrGetNode, definitionMethod, newLexicalScope);
} finally {
environment.popLexicalScope();
}
return new OpenModuleNode(context, sourceSection, defineOrGetNode, definitionMethod);
}

@Override
@@ -882,13 +879,13 @@ public RubyNode visitClassNode(org.jruby.ast.ClassNode node) {
public RubyNode visitClassVarAsgnNode(org.jruby.ast.ClassVarAsgnNode node) {
final SourceSection sourceSection = translate(node.getPosition());
final RubyNode rhs = node.getValueNode().accept(this);
return new WriteClassVariableNode(context, sourceSection, node.getName(), environment.getLexicalScope(), rhs);
return new WriteClassVariableNode(context, sourceSection, node.getName(), rhs);
}

@Override
public RubyNode visitClassVarNode(org.jruby.ast.ClassVarNode node) {
final SourceSection sourceSection = translate(node.getPosition());
return new ReadClassVariableNode(context, sourceSection, node.getName(), environment.getLexicalScope());
return new ReadClassVariableNode(context, sourceSection, node.getName());
}

@Override
@@ -900,7 +897,7 @@ public RubyNode visitColon2Node(org.jruby.ast.Colon2Node node) {

final RubyNode lhs = node.getLeftNode().accept(this);

return new ReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs, LexicalScope.NONE);
return new ReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs);
}

@Override
@@ -911,12 +908,12 @@ public RubyNode visitColon3Node(org.jruby.ast.Colon3Node node) {

final LiteralNode root = new LiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());

return new ReadConstantNode(context, sourceSection, node.getName(), root, LexicalScope.NONE);
return new ReadConstantNode(context, sourceSection, node.getName(), root);
}

private RubyNode translateCPath(SourceSection sourceSection, org.jruby.ast.Colon3Node node) {
if (node instanceof Colon2ImplicitNode) { // use current lexical scope
return new LexicalScopeNode(context, sourceSection, environment.getLexicalScope());
return new GetLexicalScopeModuleNode(context, sourceSection);
} else if (node instanceof Colon2ConstNode) { // A::B
return node.childNodes().get(0).accept(this);
} else { // Colon3Node: on top-level (Object)
@@ -944,7 +941,7 @@ private RubyNode visitConstDeclNode(org.jruby.ast.ConstDeclNode node, RubyNode r
RubyNode moduleNode;
Node constNode = node.getConstNode();
if (constNode == null || constNode instanceof Colon2ImplicitNode) {
moduleNode = new LexicalScopeNode(context, sourceSection, environment.getLexicalScope());
moduleNode = new GetLexicalScopeModuleNode(context, sourceSection);
} else if (constNode instanceof Colon2ConstNode) {
constNode = ((Colon2Node) constNode).getLeftNode(); // Misleading doc, we only want the defined part.
moduleNode = constNode.accept(this);
@@ -973,9 +970,8 @@ public RubyNode visitConstNode(org.jruby.ast.ConstNode node) {
return new org.jruby.ast.Colon3Node(node.getPosition(), node.getName()).accept(this);
}

final LexicalScope lexicalScope = environment.getLexicalScope();
final RubyNode moduleNode = new LexicalScopeNode(context, sourceSection, lexicalScope);
return new ReadConstantNode(context, sourceSection, node.getName(), moduleNode, lexicalScope);
final RubyNode moduleNode = new GetLexicalScopeModuleNode(context, sourceSection);
return new ReadConstantNode(context, sourceSection, node.getName(), moduleNode, true);
}

@Override
@@ -1111,7 +1107,7 @@ public RubyNode visitDefsNode(org.jruby.ast.DefsNode node) {
}

protected RubyNode translateMethodDefinition(SourceSection sourceSection, RubyNode classNode, String methodName, org.jruby.ast.Node parseTree, org.jruby.ast.ArgsNode argsNode, org.jruby.ast.Node bodyNode) {
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, environment.getLexicalScope(), MethodTranslator.getArity(argsNode), methodName, false, parseTree, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, MethodTranslator.getArity(argsNode), methodName, false, parseTree, false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getParseEnvironment().allocateReturnID(), true, true, sharedMethodInfo, methodName, false, null);
@@ -1723,7 +1719,7 @@ public RubyNode visitIterNode(org.jruby.ast.IterNode node) {
}

// Unset this flag for any for any blocks within the for statement's body
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, environment.getLexicalScope(), MethodTranslator.getArity(argsNode), currentCallMethodName, true, node, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, MethodTranslator.getArity(argsNode), currentCallMethodName, true, node, false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getReturnID(), hasOwnScope, false,
@@ -2451,11 +2447,10 @@ public RubyNode visitRationalNode(RationalNode node) {
private RubyNode translateRationalComplex(SourceSection sourceSection, String name, RubyNode a, RubyNode b) {
// Translate as Rubinius.privately { Rational.convert(a, b) }

final LexicalScope lexicalScope = environment.getLexicalScope();
final RubyNode moduleNode = new LexicalScopeNode(context, sourceSection, lexicalScope);
final RubyNode moduleNode = new LiteralNode(context, sourceSection, context.getCoreLibrary().getObjectClass());
return new RubyCallNode(
context, sourceSection, "convert",
new ReadConstantNode(context, sourceSection, name, moduleNode, lexicalScope),
new ReadConstantNode(context, sourceSection, name, moduleNode),
null, false, true, new RubyNode[]{a, b});
}

@@ -2847,7 +2842,7 @@ public RubyNode visitLambdaNode(org.jruby.ast.LambdaNode node) {
}

// TODO(cs): code copied and modified from visitIterNode - extract common
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, environment.getLexicalScope(), MethodTranslator.getArity(argsNode), "(lambda)", true, node, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, MethodTranslator.getArity(argsNode), "(lambda)", true, node, false);

final TranslatorEnvironment newEnvironment = new TranslatorEnvironment(
context, environment, environment.getParseEnvironment(), environment.getReturnID(), false, false,
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@
*/
package org.jruby.truffle.translator;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
@@ -29,6 +30,11 @@ public DeadNode(RubyContext context, SourceSection sourceSection, Exception reas

@Override
public Object execute(VirtualFrame frame) {
throw new UnsupportedOperationException(reason);
throw exception();
}

@TruffleBoundary
private RuntimeException exception() {
return new UnsupportedOperationException(reason);
}
}
Original file line number Diff line number Diff line change
@@ -19,27 +19,9 @@
*/
public class ParseEnvironment {

private LexicalScope lexicalScope = null;

public ParseEnvironment(RubyContext context) {
}

public void resetLexicalScope(LexicalScope lexicalScope) {
this.lexicalScope = lexicalScope;
}

public LexicalScope getLexicalScope() {
return lexicalScope;
}

public LexicalScope pushLexicalScope() {
return lexicalScope = new LexicalScope(lexicalScope);
}

public void popLexicalScope() {
lexicalScope = lexicalScope.getParent();
}

public ReturnID allocateReturnID() {
return new ReturnID();
}
Original file line number Diff line number Diff line change
@@ -17,12 +17,14 @@
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.Encoding;
import org.jruby.parser.StaticScope;
import org.jruby.runtime.scope.ManyVarsDynamicScope;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.FiberNodes;
import org.jruby.truffle.nodes.core.ModuleNodes;
import org.jruby.truffle.nodes.defined.DefinedWrapperNode;
import org.jruby.truffle.nodes.literal.LiteralNode;
@@ -107,21 +109,8 @@ public RubyRootNode parse(RubyContext context, Source source, Encoding defaultEn
private RubyRootNode parse(Node currentNode, RubyContext context, Source source, ParserContext parserContext, MaterializedFrame parentFrame, boolean ownScopeForAssignments, org.jruby.ast.RootNode rootNode, NodeWrapper wrapper) {
final SourceSection sourceSection = source.createSection("<main>", 0, source.getCode().length());

final InternalMethod parentMethod = parentFrame == null ? null : RubyArguments.getMethod(parentFrame.getArguments());
LexicalScope lexicalScope;
if (parentMethod != null && parentMethod.getSharedMethodInfo().getLexicalScope() != null) {
lexicalScope = parentMethod.getSharedMethodInfo().getLexicalScope();
} else {
lexicalScope = context.getRootLexicalScope();
}
if (parserContext == TranslatorDriver.ParserContext.MODULE) {
Object module = RubyArguments.getSelf(Truffle.getRuntime().getCurrentFrame().getFrame(FrameAccess.READ_ONLY, true).getArguments());
lexicalScope = new LexicalScope(lexicalScope, (RubyBasicObject) module);
}
parseEnvironment.resetLexicalScope(lexicalScope);

// TODO (10 Feb. 2015): name should be "<top (required)> for the require-d/load-ed files.
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, parseEnvironment.getLexicalScope(), Arity.NO_ARGUMENTS, "<main>", false, rootNode, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, Arity.NO_ARGUMENTS, "<main>", false, rootNode, false);

final TranslatorEnvironment environment = new TranslatorEnvironment(context, environmentForFrame(context, parentFrame),
parseEnvironment, parseEnvironment.allocateReturnID(), ownScopeForAssignments, false, sharedMethodInfo, sharedMethodInfo.getName(), false, null);
@@ -211,7 +200,7 @@ private TranslatorEnvironment environmentForFrame(RubyContext context, Materiali
return null;
} else {
SourceSection sourceSection = SourceSection.createUnavailable("Unknown source section", "(unknown)");
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, context.getRootLexicalScope(), Arity.NO_ARGUMENTS, "(unknown)", false, null, false);
final SharedMethodInfo sharedMethodInfo = new SharedMethodInfo(sourceSection, Arity.NO_ARGUMENTS, "(unknown)", false, null, false);
final MaterializedFrame parent = RubyArguments.getDeclarationFrame(frame.getArguments());
// TODO(CS): how do we know if the frame is a block or not?
return new TranslatorEnvironment(context, environmentForFrame(context, parent), parseEnvironment,
Original file line number Diff line number Diff line change
@@ -79,18 +79,6 @@ public TranslatorEnvironment(RubyContext context, TranslatorEnvironment parent,
new FrameDescriptor(context.getCoreLibrary().getNilObject()));
}

public LexicalScope getLexicalScope() {
return parseEnvironment.getLexicalScope();
}

public LexicalScope pushLexicalScope() {
return parseEnvironment.pushLexicalScope();
}

public void popLexicalScope() {
parseEnvironment.popLexicalScope();
}

public TranslatorEnvironment getParent() {
return parent;
}

0 comments on commit 28797d4

Please sign in to comment.