Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add file, line to calls in JIT, for logging and debugging.
Browse files Browse the repository at this point in the history
headius committed Jun 10, 2016
1 parent 23a92fa commit a83428f
Showing 5 changed files with 407 additions and 58 deletions.
26 changes: 18 additions & 8 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter.java
Original file line number Diff line number Diff line change
@@ -366,7 +366,7 @@ public org.objectweb.asm.Label newLabel() {
* @param arity arity of the call
* @param hasClosure whether a closure will be on the stack for passing
*/
public abstract void invokeOther(String name, int arity, boolean hasClosure, boolean isPotentiallyRefined);
public abstract void invokeOther(String file, int line, String name, int arity, boolean hasClosure, boolean isPotentiallyRefined);

/**
* Invoke the array dereferencing method ([]) on an object other than self.
@@ -384,7 +384,7 @@ public org.objectweb.asm.Label newLabel() {
*
* @param name name of the method to invoke
*/
public abstract void invokeOtherOneFixnum(String name, long fixnum);
public abstract void invokeOtherOneFixnum(String file, int line, String name, long fixnum);

/**
* Invoke a float-receiving method on an object other than self.
@@ -393,68 +393,78 @@ public org.objectweb.asm.Label newLabel() {
*
* @param name name of the method to invoke
*/
public abstract void invokeOtherOneFloat(String name, double flote);
public abstract void invokeOtherOneFloat(String file, int line, String name, double flote);


/**
* Invoke a method on self.
*
* Stack required: context, caller, self, all arguments, optional block
*
* @param file the filename of the script making this call
* @param line the line number where this call appears
* @param name name of the method to invoke
* @param arity arity of the call
* @param hasClosure whether a closure will be on the stack for passing
* @param callType
*/
public abstract void invokeSelf(String name, int arity, boolean hasClosure, CallType callType, boolean isPotentiallyRefined);
public abstract void invokeSelf(String file, int line, String name, int arity, boolean hasClosure, CallType callType, boolean isPotentiallyRefined);

/**
* Invoke a superclass method from an instance context.
*
* Stack required: context, caller, self, start class, arguments[, block]
*
* @param file the filename of the script making this call
* @param line the line number where this call appears
* @param name name of the method to invoke
* @param arity arity of the arguments on the stack
* @param hasClosure whether a block is passed
* @param splatmap a map of arguments to be splatted back into arg list
*/
public abstract void invokeInstanceSuper(String name, int arity, boolean hasClosure, boolean[] splatmap);
public abstract void invokeInstanceSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap);

/**
* Invoke a superclass method from a class context.
*
* Stack required: context, caller, self, start class, arguments[, block]
*
* @param file the filename of the script making this call
* @param line the line number where this call appears
* @param name name of the method to invoke
* @param arity arity of the arguments on the stack
* @param hasClosure whether a block is passed
* @param splatmap a map of arguments to be splatted back into arg list
*/
public abstract void invokeClassSuper(String name, int arity, boolean hasClosure, boolean[] splatmap);
public abstract void invokeClassSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap);

/**
* Invoke a superclass method from an unresolved context.
*
* Stack required: context, caller, self, arguments[, block]
*
* @param file the filename of the script making this call
* @param line the line number where this call appears
* @param name name of the method to invoke
* @param arity arity of the arguments on the stack
* @param hasClosure whether a block is passed
* @param splatmap a map of arguments to be splatted back into arg list
*/
public abstract void invokeUnresolvedSuper(String name, int arity, boolean hasClosure, boolean[] splatmap);
public abstract void invokeUnresolvedSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap);

/**
* Invoke a superclass method from a zsuper in a block.
*
* Stack required: context, caller, self, arguments[, block]
*
* @param file the filename of the script making this call
* @param line the line number where this call appears
* @param name name of the method to invoke
* @param arity arity of the arguments on the stack
* @param hasClosure whether a block is passed
* @param splatmap a map of arguments to be splatted back into arg list
*/
public abstract void invokeZSuper(String name, int arity, boolean hasClosure, boolean[] splatmap);
public abstract void invokeZSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap);

