context.postScopedBody();
}
}
public IRubyObject exec(ThreadContext context, IRubyObject self, Instruction[] bytecodes) {
Ruby runtime = context.getRuntime();
// Where this frames stack begins.
int stackStart = stackTop;
int ip = 0;
IRubyObject other;
yarvloop: while (ip < bytecodes.length) {
//System.err.println("Executing: " + YARVInstructions.name(bytecodes[ip].bytecode));
switch (bytecodes[ip].bytecode) {
case YARVInstructions.NOP:
break;
case YARVInstructions.GETGLOBAL:
push(runtime.getGlobalVariables().get(bytecodes[ip].s_op0));
break;
case YARVInstructions.SETGLOBAL:
runtime.getGlobalVariables().set(bytecodes[ip].s_op0, pop());
break;
case YARVInstructions.GETLOCAL:
push(context.getCurrentScope().getValue((int) bytecodes[ip].l_op0, 0));
break;
case YARVInstructions.SETLOCAL:
context.getCurrentScope().setValue((int) bytecodes[ip].l_op0, pop(), 0);
break;
case YARVInstructions.GETINSTANCEVARIABLE:
push(self.getInstanceVariables().fastGetInstanceVariable(bytecodes[ip].s_op0));
break;
case YARVInstructions.SETINSTANCEVARIABLE:
self.getInstanceVariables().fastSetInstanceVariable(bytecodes[ip].s_op0, pop());
break;
case YARVInstructions.GETCLASSVARIABLE: {
RubyModule rubyClass = context.getRubyClass();
String name = bytecodes[ip].s_op0;
if (rubyClass == null) {
push(self.getMetaClass().fastGetClassVar(name));
} else if (!rubyClass.isSingleton()) {
push(rubyClass.fastGetClassVar(name));
} else {
RubyModule module = (RubyModule)(((MetaClass)rubyClass).getAttached());
if (module != null) {
push(module.fastGetClassVar(name));
} else {
push(runtime.getNil());
}
}
break;
}
case YARVInstructions.SETCLASSVARIABLE: {
RubyModule rubyClass = context.getCurrentScope().getStaticScope().getModule();
if (rubyClass == null) {
rubyClass = self.getMetaClass();
} else if (rubyClass.isSingleton()) {
rubyClass = (RubyModule)(((MetaClass)rubyClass).getAttached());
}
rubyClass.fastSetClassVar(bytecodes[ip].s_op0, pop());
break;
}
case YARVInstructions.GETCONSTANT:
push(context.getConstant(bytecodes[ip].s_op0));
break;
case YARVInstructions.SETCONSTANT:
context.setConstantInCurrent(bytecodes[ip].s_op0, pop());
runtime.incGlobalState();
break;
case YARVInstructions.PUTNIL:
push(context.getRuntime().getNil());
break;
case YARVInstructions.PUTSELF:
push(self);
break;
case YARVInstructions.PUTOBJECT:
//System.out.println("PUTOBJECT: " + bytecodes[ip].o_op0);
push(bytecodes[ip].o_op0);
break;
case YARVInstructions.PUTSTRING:
push(context.getRuntime().newString(bytecodes[ip].s_op0));
break;
case YARVInstructions.CONCATSTRINGS: {
StringBuilder concatter = new StringBuilder();
for (int i = 0; i < bytecodes[ip].l_op0; i++) {
concatter.append(pop().toString());
}
push(runtime.newString(concatter.toString()));
break;
}
case YARVInstructions.TOSTRING:
IRubyObject top = peek();
if (!(top instanceof RubyString)) {
set(top.callMethod(context, "to_s"));
}
break;
case YARVInstructions.NEWARRAY:
push(runtime.newArrayNoCopy(popArray(new IRubyObject[(int) bytecodes[ip].l_op0])));
break;
case YARVInstructions.DUPARRAY:
push(bytecodes[ip].o_op0.dup());
break;
case YARVInstructions.NEWHASH:
int hsize = (int)bytecodes[ip].l_op0;
RubyHash h = RubyHash.newHash(runtime);
IRubyObject v,k;
for(int i = hsize; i>0; i -= 2) {
v = pop();
k = pop();
h.op_aset(context, k, v);
}
push(h);
break;
case YARVInstructions.PUTNOT:
push(peek().isTrue() ? runtime.getFalse() : runtime.getTrue());
break;
case YARVInstructions.POP:
pop();
break;
case YARVInstructions.DUP:
push(peek());
break;
case YARVInstructions.DUPN:
dupn((int) bytecodes[ip].l_op0);
break;
case YARVInstructions.SWAP:
swap();
break;
case YARVInstructions.TOPN:
topn((int) bytecodes[ip].l_op0);
break;
case YARVInstructions.SETN:
setn((int) bytecodes[ip].l_op0, peek());
break;
case YARVInstructions.EMPTSTACK:
stackTop = stackStart;
break;
case YARVInstructions.DEFINEMETHOD:
RubyModule containingClass = context.getRubyClass();
if (containingClass == null) {
throw runtime.newTypeError("No class to add method.");
}
String mname = bytecodes[ip].iseq_op.name;
if (containingClass == runtime.getObject() && mname == "initialize") {
runtime.getWarnings().warn(ID.REDEFINING_DANGEROUS, "redefining Object#initialize may cause infinite loop", "Object#initialize");
}
Visibility visibility = context.getCurrentVisibility();
if (mname == "initialize" || visibility == Visibility.MODULE_FUNCTION) {
visibility = Visibility.PRIVATE;
}
if (containingClass.isSingleton()) {
IRubyObject attachedObject = ((MetaClass) containingClass).getAttached();
if (attachedObject instanceof RubyFixnum || attachedObject instanceof RubySymbol) {
throw runtime.newTypeError("can't define singleton method \"" +
mname + "\" for " + attachedObject.getType());
}
}
StaticScope sco = new LocalStaticScope(null);
sco.setVariables(bytecodes[ip].iseq_op.locals);
YARVMethod newMethod = new YARVMethod(containingClass, bytecodes[ip].iseq_op, sco, visibility);
containingClass.addMethod(mname, newMethod);
if (context.getCurrentVisibility() == Visibility.MODULE_FUNCTION) {
RubyModule singleton = containingClass.getSingletonClass();
singleton.addMethod(mname, new WrapperMethod(singleton, newMethod, Visibility.PUBLIC));
containingClass.callMethod(context, "singleton_method_added", runtime.fastNewSymbol(mname));
}
// 'class << state.self' and 'class << obj' uses defn as opposed to defs
if (containingClass.isSingleton()) {
((MetaClass) containingClass).getAttached().callMethod(context,
"singleton_method_added", runtime.fastNewSymbol(mname));
} else {
containingClass.callMethod(context, "method_added", runtime.fastNewSymbol(mname));
}
push(runtime.getNil());
runtime.incGlobalState();
break;
case YARVInstructions.SEND: {
ip = send(runtime, context, self, bytecodes, stackStart, ip);
break;
}
case YARVInstructions.LEAVE:
break yarvloop;
case YARVInstructions.JUMP:
ip = (int) bytecodes[ip].l_op0;
continue yarvloop;
case YARVInstructions.BRANCHIF:
ip = pop().isTrue() ? (int) bytecodes[ip].l_op0 : ip + 1;
continue yarvloop;
case YARVInstructions.BRANCHUNLESS: {
ip = !pop().isTrue() ? (int) bytecodes[ip].l_op0 : ip + 1;
continue yarvloop;
}
case YARVInstructions.GETINLINECACHE:
if(bytecodes[ip].l_op1 == runtime.getGlobalState()) {
push(bytecodes[ip].o_op0);
ip = (int) bytecodes[ip].l_op0;
continue yarvloop;
}
break;
case YARVInstructions.ONCEINLINECACHE:
if(bytecodes[ip].l_op1 > 0) {
push(bytecodes[ip].o_op0);
ip = (int) bytecodes[ip].l_op0;
continue yarvloop;
}
break;
case YARVInstructions.SETINLINECACHE:
int we = (int)bytecodes[ip].l_op0;
bytecodes[we].o_op0 = peek();
bytecodes[we].l_op1 = runtime.getGlobalState();
break;
case YARVInstructions.OPT_PLUS:
op_plus(runtime, context, pop(), pop());
break;
case YARVInstructions.OPT_MINUS:
op_minus(runtime, context, pop(), pop());
break;
case YARVInstructions.OPT_MULT:
other = pop();
push(pop().callMethod(context,MethodIndex.OP_TIMES, "*", other));
break;
case YARVInstructions.OPT_DIV:
other = pop();
push(pop().callMethod(context, "/", other));
break;
case YARVInstructions.OPT_MOD:
other = pop();
push(pop().callMethod(context,"%",other));
break;
case YARVInstructions.OPT_EQ:
other = pop();
push(pop().callMethod(context,MethodIndex.EQUALEQUAL, "==", other));
break;
case YARVInstructions.OPT_LT:
op_lt(runtime, context, pop(), pop());
break;
case YARVInstructions.OPT_LE:
other = pop();
push(pop().callMethod(context,MethodIndex.OP_LE, "<=", other));
break;
case YARVInstructions.OPT_LTLT:
other = pop();
push(pop().callMethod(context,MethodIndex.OP_LSHIFT, "<<", other));
break;
case YARVInstructions.OPT_AREF:
other = pop();
push(pop().callMethod(context,MethodIndex.AREF, "[]",other));
break;
case YARVInstructions.OPT_ASET: {
//YARV will never emit this, for some reason.
IRubyObject value = pop();
other = pop();
push(RuntimeHelpers.invoke(context, pop(), "[]=", other,value));
break;
}
case YARVInstructions.OPT_LENGTH:
push(pop().callMethod(context, "length"));
break;
case YARVInstructions.OPT_SUCC:
push(pop().callMethod(context, "succ"));
break;
case YARVInstructions.OPT_REGEXPMATCH1:
push(bytecodes[ip].o_op0.callMethod(context, "=~", peek()));
break;
case YARVInstructions.OPT_REGEXPMATCH2:
other = pop();
push(pop().callMethod(context, "=~", other));
break;
case YARVInstructions.ANSWER:
push(runtime.newFixnum(42));
break;
case YARVInstructions.GETSPECIAL:
case YARVInstructions.SETSPECIAL:
case YARVInstructions.GETDYNAMIC:
case YARVInstructions.SETDYNAMIC: