Skip to content

Commit

Permalink
Showing 29 changed files with 553 additions and 181 deletions.
2 changes: 1 addition & 1 deletion core/pom.rb
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@
jar 'org.jruby.joni:joni:2.1.5'
jar 'org.jruby.extras:bytelist:1.0.12'
jar 'org.jruby.jcodings:jcodings:1.0.12'
jar 'org.jruby:dirgra:0.1'
jar 'org.jruby:dirgra:0.2'

jar 'com.headius:invokebinder:1.5'
jar 'com.headius:options:1.1'
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
@@ -147,7 +147,7 @@
<dependency>
<groupId>org.jruby</groupId>
<artifactId>dirgra</artifactId>
<version>0.1</version>
<version>0.2</version>
</dependency>
<dependency>
<groupId>com.headius</groupId>
16 changes: 6 additions & 10 deletions core/src/main/java/org/jruby/RubyProcess.java
Original file line number Diff line number Diff line change
@@ -113,7 +113,7 @@ public static RubyModule createProcessModule(Ruby runtime) {
public static final String CLOCK_UNIT_FLOAT_MILLISECOND = "float_millisecond";
public static final String CLOCK_UNIT_FLOAT_SECOND = "float_second";
public static final String CLOCK_UNIT_HERTZ = "hertz";

@JRubyClass(name="Process::Status")
public static class RubyStatus extends RubyObject {
private final long status;
@@ -573,16 +573,12 @@ public static IRubyObject exit_bang(IRubyObject recv, IRubyObject[] args) {

@JRubyMethod(name = "groups", module = true, visibility = PRIVATE)
public static IRubyObject groups(IRubyObject recv) {
if(Platform.IS_WINDOWS) {
throw recv.getRuntime().newNotImplementedError("groups() function is unimplemented on this machine");
} else {
long[] groups = (new com.sun.security.auth.module.UnixSystem()).getGroups();
RubyArray ary = RubyArray.newArray(recv.getRuntime(), groups.length);
for(int i = 0; i < groups.length; i++) {
ary.push(RubyFixnum.newFixnum(recv.getRuntime(), groups[i]));
}
return ary;
long[] groups = Platform.getPlatform().getGroups(recv);
RubyArray ary = RubyArray.newArray(recv.getRuntime(), groups.length);
for(int i = 0; i < groups.length; i++) {
ary.push(RubyFixnum.newFixnum(recv.getRuntime(), groups[i]));
}
return ary;
}

@JRubyMethod(name = "setrlimit", rest = true, module = true, visibility = PRIVATE)
85 changes: 0 additions & 85 deletions core/src/main/java/org/jruby/RubyRegexp.java
Original file line number Diff line number Diff line change
@@ -1965,91 +1965,6 @@ public static IRubyObject match_last(IRubyObject match) {
return nth_match(i, match);
}

static RubyString regsub(RubyString str, RubyString src, Matcher matcher, Encoding enc) {
Region regs = matcher.getRegion();

int no = -1;
ByteList bs = str.getByteList();
int p = bs.getBegin();
int s = p;
int end = p + bs.getRealSize();
byte[]bytes = bs.getUnsafeBytes();

ByteList srcbs = src.getByteList();

ByteList val = null;

while (s < end) {
int ss = s;
int c = bytes[s] & 0xff;
int l = enc.length(bytes, s++, end);
if (l != 1) {
s += l - 1;
continue;
}
if (c != '\\' || s == end) continue;
if (val == null) val = new ByteList(ss - p);

val.append(bytes, p, ss - p);
c = bytes[s++] & 0xff;
p = s;

switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
no = c - '0';
break;
case '&':
no = 0;
break;
case '`':
val.append( srcbs.getUnsafeBytes(), srcbs.getBegin(), matcher.getBegin());
continue;
case '\'':
val.append(srcbs.getUnsafeBytes(), srcbs.getBegin() + matcher.getEnd(), srcbs.getRealSize() - matcher.getEnd());
continue;
case '+':
if (regs == null) {
if (matcher.getBegin() == -1) {
no = 0;
continue;
}
} else {
no = regs.numRegs - 1;
while (regs.beg[no] == -1 && no > 0) no--;
if (no == 0) continue;
}
break;
case '\\':
val.append(bytes, s - 1, 1);
continue;
default:
val.append(bytes, s - 2, 2);
continue;
}

if (regs != null) {
if (no >= 0) {
if (no >= regs.numRegs || regs.beg[no] == -1) continue;
val.append(srcbs.getUnsafeBytes(), srcbs.getBegin() + regs.beg[no], regs.end[no] - regs.beg[no]);
}
} else {
if (no != 0 || matcher.getBegin() == -1) continue;
val.append(srcbs.getUnsafeBytes(), srcbs.getBegin() + matcher.getBegin(), matcher.getEnd() - matcher.getBegin());
}
}

if (p < end) {
if (val == null) {
return RubyString.newString(str.getRuntime(), bs.makeShared(p - bs.getBegin(), end - p));
} else {
val.append(bytes, p, end - p);
}
}
if (val == null) return str;
return RubyString.newString(str.getRuntime(), val);
}

// MRI: ASCGET macro from rb_reg_regsub
private static final int ASCGET(boolean acompat, byte[] sBytes, int s, int e, int[] cl, Encoding strEnc) {
if (acompat) {
4 changes: 2 additions & 2 deletions core/src/main/java/org/jruby/ir/operands/Array.java
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ public class Array extends Operand {

// SSS FIXME: Do we create a special-case for zero-length arrays?
public Array() {
this(new Operand[0]);
this(EMPTY_ARRAY);
}

public Array(List<Operand> elts) {
@@ -30,7 +30,7 @@ public Array(List<Operand> elts) {
public Array(Operand[] elts) {
super(OperandType.ARRAY);

this.elts = elts == null ? new Operand[0] : elts;
this.elts = elts == null ? EMPTY_ARRAY : elts;
}

public boolean isBlank() {
7 changes: 3 additions & 4 deletions core/src/main/java/org/jruby/ir/operands/AsString.java
Original file line number Diff line number Diff line change
@@ -16,19 +16,18 @@ public class AsString extends Operand {
public AsString(Operand source) {
super(OperandType.AS_STRING);

if (source == null) source = new StringLiteral("");
this.source = source;
this.source = source == null ? StringLiteral.EMPTY_STRING : source;
}

@Override
public Object retrieve(ThreadContext context, IRubyObject self, StaticScope currScope, DynamicScope currDynScope, Object[] temp) {
return ((IRubyObject)source.retrieve(context, self, currScope, currDynScope, temp)).asString();
return ((IRubyObject) source.retrieve(context, self, currScope, currDynScope, temp)).asString();
}

@Override
public Operand getSimplifiedOperand(Map<Operand, Operand> valueMap, boolean force) {
Operand newSource = source.getSimplifiedOperand(valueMap, force);
return (newSource == source) ? this : new AsString(newSource);
return newSource == source ? this : new AsString(newSource);
}

@Override
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/ir/operands/Complex.java
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
* Represents a Complex literal.
*/
public class Complex extends ImmutableLiteral {
private ImmutableLiteral number;
private final ImmutableLiteral number;

public Complex(ImmutableLiteral number) {
super(OperandType.COMPLEX);
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/ir/operands/DynamicSymbol.java
Original file line number Diff line number Diff line change
@@ -35,7 +35,9 @@ public void addUsedVariables(List<Variable> l) {
}

public Operand cloneForInlining(CloneInfo ii) {
return new DynamicSymbol(symbolName.cloneForInlining(ii));
Operand clonedSymbolName = symbolName.cloneForInlining(ii);

return clonedSymbolName == symbolName ? this : new DynamicSymbol(clonedSymbolName);
}

@Override
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/ir/operands/StringLiteral.java
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@
* This is not like a Java string.
*/
public class StringLiteral extends Operand {
public static final StringLiteral EMPTY_STRING = new StringLiteral("");

// SSS FIXME: Pick one of bytelist or string, or add internal conversion methods to convert to the default representation

final public ByteList bytelist;
18 changes: 2 additions & 16 deletions core/src/main/java/org/jruby/ir/representations/BasicBlock.java
Original file line number Diff line number Diff line change
@@ -21,7 +21,6 @@ public class BasicBlock implements ExplicitVertexID, Comparable {
private Label label; // All basic blocks have a starting label
private List<Instr> instrs; // List of non-label instructions
private boolean isRescueEntry; // Is this basic block entry of a rescue?
private Instr[] instrsArray;

public BasicBlock(CFG cfg, Label label) {
this.label = label;
@@ -30,21 +29,19 @@ public BasicBlock(CFG cfg, Label label) {
isRescueEntry = false;

assert label != null : "label is null";
assert cfg != null : "cfg is null";

initInstrs();
}

private void initInstrs() {
instrs = new ArrayList<Instr>();
instrs = new ArrayList<>();
if (RubyInstanceConfig.IR_COMPILER_DEBUG || RubyInstanceConfig.IR_VISUALIZER) {
IRManager irManager = cfg.getScope().getManager();
InstructionsListener listener = irManager.getInstructionsListener();
if (listener != null) {
instrs = new InstructionsListenerDecorator(instrs, listener);
}
}
instrsArray = null;
}

@Override
@@ -79,7 +76,6 @@ public boolean isRescueEntry() {

public void replaceInstrs(List<Instr> instrs) {
this.instrs = instrs;
this.instrsArray = null;
}

public void addInstr(Instr i) {
@@ -94,23 +90,13 @@ public List<Instr> getInstrs() {
return instrs;
}

public int instrCount() {
return instrs.size();
}

public Instr[] getInstrsArray() {
if (instrsArray == null) instrsArray = instrs.toArray(new Instr[instrs.size()]);

return instrsArray;
}

public Instr getLastInstr() {
int n = instrs.size();
return (n == 0) ? null : instrs.get(n-1);
}

public boolean removeInstr(Instr i) {
return i == null? false : instrs.remove(i);
return i != null && instrs.remove(i);
}

public boolean isEmpty() {
6 changes: 6 additions & 0 deletions core/src/main/java/org/jruby/ir/runtime/IRRuntimeHelpers.java
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
import org.jruby.parser.StaticScope;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.FunctionalCachingCallSite;
import org.jruby.util.ByteList;
import org.jruby.util.DefinedMessage;
import org.jruby.util.RegexpOptions;
@@ -1292,4 +1293,9 @@ public static RaiseException newRequiredKeywordArgumentError(ThreadContext conte
public static void pushExitBlock(ThreadContext context, Block blk) {
context.runtime.pushExitBlock(context.runtime.newProc(Block.Type.LAMBDA, blk));
}

@JIT
public static FunctionalCachingCallSite newFunctionalCachingCallSite(String name) {
return new FunctionalCachingCallSite(name);
}
}
18 changes: 18 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -275,6 +275,24 @@ public org.objectweb.asm.Label newLabel() {
*/
public abstract void invokeOther(String name, int arity, boolean hasClosure);

/**
* Invoke a fixnum-receiving method on an object other than self.
*
* Stack required: context, self, receiver (fixnum will be handled separately)
*
* @param name name of the method to invoke
*/
public abstract void invokeOtherOneFixnum(String name, long fixnum);

/**
* Invoke a float-receiving method on an object other than self.
*
* Stack required: context, self, receiver (float will be handled separately)
*
* @param name name of the method to invoke
*/
public abstract void invokeOtherOneFloat(String name, double flote);


/**
* Invoke a method on self.
92 changes: 89 additions & 3 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -254,10 +254,8 @@ public void invokeOther(String name, int arity, boolean hasClosure) {
Label doCall = new Label();
adapter2.ifnonnull(doCall);
adapter2.pop();
adapter2.newobj(p(FunctionalCachingCallSite.class));
adapter2.dup();
adapter2.ldc(name);
adapter2.invokespecial(p(FunctionalCachingCallSite.class), "<init>", sig(void.class, String.class));
adapter2.invokestatic(p(IRRuntimeHelpers.class), "newFunctionalCachingCallSite", sig(FunctionalCachingCallSite.class, String.class));
adapter2.dup();
adapter2.putstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));

@@ -322,6 +320,94 @@ public static void buildArrayFromLocals(SkinnyMethodAdapter adapter2, int base,
}
}

public void invokeOtherOneFixnum(String name, long fixnum) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT));
String outgoingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT, long.class));

String methodName = "invokeOtherOneFixnum" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);

adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
methodName,
incomingSig,
null,
null);

// call site object field
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, methodName, ci(CachingCallSite.class), null, null).visitEnd();

// lazily construct it
adapter2.getstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));
adapter2.dup();
Label doCall = new Label();
adapter2.ifnonnull(doCall);
adapter2.pop();
adapter2.ldc(name);
adapter2.invokestatic(p(IRRuntimeHelpers.class), "newFunctionalCachingCallSite", sig(FunctionalCachingCallSite.class, String.class));
adapter2.dup();
adapter2.putstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));

// use call site to invoke
adapter2.label(doCall);
adapter2.aload(0); // context
adapter2.aload(1); // caller
adapter2.aload(2); // target
adapter2.ldc(fixnum); // fixnum

adapter2.invokevirtual(p(CachingCallSite.class), "call", outgoingSig);
adapter2.areturn();
adapter2.end();

// now call it
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
}

public void invokeOtherOneFloat(String name, double flote) {
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT));
String outgoingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT, double.class));

String methodName = "invokeOtherOneFloat" + getClassData().callSiteCount.getAndIncrement() + ":" + JavaNameMangler.mangleMethodName(name);

adapter2 = new SkinnyMethodAdapter(
adapter.getClassVisitor(),
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
methodName,
incomingSig,
null,
null);

// call site object field
adapter.getClassVisitor().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, methodName, ci(CachingCallSite.class), null, null).visitEnd();

// lazily construct it
adapter2.getstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));
adapter2.dup();
Label doCall = new Label();
adapter2.ifnonnull(doCall);
adapter2.pop();
adapter2.ldc(name);
adapter2.invokestatic(p(IRRuntimeHelpers.class), "newFunctionalCachingCallSite", sig(FunctionalCachingCallSite.class, String.class));
adapter2.dup();
adapter2.putstatic(getClassData().clsName, methodName, ci(CachingCallSite.class));

// use call site to invoke
adapter2.label(doCall);
adapter2.aload(0); // context
adapter2.aload(1); // caller
adapter2.aload(2); // target
adapter2.ldc(flote); // float

adapter2.invokevirtual(p(CachingCallSite.class), "call", outgoingSig);
adapter2.areturn();
adapter2.end();

// now call it
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
}

public void invokeSelf(String name, int arity, boolean hasClosure) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to `" + name + "' has more than " + MAX_ARGUMENTS + " arguments");

24 changes: 24 additions & 0 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter7.java
Original file line number Diff line number Diff line change
@@ -136,6 +136,30 @@ public void invokeOther(String name, int arity, boolean hasClosure) {
}
}

public void invokeOtherOneFixnum(String name, long fixnum) {
String signature = sig(IRubyObject.class, params(ThreadContext.class, IRubyObject.class, IRubyObject.class));

adapter.invokedynamic(
"fixnumOperator:" + JavaNameMangler.mangleMethodName(name),
signature,
InvokeDynamicSupport.getFixnumOperatorHandle(),
fixnum,
"",
0);
}

public void invokeOtherOneFloat(String name, double flote) {
String signature = sig(IRubyObject.class, params(ThreadContext.class, IRubyObject.class, IRubyObject.class));

adapter.invokedynamic(
"floatOperator:" + JavaNameMangler.mangleMethodName(name),
signature,
InvokeDynamicSupport.getFloatOperatorHandle(),
flote,
"",
0);
}

public void invokeSelf(String name, int arity, boolean hasClosure) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to `" + name + "' has more than " + MAX_ARGUMENTS + " arguments");

22 changes: 3 additions & 19 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@ private void logScope(IRScope scope) {

int i = 0;
for (BasicBlock bb : scope.buildLinearization()) {
for (Instr instr : bb.getInstrsArray()) {
for (Instr instr : bb.getInstrs()) {
if (i > 0) b.append("\n");

b.append(" ").append(i).append('\t').append(instr);
@@ -1306,15 +1306,7 @@ public void OneFixnumArgNoBlockCallInstr(OneFixnumArgNoBlockCallInstr oneFixnumA

visit(receiver);

String signature = sig(IRubyObject.class, params(ThreadContext.class, IRubyObject.class, IRubyObject.class));

m.adapter.invokedynamic(
"fixnumOperator:" + JavaNameMangler.mangleMethodName(name),
signature,
InvokeDynamicSupport.getFixnumOperatorHandle(),
fixnum,
"",
0);
m.invokeOtherOneFixnum(name, fixnum);

if (result != null) {
jvmStoreLocal(result);
@@ -1344,15 +1336,7 @@ public void OneFloatArgNoBlockCallInstr(OneFloatArgNoBlockCallInstr oneFloatArgN

visit(receiver);

String signature = sig(IRubyObject.class, params(ThreadContext.class, IRubyObject.class, IRubyObject.class));

m.adapter.invokedynamic(
"floatOperator:" + JavaNameMangler.mangleMethodName(name),
signature,
InvokeDynamicSupport.getFloatOperatorHandle(),
flote,
"",
0);
m.invokeOtherOneFloat(name, flote);

if (result != null) {
jvmStoreLocal(result);
57 changes: 57 additions & 0 deletions core/src/main/java/org/jruby/platform/NTPlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2014 Timur Duehr <tduehr@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby.platform;

import org.jruby.runtime.builtin.IRubyObject;

public class NTPlatform extends Platform {
private final Class systemClass;
private final Object system;

protected NTPlatform() {
Class sClass = null;
Object s = null;

try {
sClass = Class.forName("com.sun.security.auth.module.NTSystem");
s = sClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new UnsupportedOperationException(e.getMessage(), e);
}

systemClass = sClass;
system = s;
}


@Override
public long[] getGroups(IRubyObject recv) {
throw recv.getRuntime().newNotImplementedError("groups() function is unimplemented on Windows");
}
}
23 changes: 21 additions & 2 deletions core/src/main/java/org/jruby/platform/Platform.java
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
package org.jruby.platform;

import org.jruby.util.SafePropertyAccessor;
import org.jruby.runtime.builtin.IRubyObject;

import java.nio.ByteOrder;
import java.util.HashMap;
@@ -38,8 +39,8 @@
/**
* Platform specific constants.
*/
public class Platform {
private static final Platform INSTANCE = new Platform();
public abstract class Platform {
private static final Platform INSTANCE = initPlatform();
public static Platform getPlatform() {
return INSTANCE;
}
@@ -103,6 +104,7 @@ private static String initArchitecture() {
}
return arch;
}

public static final String ARCH = initArchitecture();
public static final String OS = initOperatingSystem();
public static final String JVM = getProperty("java.vm.name", "unknown");
@@ -124,6 +126,21 @@ private static String initArchitecture() {
public static final boolean IS_GCJ = JVM.equals(GCJ);
public static final boolean IS_IBM = JVM.equals(IBM);

private static Platform initPlatform(){
try {
if (IS_WINDOWS)
return new NTPlatform();

if (IS_SOLARIS)
return new SolarisPlatform();

// Punt
return new UnixPlatform();
} catch (UnsupportedOperationException e) {
return new UnsupportedPlatform();
}
}

/**
* An extension over <code>System.getProperty</code> method.
* Handles security restrictions, and returns the default
@@ -140,4 +157,6 @@ public static String getProperty(String property, String defValue) {
return defValue;
}
}

public abstract long[] getGroups(IRubyObject recv);
}
69 changes: 69 additions & 0 deletions core/src/main/java/org/jruby/platform/SolarisPlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2014 Timur Duehr <tduehr@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby.platform;

import org.jruby.runtime.builtin.IRubyObject;

import java.lang.Class;
import java.lang.reflect.Method;

public class SolarisPlatform extends Platform {
private final Class systemClass;
private final Object system;
private final Method groupsMethod;

protected SolarisPlatform() {
Class sClass = null;
Object s = null;
Method g = null;
try {
sClass = Class.forName("com.sun.security.auth.module.SolarisSystem");
s = sClass.getDeclaredConstructor().newInstance();
g = sClass.getDeclaredMethod("getGroups");
} catch (Exception e) {
throw new UnsupportedOperationException(e.getMessage(), e);
}

systemClass = sClass;
system = s;
groupsMethod = g;
}

@Override
public long[] getGroups(IRubyObject recv) {
if (groupsMethod == null)
throw recv.getRuntime().newNotImplementedError("groups() function is unimplemented on this platform");

try {
return (long[])groupsMethod.invoke(system);
} catch (Exception e) {
throw new UnsupportedOperationException("groups() function is unimplemented on this platform", e);
}
}
}
69 changes: 69 additions & 0 deletions core/src/main/java/org/jruby/platform/UnixPlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2014 Timur Duehr <tduehr@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby.platform;

import org.jruby.runtime.builtin.IRubyObject;

import java.lang.Class;
import java.lang.reflect.Method;

public class UnixPlatform extends Platform {
private final Class systemClass;
private final Object system;
private final Method groupsMethod;

protected UnixPlatform() {
Class sClass = null;
Object s = null;
Method g = null;
try {
sClass = Class.forName("com.sun.security.auth.module.UnixSystem");
s = sClass.getDeclaredConstructor().newInstance();
g = sClass.getDeclaredMethod("getGroups");
} catch (Exception e) {
throw new UnsupportedOperationException(e.getMessage(), e);
}

systemClass = sClass;
system = s;
groupsMethod = g;
}

@Override
public long[] getGroups(IRubyObject recv) {
if (groupsMethod == null)
throw recv.getRuntime().newNotImplementedError("groups() function is unimplemented on this platform");

try {
return (long[])groupsMethod.invoke(system);
} catch (Exception e) {
throw new UnsupportedOperationException("groups() function is unimplemented on this platform", e);
}
}
}
37 changes: 37 additions & 0 deletions core/src/main/java/org/jruby/platform/UnsupportedPlatform.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/***** BEGIN LICENSE BLOCK *****
* Version: EPL 1.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Eclipse Public
* License Version 1.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.eclipse.org/legal/epl-v10.html
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Copyright (C) 2014 Timur Duehr <tduehr@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the EPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the EPL, the GPL or the LGPL.
***** END LICENSE BLOCK *****/

package org.jruby.platform;

import org.jruby.runtime.builtin.IRubyObject;

public class UnsupportedPlatform extends Platform {
public long[] getGroups(IRubyObject recv) {
throw recv.getRuntime().newNotImplementedError("groups() function is unimplemented on this platform");
}
}
Original file line number Diff line number Diff line change
@@ -36,6 +36,11 @@ public class IfNode extends RubyNode {

public IfNode(RubyContext context, SourceSection sourceSection, BooleanCastNode condition, RubyNode thenBody, RubyNode elseBody) {
super(context, sourceSection);

assert condition != null;
assert thenBody != null;
assert elseBody != null;

this.condition = condition;
this.thenBody = thenBody;
this.elseBody = elseBody;
16 changes: 13 additions & 3 deletions core/src/main/java/org/jruby/truffle/nodes/core/StringNodes.java
Original file line number Diff line number Diff line change
@@ -1325,10 +1325,20 @@ public static ByteList downcase(RubyString string) {
}

public static ByteList chomp(RubyString string) {
ByteList byteListString = ByteList.create(string.toString().trim());
byteListString.setEncoding(string.getBytes().getEncoding());
String javaString = string.toString();
if (javaString.endsWith("\r")) {
String newString = javaString.substring(0, javaString.length()-1);
ByteList byteListString = ByteList.create(newString);
byteListString.setEncoding(string.getBytes().getEncoding());

return byteListString;
} else {
ByteList byteListString = ByteList.create(javaString.trim());
byteListString.setEncoding(string.getBytes().getEncoding());

return byteListString;
}

return byteListString;
}

public static ByteList chompWithString(RubyString string, RubyString stringToChomp) {
Original file line number Diff line number Diff line change
@@ -12,28 +12,53 @@
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import com.oracle.truffle.api.frame.FrameSlot;
import org.jruby.ast.LocalAsgnNode;
import org.jruby.ast.RequiredKeywordArgumentValueNode;
import org.jruby.ast.StarNode;
import org.jruby.ast.types.INameNode;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.truffle.nodes.ReadNode;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.cast.ArrayCastNodeFactory;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.control.IfNode;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.ArrayIndexNodeFactory;
import org.jruby.truffle.nodes.core.ArraySliceNodeFactory;
import org.jruby.truffle.nodes.literal.ArrayLiteralNode;
import org.jruby.truffle.nodes.literal.NilLiteralNode;
import org.jruby.truffle.nodes.methods.arguments.*;
import org.jruby.truffle.nodes.methods.locals.ReadLocalVariableNodeFactory;
import org.jruby.truffle.nodes.methods.locals.WriteLocalVariableNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.omg.Dynamic.Parameter;

import java.util.*;

public class LoadArgumentsTranslator extends Translator {

private static class ArraySlot {

private FrameSlot arraySlot;
private int previousIndex;

public ArraySlot(FrameSlot arraySlot, int previousIndex) {
this.arraySlot = arraySlot;
this.previousIndex = previousIndex;
}

public FrameSlot getArraySlot() {
return arraySlot;
}

public int getPreviousIndex() {
return previousIndex;
}
}

private final boolean isBlock;
private final BodyTranslator methodBodyTranslator;
private final Deque<FrameSlot> arraySlotStack = new ArrayDeque<>();
private final Deque<ArraySlot> arraySlotStack = new ArrayDeque<>();

private enum State {
PRE,
@@ -43,6 +68,7 @@ private enum State {

private int required;
private int index;
private int indexFromEnd = 1;
private State state;
private boolean hasKeywordArguments;
private List<String> excludedKeywords = new ArrayList<>();
@@ -161,7 +187,7 @@ public RubyNode visitKeywordArgNode(org.jruby.ast.KeywordArgNode node) {
defaultValue = dAsgnNode.getValueNode().accept(this);
}
} else {
throw new UnsupportedOperationException();
throw new UnsupportedOperationException("unsupported keyword arg " + node);
}

excludedKeywords.add(name);
@@ -243,30 +269,33 @@ private RubyNode translateLocalAssignment(ISourcePosition sourcePosition, String

final RubyNode readNode;

if (valueNode instanceof org.jruby.ast.NilImplicitNode) {
// Multiple assignment
if (indexFromEnd == 1) {
if (valueNode instanceof org.jruby.ast.NilImplicitNode) {
// Multiple assignment

if (useArray()) {
readNode = ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection));
if (useArray()) {
readNode = ArrayIndexNodeFactory.create(context, sourceSection, index, loadArray(sourceSection));
} else {
readNode = readArgument(sourceSection);
}
} else {
readNode = readArgument(sourceSection);
}
} else {
// Optional argument
final RubyNode defaultValue = valueNode.accept(this);
// Optional argument
final RubyNode defaultValue = valueNode.accept(this);

int minimum = index + 1 + argsNode.getPostCount();
int minimum = index + 1 + argsNode.getPostCount();

if (argsNode.hasKwargs()) {
minimum += 1;
}
if (argsNode.hasKwargs()) {
minimum += 1;
}

readNode = new ReadOptionalArgumentNode(context, sourceSection, index, minimum, defaultValue);
readNode = new ReadOptionalArgumentNode(context, sourceSection, index, minimum, defaultValue);
}
} else {
readNode = ArraySliceNodeFactory.create(context, sourceSection, index, indexFromEnd, loadArray(sourceSection));
}

final FrameSlot slot = methodBodyTranslator.getEnvironment().getFrameDescriptor().findFrameSlot(name);
final FrameSlot slot = methodBodyTranslator.getEnvironment().getFrameDescriptor().findOrAddFrameSlot(name);
return WriteLocalVariableNodeFactory.create(context, sourceSection, slot, readNode);

}

@Override
@@ -298,9 +327,29 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgn19Node node) {

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

for (int n = 0; n < childNodes.size(); n++) {
index = n;
notNilSequence.add(childNodes.get(n).accept(this));
if (node.getPre() != null) {
index = 0;
for (org.jruby.ast.Node child : node.getPre().childNodes()) {
notNilSequence.add(child.accept(this));
index++;
}
}

if (node.getRest() != null) {
index = node.getPreCount();
indexFromEnd = -node.getPostCount();
notNilSequence.add(node.getRest().accept(this));
indexFromEnd = 1;
}

if (node.getPost() != null) {
index = -1;
final List<org.jruby.ast.Node> children = new ArrayList<>(node.getPost().childNodes());
Collections.reverse(children);
for (org.jruby.ast.Node child : children) {
notNilSequence.add(child.accept(this));
index--;
}
}

final RubyNode notNil = SequenceNode.sequence(context, sourceSection, notNilSequence);
@@ -309,6 +358,35 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgn19Node node) {

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

final ParameterCollector parametersToClearCollector = new ParameterCollector();

if (node.getPre() != null) {
for (org.jruby.ast.Node child : node.getPre().childNodes()) {
child.accept(parametersToClearCollector);
}
}

if (node.getRest() != null) {
if (node.getRest() instanceof INameNode) {
final String name = ((INameNode) node.getRest()).getName();
nilSequence.add(((ReadNode) methodBodyTranslator.getEnvironment().findOrAddLocalVarNodeDangerous(name, sourceSection)).makeWriteNode(new ArrayLiteralNode.UninitialisedArrayLiteralNode(context, sourceSection, new RubyNode[]{})));
} else if (node.getRest() instanceof StarNode) {
// Don't think we need to do anything
} else {
throw new UnsupportedOperationException("unsupported rest node " + node.getRest());
}
}

if (node.getPost() != null) {
for (org.jruby.ast.Node child : node.getPost().childNodes()) {
child.accept(parametersToClearCollector);
}
}

for (String parameterToClear : parametersToClearCollector.getParameters()) {
nilSequence.add(((ReadNode) methodBodyTranslator.getEnvironment().findOrAddLocalVarNodeDangerous(parameterToClear, sourceSection)).makeWriteNode(new NilLiteralNode(context, sourceSection)));
}

if (!childNodes.isEmpty()) {
// We haven't pushed a new array slot, so this will read the value which we couldn't convert to an array into the first destructured argument
index = arrayIndex;
@@ -325,7 +403,7 @@ public RubyNode visitMultipleAsgnNode(org.jruby.ast.MultipleAsgn19Node node) {
BooleanCastNodeFactory.create(context, sourceSection,
new IsNilNode(context, sourceSection, ReadLocalVariableNodeFactory.create(context, sourceSection, arraySlot))),
nil,
notNil));
notNil == null ? new NilLiteralNode(context, sourceSection) : notNil));
}

@Override
@@ -335,19 +413,19 @@ protected RubyNode defaultVisit(org.jruby.ast.Node node) {
}

public void pushArraySlot(FrameSlot slot) {
arraySlotStack.push(slot);
arraySlotStack.push(new ArraySlot(slot, index));
}

public void popArraySlot(FrameSlot slot) {
arraySlotStack.pop();
index = arraySlotStack.pop().getPreviousIndex();
}

protected boolean useArray() {
return !arraySlotStack.isEmpty();
}

protected RubyNode loadArray(SourceSection sourceSection) {
return ReadLocalVariableNodeFactory.create(context, sourceSection, arraySlotStack.peek());
return ReadLocalVariableNodeFactory.create(context, sourceSection, arraySlotStack.peek().getArraySlot());
}

@Override
Original file line number Diff line number Diff line change
@@ -176,6 +176,11 @@ public MethodDefinitionNode compileFunctionNode(SourceSection sourceSection, Str
NodeUtil.printCompactTree(System.err, rootNode);
}

if (PRINT_FULL_AST_METHOD_NAMES.contains(methodName)) {
System.err.println(methodName);
NodeUtil.printTree(System.err, rootNode);
}

if (isBlock) {
final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
final CallTarget callTargetForMethods = withoutBlockDestructureSemantics(callTarget);
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
public abstract class Translator extends org.jruby.ast.visitor.AbstractNodeVisitor<RubyNode> {

public static final Set<String> PRINT_AST_METHOD_NAMES = new HashSet<>(Arrays.asList(Options.TRUFFLE_TRANSLATOR_PRINT_AST.load().split(",")));
public static final Set<String> PRINT_FULL_AST_METHOD_NAMES = new HashSet<>(Arrays.asList(Options.TRUFFLE_TRANSLATOR_PRINT_FULL_AST.load().split(",")));
public static final Set<String> PRINT_PARSE_TREE_METHOD_NAMES = new HashSet<>(Arrays.asList(Options.TRUFFLE_TRANSLATOR_PRINT_PARSE_TREE.load().split(",")));

protected final RubyNode currentNode;
Original file line number Diff line number Diff line change
@@ -119,6 +119,17 @@ public SharedMethodInfo findMethodForLocalVar(String name) {
return null;
}

public RubyNode findOrAddLocalVarNodeDangerous(String name, SourceSection sourceSection) {
RubyNode localVar = findLocalVarNode(name, sourceSection);

if (localVar == null) {
declareVar(name);
localVar = findLocalVarNode(name, sourceSection);
}

return localVar;
}

public RubyNode findLocalVarNode(String name, SourceSection sourceSection) {
TranslatorEnvironment current = this;
int level = -1;
1 change: 1 addition & 0 deletions core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -153,6 +153,7 @@ public class Options {
public static final Option<Boolean> TRUFFLE_DISPATCH_METHODMISSING_ALWAYS_CLONED = bool(TRUFFLE, "truffle.call.method_missing_always_cloned", true, "Always clone #method_missing call targets.");
public static final Option<Boolean> TRUFFLE_DISPATCH_METHODMISSING_ALWAYS_INLINED = bool(TRUFFLE, "truffle.call.method_missing_always_inlined", true, "Always inline #method_missing call targets.");
public static final Option<String> TRUFFLE_TRANSLATOR_PRINT_AST = string(TRUFFLE, "truffle.translator.print_asts", "", "Comma delimited list of method names to print the AST of after translation.");
public static final Option<String> TRUFFLE_TRANSLATOR_PRINT_FULL_AST = string(TRUFFLE, "truffle.translator.print_full_asts", "", "Comma delimited list of method names to print the full AST of after translation.");
public static final Option<String> TRUFFLE_TRANSLATOR_PRINT_PARSE_TREE = string(TRUFFLE, "truffle.translator.print_parse_trees", "", "Comma delimited list of method names to print the JRuby parse tree of before translation.");

public static final Option<Boolean> NATIVE_ENABLED = bool(NATIVE, "native.enabled", true, "Enable/disable native code, including POSIX features and C exts.");
4 changes: 0 additions & 4 deletions spec/truffle/tags/language/method_tags.txt
Original file line number Diff line number Diff line change
@@ -17,7 +17,3 @@ fails:"A method assigns local variables from method parameters for definition \n
fails:"A method assigns local variables from method parameters for definition \n def m(a: def m(a: 1) a end, b:)\n [a, b]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m(a, b=1, *c, (*d, (e)), f: 2, g:, h:, **k, &l)\n [a, b, c, d, e, f, g, h, k, l]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m a, b=1, *c, d, e:, f: 2, g:, **k, &l\n [a, b, c, d, e, f, g, k, l]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m(a, (b, c)) [a, b, c] end"
fails:"A method assigns local variables from method parameters for definition \n def m((a, b), (c, d))\n [a, b, c, d]\n end"
fails:"A method assigns local variables from method parameters for definition \n def m(a=1, (b, c)) [a, b, c] end"
fails:"A method assigns local variables from method parameters for definition \n def m(a=1, (b, c), (d, e)) [a, b, c, d, e] end"
4 changes: 0 additions & 4 deletions test/jruby/test_load.rb
Original file line number Diff line number Diff line change
@@ -183,10 +183,6 @@ def test_require_with_non_existent_jar_3
$:.shift
end

def test_load_rb_if_jar_doesnt_exist
require 'test/jruby/fake.jar' # test/fake.jar does not exist, but test/fake.jar.rb does.
end

def test_overriding_require_shouldnt_cause_problems
eval(<<DEPS, binding, "deps")
class ::Object

0 comments on commit f3e944c

Please sign in to comment.