/**
* Lookup a constant from current context.
44 changes: 26 additions & 18 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter6.java
Original file line number Diff line number Diff line change
@@ -385,8 +385,8 @@ public void run() {
});
}

public void invokeOther(String name, int arity, boolean hasClosure, boolean isPotentiallyRefined) {
invoke(name, arity, hasClosure, CallType.NORMAL, isPotentiallyRefined);
public void invokeOther(String file, int line, String name, int arity, boolean hasClosure, boolean isPotentiallyRefined) {
invoke(file, line, name, arity, hasClosure, CallType.NORMAL, isPotentiallyRefined);
}

public void invokeArrayDeref() {
@@ -413,7 +413,7 @@ public void invokeArrayDeref() {
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
}

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

SkinnyMethodAdapter adapter2;
@@ -468,6 +468,8 @@ public void invoke(String name, int arity, boolean hasClosure, CallType callType
null,
null);

adapter2.line(lineNumber);

cacheCallSite(adapter2, getClassData().clsName, methodName, name, callType, isPotentiallyRefined);

// use call site to invoke
@@ -530,10 +532,10 @@ public static void buildArrayFromLocals(SkinnyMethodAdapter adapter2, int base,
}
}

public void invokeOtherOneFixnum(String name, long fixnum) {
public void invokeOtherOneFixnum(String file, int line, String name, long fixnum) {
if (!MethodIndex.hasFastFixnumOps(name)) {
pushFixnum(fixnum);
invokeOther(name, 1, false, false);
invokeOther(file, line, name, 1, false, false);
}
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT));
@@ -549,6 +551,8 @@ public void invokeOtherOneFixnum(String name, long fixnum) {
null,
null);

adapter2.line(line);

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

@@ -578,10 +582,10 @@ public void invokeOtherOneFixnum(String name, long fixnum) {
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
}

public void invokeOtherOneFloat(String name, double flote) {
public void invokeOtherOneFloat(String file, int line, String name, double flote) {
if (!MethodIndex.hasFastFloatOps(name)) {
pushFloat(flote);
invokeOther(name, 1, false, false);
invokeOther(file, line, name, 1, false, false);
}
SkinnyMethodAdapter adapter2;
String incomingSig = sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT));
@@ -597,6 +601,8 @@ public void invokeOtherOneFloat(String name, double flote) {
null,
null);

adapter2.line(line);

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

@@ -626,37 +632,37 @@ public void invokeOtherOneFloat(String name, double flote) {
adapter.invokestatic(getClassData().clsName, methodName, incomingSig);
}

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

invoke(name, arity, hasClosure, callType, isPotentiallyRefined);
invoke(file, line, name, arity, hasClosure, callType, isPotentiallyRefined);
}

public void invokeInstanceSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeInstanceSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to instance super has more than " + MAX_ARGUMENTS + " arguments");

performSuper(name, arity, hasClosure, splatmap, "instanceSuper", "instanceSuperSplatArgs", false);
performSuper(file, line, name, arity, hasClosure, splatmap, "instanceSuper", "instanceSuperSplatArgs", false);
}

public void invokeClassSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeClassSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to class super has more than " + MAX_ARGUMENTS + " arguments");

performSuper(name, arity, hasClosure, splatmap, "classSuper", "classSuperSplatArgs", false);
performSuper(file, line, name, arity, hasClosure, splatmap, "classSuper", "classSuperSplatArgs", false);
}

public void invokeUnresolvedSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeUnresolvedSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to unresolved super has more than " + MAX_ARGUMENTS + " arguments");

performSuper(name, arity, hasClosure, splatmap, "unresolvedSuper", "unresolvedSuperSplatArgs", true);
performSuper(file, line, name, arity, hasClosure, splatmap, "unresolvedSuper", "unresolvedSuperSplatArgs", true);
}

public void invokeZSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeZSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to zsuper has more than " + MAX_ARGUMENTS + " arguments");

performSuper(name, arity, hasClosure, splatmap, "zSuper", "zSuperSplatArgs", true);
performSuper(file, line, name, arity, hasClosure, splatmap, "zSuper", "zSuperSplatArgs", true);
}

private void performSuper(String name, int arity, boolean hasClosure, boolean[] splatmap, String superHelper, String splatHelper, boolean unresolved) {
private void performSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap, String superHelper, String splatHelper, boolean unresolved) {
SkinnyMethodAdapter adapter2;
String incomingSig;
String outgoingSig;
@@ -692,6 +698,8 @@ private void performSuper(String name, int arity, boolean hasClosure, boolean[]
null,
null);

adapter2.line(line);

// CON FIXME: make these offsets programmatically determined
adapter2.aload(0);
adapter2.aload(2);
20 changes: 10 additions & 10 deletions core/src/main/java/org/jruby/ir/targets/IRBytecodeAdapter7.java
Original file line number Diff line number Diff line change
@@ -124,10 +124,10 @@ public void pushEncoding(Encoding encoding) {
adapter.invokedynamic("encoding", sig(RubyEncoding.class, ThreadContext.class), Bootstrap.contextValueString(), new String(encoding.getName()));
}

public void invokeOther(String name, int arity, boolean hasClosure, boolean isPotentiallyRefined) {
public void invokeOther(String file, int line, String name, int arity, boolean hasClosure, boolean isPotentiallyRefined) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to `" + name + "' has more than " + MAX_ARGUMENTS + " arguments");
if (isPotentiallyRefined) {
super.invokeOther(name, arity, hasClosure, isPotentiallyRefined);
super.invokeOther(file, line, name, arity, hasClosure, isPotentiallyRefined);
return;
}

@@ -151,7 +151,7 @@ public void invokeArrayDeref() {
adapter.invokedynamic("aref", sig(JVM.OBJECT, params(ThreadContext.class, JVM.OBJECT, JVM.OBJECT, JVM.OBJECT, 1)), ArrayDerefInvokeSite.BOOTSTRAP);
}

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

adapter.invokedynamic(
@@ -163,7 +163,7 @@ public void invokeOtherOneFixnum(String name, long fixnum) {
0);
}

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

adapter.invokedynamic(
@@ -175,10 +175,10 @@ public void invokeOtherOneFloat(String name, double flote) {
0);
}

public void invokeSelf(String name, int arity, boolean hasClosure, CallType callType, boolean isPotentiallyRefined) {
public void invokeSelf(String file, int line, String name, int arity, boolean hasClosure, CallType callType, boolean isPotentiallyRefined) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to `" + name + "' has more than " + MAX_ARGUMENTS + " arguments");
if (isPotentiallyRefined) {
super.invokeSelf(name, arity, hasClosure, callType, isPotentiallyRefined);
super.invokeSelf(file, line, name, arity, hasClosure, callType, isPotentiallyRefined);
return;
}

@@ -198,7 +198,7 @@ public void invokeSelf(String name, int arity, boolean hasClosure, CallType call
}
}

public void invokeInstanceSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeInstanceSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to instance super has more than " + MAX_ARGUMENTS + " arguments");

String splatmapString = IRRuntimeHelpers.encodeSplatmap(splatmap);
@@ -209,7 +209,7 @@ public void invokeInstanceSuper(String name, int arity, boolean hasClosure, bool
}
}

public void invokeClassSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeClassSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to class super has more than " + MAX_ARGUMENTS + " arguments");

String splatmapString = IRRuntimeHelpers.encodeSplatmap(splatmap);
@@ -220,7 +220,7 @@ public void invokeClassSuper(String name, int arity, boolean hasClosure, boolean
}
}

public void invokeUnresolvedSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeUnresolvedSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to unresolved super has more than " + MAX_ARGUMENTS + " arguments");

String splatmapString = IRRuntimeHelpers.encodeSplatmap(splatmap);
@@ -231,7 +231,7 @@ public void invokeUnresolvedSuper(String name, int arity, boolean hasClosure, bo
}
}

public void invokeZSuper(String name, int arity, boolean hasClosure, boolean[] splatmap) {
public void invokeZSuper(String file, int line, String name, int arity, boolean hasClosure, boolean[] splatmap) {
if (arity > MAX_ARGUMENTS) throw new NotCompilableException("call to zsuper has more than " + MAX_ARGUMENTS + " arguments");

String splatmapString = IRRuntimeHelpers.encodeSplatmap(splatmap);
53 changes: 31 additions & 22 deletions core/src/main/java/org/jruby/ir/targets/JVMVisitor.java
Original file line number Diff line number Diff line change
@@ -79,16 +79,22 @@ public JVMVisitor() {
}

public Class compile(IRScope scope, ClassDefiningClassLoader jrubyClassLoader) {
file = scope.getFileName();
lastLine = -1;
JVMVisitorMethodContext context = new JVMVisitorMethodContext();
return defineFromBytecode(scope, compileToBytecode(scope, context), jrubyClassLoader);
}

public byte[] compileToBytecode(IRScope scope, JVMVisitorMethodContext context) {
file = scope.getFileName();
lastLine = -1;
codegenScope(scope, context);
return code();
}

public Class defineFromBytecode(IRScope scope, byte[] code, ClassDefiningClassLoader jrubyClassLoader) {
file = scope.getFileName();
lastLine = -1;
Class result = jrubyClassLoader.defineClass(c(JVM.scriptToClass(scope.getFileName())), code);

for (Map.Entry<String, IRScope> entry : scopeMap.entrySet()) {
@@ -106,7 +112,7 @@ public byte[] code() {
return jvm.code();
}

public void codegenScope(IRScope scope, JVMVisitorMethodContext context) {
protected void codegenScope(IRScope scope, JVMVisitorMethodContext context) {
if (scope instanceof IRScriptBody) {
codegenScriptBody((IRScriptBody)scope);
} else if (scope instanceof IRMethod) {
@@ -120,11 +126,11 @@ public void codegenScope(IRScope scope, JVMVisitorMethodContext context) {
}
}

public void codegenScriptBody(IRScriptBody script) {
protected void codegenScriptBody(IRScriptBody script) {
emitScriptBody(script);
}

public void emitScope(IRScope scope, String name, Signature signature, boolean specificArity, boolean print) {
protected void emitScope(IRScope scope, String name, Signature signature, boolean specificArity, boolean print) {
BasicBlock[] bbs = scope.prepareForCompilation();

if (print && Options.IR_PRINT.load()) {
@@ -236,7 +242,7 @@ public void emitScope(IRScope scope, String name, Signature signature, boolean s
jvm.popmethod();
}

public static final Signature signatureFor(IRScope method, boolean aritySplit) {
protected static final Signature signatureFor(IRScope method, boolean aritySplit) {
if (aritySplit) {
StaticScope argScope = method.getStaticScope();
if (argScope.isArgumentScope() &&
@@ -259,7 +265,7 @@ public static final Signature signatureFor(IRScope method, boolean aritySplit) {
return METHOD_SIGNATURE_BASE.insertArgs(3, new String[]{"args"}, IRubyObject[].class);
}

public void emitScriptBody(IRScriptBody script) {
protected void emitScriptBody(IRScriptBody script) {
// Note: no index attached because there should be at most one script body per .class
String name = JavaNameMangler.encodeScopeForBacktrace(script);
String clsName = jvm.scriptToClass(script.getFileName());
@@ -271,13 +277,13 @@ public void emitScriptBody(IRScriptBody script) {
jvm.popclass();
}

public void emitMethod(IRMethod method, JVMVisitorMethodContext context) {
protected void emitMethod(IRMethod method, JVMVisitorMethodContext context) {
String name = JavaNameMangler.encodeScopeForBacktrace(method) + '$' + methodIndex++;

emitWithSignatures(method, context, name);
}

public void emitMethodJIT(IRMethod method, JVMVisitorMethodContext context) {
protected void emitMethodJIT(IRMethod method, JVMVisitorMethodContext context) {
String clsName = jvm.scriptToClass(method.getFileName());
String name = JavaNameMangler.encodeScopeForBacktrace(method) + '$' + methodIndex++;
jvm.pushscript(clsName, method.getFileName());
@@ -288,7 +294,7 @@ public void emitMethodJIT(IRMethod method, JVMVisitorMethodContext context) {
jvm.popclass();
}

public void emitBlockJIT(IRClosure closure, JVMVisitorMethodContext context) {
protected void emitBlockJIT(IRClosure closure, JVMVisitorMethodContext context) {
String clsName = jvm.scriptToClass(closure.getFileName());
String name = JavaNameMangler.encodeScopeForBacktrace(closure) + '$' + methodIndex++;
jvm.pushscript(clsName, closure.getFileName());
@@ -315,7 +321,7 @@ private void emitWithSignatures(IRMethod method, JVMVisitorMethodContext context
}
}

public Handle emitModuleBodyJIT(IRModuleBody method) {
protected Handle emitModuleBodyJIT(IRModuleBody method) {
String name = JavaNameMangler.encodeScopeForBacktrace(method) + '$' + methodIndex++;

String clsName = jvm.scriptToClass(method.getFileName());
@@ -339,7 +345,7 @@ private void emitClosures(IRScope s, boolean print) {
}
}

public Handle emitClosure(IRClosure closure, boolean print) {
protected Handle emitClosure(IRClosure closure, boolean print) {
/* Compile the closure like a method */
String name = JavaNameMangler.encodeScopeForBacktrace(closure) + '$' + methodIndex++;

@@ -348,7 +354,7 @@ public Handle emitClosure(IRClosure closure, boolean print) {
return new Handle(Opcodes.H_INVOKESTATIC, jvm.clsData().clsName, name, sig(CLOSURE_SIGNATURE.type().returnType(), CLOSURE_SIGNATURE.type().parameterArray()));
}

public Handle emitModuleBody(IRModuleBody method) {
protected Handle emitModuleBody(IRModuleBody method) {
String name = JavaNameMangler.encodeScopeForBacktrace(method) + '$' + methodIndex++;

Signature signature = signatureFor(method, false);
@@ -815,7 +821,7 @@ public void BacktickInstr(BacktickInstr instr) {
jvmAdapter().invokeinterface(p(IRubyObject.class), "setFrozen", sig(void.class, boolean.class));

// invoke the "`" method on self
jvmMethod().invokeSelf("`", 1, false, CallType.FUNCTIONAL, false);
jvmMethod().invokeSelf(file, lastLine, "`", 1, false, CallType.FUNCTIONAL, false);
jvmStoreLocal(instr.getResult());
}

@@ -1035,13 +1041,13 @@ private void compileCallCommon(IRBytecodeAdapter m, String name, Operand[] args,

switch (callType) {
case FUNCTIONAL:
m.invokeSelf(name, arity, hasClosure, CallType.FUNCTIONAL, isPotentiallyRefined);
m.invokeSelf(file, lastLine, name, arity, hasClosure, CallType.FUNCTIONAL, isPotentiallyRefined);
break;
case VARIABLE:
m.invokeSelf(name, arity, hasClosure, CallType.VARIABLE, isPotentiallyRefined);
m.invokeSelf(file, lastLine, name, arity, hasClosure, CallType.VARIABLE, isPotentiallyRefined);
break;
case NORMAL:
m.invokeOther(name, arity, hasClosure, isPotentiallyRefined);
m.invokeOther(file, lastLine, name, arity, hasClosure, isPotentiallyRefined);
break;
}

@@ -1376,16 +1382,16 @@ private void superCommon(String name, CallInstr instr, Operand[] args, Operand d

switch (operation) {
case INSTANCE_SUPER:
m.invokeInstanceSuper(name, args.length, hasClosure, splatMap);
m.invokeInstanceSuper(file, lastLine, name, args.length, hasClosure, splatMap);
break;
case CLASS_SUPER:
m.invokeClassSuper(name, args.length, hasClosure, splatMap);
m.invokeClassSuper(file, lastLine, name, args.length, hasClosure, splatMap);
break;
case UNRESOLVED_SUPER:
m.invokeUnresolvedSuper(name, args.length, hasClosure, splatMap);
m.invokeUnresolvedSuper(file, lastLine, name, args.length, hasClosure, splatMap);
break;
case ZSUPER:
m.invokeZSuper(name, args.length, hasClosure, splatMap);
m.invokeZSuper(file, lastLine, name, args.length, hasClosure, splatMap);
break;
default:
throw new NotCompilableException("unknown super type " + operation + " in " + instr);
@@ -1417,7 +1423,8 @@ public void LexicalSearchConstInstr(LexicalSearchConstInstr lexicalsearchconstin
public void LineNumberInstr(LineNumberInstr linenumberinstr) {
if (DEBUG) return; // debug mode uses IPC for line numbers

jvmAdapter().line(linenumberinstr.getLineNumber() + 1);
lastLine = linenumberinstr.getLineNumber() + 1;
jvmAdapter().line(lastLine);
}

@Override
@@ -1519,7 +1526,7 @@ public void oneFixnumArgNoBlockCallInstr(OneFixnumArgNoBlockCallInstr oneFixnumA

visit(receiver);

m.invokeOtherOneFixnum(name, fixnum);
m.invokeOtherOneFixnum(file, lastLine, name, fixnum);

if (result != null) {
jvmStoreLocal(result);
@@ -1548,7 +1555,7 @@ public void oneFloatArgNoBlockCallInstr(OneFloatArgNoBlockCallInstr oneFloatArgN

visit(receiver);

m.invokeOtherOneFloat(name, flote);
m.invokeOtherOneFloat(file, lastLine, name, flote);

if (result != null) {
jvmStoreLocal(result);
@@ -2532,4 +2539,6 @@ private IRBytecodeAdapter jvmMethod() {
private JVM jvm;
private int methodIndex;
private Map<String, IRScope> scopeMap;
private String file;
private int lastLine = -1;
}
322 changes: 322 additions & 0 deletions core/src/main/java/org/jruby/specialized/RubyArrayTwoObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
package org.jruby.specialized;

import org.jcodings.specific.USASCIIEncoding;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.RubyString;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.Block;
import org.jruby.runtime.Constants;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.io.EncodingUtils;

import static org.jruby.RubyEnumerator.enumeratorizeWithSize;
import static org.jruby.runtime.Helpers.arrayOf;

/**
* Created by headius on 5/28/16.
*/
public class RubyArrayTwoObject extends RubyArraySpecialized {
private IRubyObject value;

public RubyArrayTwoObject(Ruby runtime, IRubyObject value) {
// packed arrays are omitted from ObjectSpace
super(runtime, false);
this.value = value;
this.realLength = 1;
setFlag(Constants.PACKED_ARRAY_F, true);
}

public RubyArrayTwoObject(RubyClass otherClass, IRubyObject value) {
super(otherClass, false);
this.value = value;
this.realLength = 1;
setFlag(Constants.PACKED_ARRAY_F, true);
}

RubyArrayTwoObject(RubyArrayTwoObject other) {
this(other.getMetaClass(), other.value);
}

RubyArrayTwoObject(RubyClass metaClass, RubyArrayTwoObject other) {
this(metaClass, other.value);
}

@Override
public final IRubyObject eltInternal(int index) {
if (!packed()) return super.eltInternal(index);
else if (index == 0) return value;
throw new ArrayIndexOutOfBoundsException(index);
}

@Override
public final IRubyObject eltInternalSet(int index, IRubyObject value) {
if (!packed()) return super.eltInternalSet(index, value);
if (index == 0) return this.value = value;
throw new ArrayIndexOutOfBoundsException(index);
}

@Override
protected void unpack() {
if (!packed()) return;
// CON: I believe most of the time we'll fail because we need to grow, so give a bit of extra room
IRubyObject nil = getRuntime().getNil();
values = new IRubyObject[]{nil, value, nil};
value = nil;
begin = 1;
realLength = 1;
setFlag(Constants.PACKED_ARRAY_F, false);
}

@Override
public RubyArray aryDup() {
if (!packed()) return super.aryDup();
return new RubyArrayTwoObject(getRuntime().getArray(), this);
}

@Override
public IRubyObject rb_clear() {
if (!packed()) return super.rb_clear();

modifyCheck();

// fail packing, but defer [] creation in case it is never needed
value = null;
values = IRubyObject.NULL_ARRAY;
realLength = 0;
setFlag(Constants.PACKED_ARRAY_F, false);

return this;
}

@Override
public IRubyObject collect(ThreadContext context, Block block) {
if (!packed()) return super.collect(context, block);

return new RubyArrayTwoObject(getRuntime(), block.yield(context, value));
}

@Override
public void copyInto(IRubyObject[] target, int start) {
if (!packed()) {
super.copyInto(target, start);
return;
}
target[start] = value;
}

@Override
public void copyInto(IRubyObject[] target, int start, int len) {
if (!packed()) {
super.copyInto(target, start);
return;
}
if (len != 1) {
unpack();
super.copyInto(target, start);
return;
}
target[start] = value;
}

@Override
public IRubyObject dup() {
if (!packed()) return super.dup();
return new RubyArrayTwoObject(this);
}

@Override
public IRubyObject each(ThreadContext context, Block block) {
if (!packed()) return super.each(context, block);

if (!block.isGiven()) return enumeratorizeWithSize(context, this, "each", enumLengthFn());

block.yield(context, value);

return this;
}

@Override
protected IRubyObject fillCommon(ThreadContext context, int beg, long len, Block block) {
if (!packed()) return super.fillCommon(context, beg, len, block);

modifyCheck();

// See [ruby-core:17483]
if (len < 0) return this;

if (len > Integer.MAX_VALUE - beg) throw context.runtime.newArgumentError("argument too big");

if (len > 1) {
unpack();
return super.fillCommon(context, beg, len, block);
}

value = block.yield(context, RubyFixnum.zero(context.runtime));

return this;
}

@Override
protected IRubyObject fillCommon(ThreadContext context, int beg, long len, IRubyObject item) {
if (!packed()) return super.fillCommon(context, beg, len, item);

modifyCheck();

// See [ruby-core:17483]
if (len < 0) return this;

if (len > Integer.MAX_VALUE - beg) throw context.runtime.newArgumentError("argument too big");

if (len > 1) {
unpack();
return super.fillCommon(context, beg, len, item);
}

value = item;

return this;
}

@Override
public boolean includes(ThreadContext context, IRubyObject item) {
if (!packed()) return super.includes(context, item);

if (equalInternal(context, value, item)) return true;

return false;
}

@Override
public int indexOf(Object element) {
if (!packed()) return super.indexOf(element);

if (element != null) {
IRubyObject convertedElement = JavaUtil.convertJavaToUsableRubyObject(getRuntime(), element);

if (convertedElement.equals(value)) return 0;
}
return -1;
}

@Override
protected IRubyObject inspectAry(ThreadContext context) {
if (!packed()) return super.inspectAry(context);

final Ruby runtime = context.runtime;
RubyString str = RubyString.newStringLight(runtime, DEFAULT_INSPECT_STR_SIZE, USASCIIEncoding.INSTANCE);
EncodingUtils.strBufCat(runtime, str, OPEN_BRACKET);
boolean tainted = isTaint();

RubyString s = inspect(context, value);
if (s.isTaint()) tainted = true;
else str.setEncoding(s.getEncoding());
str.cat19(s);

EncodingUtils.strBufCat(runtime, str, CLOSE_BRACKET);

if (tainted) str.setTaint(true);

return str;
}

@Override
protected IRubyObject internalRotate(ThreadContext context, int cnt) {
if (!packed()) return super.internalRotate(context, cnt);

return aryDup();
}

@Override
protected IRubyObject internalRotateBang(ThreadContext context, int cnt) {
if (!packed()) return super.internalRotateBang(context, cnt);

modifyCheck();

return context.runtime.getNil();
}

@Override
public IRubyObject op_plus(IRubyObject obj) {
if (!packed()) return super.op_plus(obj);
RubyArray y = obj.convertToArray();
if (y.size() == 0) return new RubyArrayTwoObject(this);
return super.op_plus(y);
}

@Override
public IRubyObject reverse_bang() {
if (!packed()) return super.reverse_bang();

return this;
}

@Override
protected RubyArray safeReverse() {
if (!packed()) return super.safeReverse();

return new RubyArrayTwoObject(this);
}

@Override
protected IRubyObject sortInternal(ThreadContext context, Block block) {
if (!packed()) return super.sortInternal(context, block);

return this;
}

@Override
protected IRubyObject sortInternal(final ThreadContext context, boolean honorOverride) {
if (!packed()) return super.sortInternal(context, honorOverride);

return this;
}

@Override
public IRubyObject store(long index, IRubyObject value) {
if (!packed()) return super.store(index, value);

if (index == 1) {
eltSetOk(index, value);
return value;
}

unpack();
return super.store(index, value);
}

@Override
public IRubyObject subseq(RubyClass metaClass, long beg, long len, boolean light) {
if (!packed()) return super.subseq(metaClass, beg, len, light);
if (beg != 0 || len != 1) {
unpack();
return super.subseq(metaClass, beg, len, light);
}
return new RubyArrayTwoObject(metaClass, this);
}

@Override
public IRubyObject[] toJavaArray() {
if (!packed()) return super.toJavaArray();

return arrayOf(value);
}

@Override
public IRubyObject uniq(ThreadContext context) {
if (!packed()) return super.uniq(context);

return new RubyArrayTwoObject(this);
}

@Override
@Deprecated
public void ensureCapacity(int minCapacity) {
if (minCapacity == 1) return;
unpack();
super.ensureCapacity(minCapacity);
}
}

0 comments on commit a83428f

Please sign in to comment.