Package org.jruby.ast.executable

Source Code of org.jruby.ast.executable.YARVMachine$InstructionSequence

package org.jruby.ast.executable;

import org.jruby.Ruby;
import org.jruby.RubyBignum;
import org.jruby.RubyFixnum;
import org.jruby.RubyHash;
import org.jruby.RubyModule;
import org.jruby.RubyString;
import org.jruby.MetaClass;
import org.jruby.RubySymbol;
import org.jruby.parser.StaticScope;
import org.jruby.parser.LocalStaticScope;
import org.jruby.runtime.CallSite;
import org.jruby.runtime.CallType;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.common.IRubyWarnings.ID;
import org.jruby.internal.runtime.methods.YARVMethod;
import org.jruby.internal.runtime.methods.WrapperMethod;
import org.jruby.javasupport.util.RuntimeHelpers;
import org.jruby.runtime.MethodIndex;
import org.jruby.runtime.scope.ManyVarsDynamicScope;

public class YARVMachine {
    private static final boolean TAILCALL_OPT = Boolean.getBoolean("jruby.tailcall.enabled");

    public static final YARVMachine INSTANCE = new YARVMachine();

    public static int instruction(String name) {
        return YARVInstructions.instruction(name);
    }

    public static class InstructionSequence {
        public String magic;
        public int major;
        public int minor;
        public int format_type;
        public Object misc;
        public String name;
        public String filename;
        public Object[] line;
        public String type;

        public String[] locals;

        public int args_argc;
        public int args_arg_opts;
        public String[] args_opt_labels;
        public int args_rest;
        public int args_block;

        public Object[] exception;

        public Instruction[] body;

        public InstructionSequence(Ruby runtime, String name, String file, String type) {
            magic = "YARVInstructionSimpledataFormat";
            major = 1;
            minor = 1;
            format_type = 1;
            misc = runtime.getNil();
            this.name = name;
            this.filename = file;
            this.line = new Object[0];
            this.type = type;
            this.locals = new String[0];
            this.args_argc = 0;
            this.args_arg_opts = 0;
            this.exception = new Object[0];
        }
    }

    public static class Instruction {
        public int bytecode;
        public int line_no;
        public String s_op0;
        public IRubyObject o_op0;
        public Object _tmp;
        public long l_op0;
        public long l_op1;
        public int i_op1;
        public InstructionSequence iseq_op;
        public Instruction[] ins_op;
        public int i_op3;

        public int index;
        public int methodIndex = -1;
        public CallSite callAdapter;

        public Instruction(int bytecode) {
            this.bytecode = bytecode;
        }

        public Instruction(int bytecode, String op) {
            this.bytecode = bytecode;
            this.s_op0 = op.intern();
        }

        public Instruction(int bytecode, String op, InstructionSequence op1) {
            this.bytecode = bytecode;
            this.s_op0 = op.intern();
            this.iseq_op = op1;
        }

        public Instruction(int bytecode, long op) {
            this.bytecode = bytecode;
            this.l_op0 = op;
        }

        public Instruction(int bytecode, IRubyObject op) {
            this.bytecode = bytecode;
            this.o_op0 = op;
        }

        public Instruction(int bytecode, String op, int op1, Instruction[] op2, int op3) {
            this.bytecode = bytecode;
            this.s_op0 = op;
            this.i_op1 = op1;
            this.ins_op = op2;
            this.i_op3 = op3;
        }

        @Override
        public String toString() {
            return "[:" + YARVInstructions.name(bytecode) + ", " +
                (s_op0 != null ? s_op0 : (o_op0 != null ? o_op0.toString() : ("" + l_op0))) + "]";
        }
    }
   
    IRubyObject[] stack = new IRubyObject[8192];
    int stackTop = 0;
   
    /*
    private void printStack(String message, int fromIndex) {
        System.out.println("(" + message + ") Stack:");
        for (int i = fromIndex; i < stackTop; i++) {
            System.out.println("" + i + ": " + (stack[i] == null ? "null" : stack[i].inspect().toString()));
        }
    }*/

    /**
     * Push a value onto the stack
     *
     * @param value to be pushed
     */
    private void push(IRubyObject value) {
        //System.out.println("push(" + value.inspect() + ")");
        stack[stackTop] = value;
        stackTop++;
    }
   
    /**
     * Swap top two values in the stack
     */
    private void swap() {
        stack[stackTop + 1] = stack[stackTop];
        stack[stackTop] = stack[stackTop - 1];
        stack[stackTop - 1] = stack[stackTop + 1];
    }

    /**
     * Duplicate top 'n' values in the stack
     *
     * @param length
     */
    private void dupn(int length) {
        System.arraycopy(stack, stackTop - length, stack, stackTop, length);
        stackTop += length;
    }
   
    /**
     * Peek at top value in the stack
     *
     * @return the top value
     */
    private IRubyObject peek() {
        return stack[stackTop];
    }
   
    /**
     * pop top value in the stack
     *
     * @return the top value
     */
    private IRubyObject pop() {
        //System.out.println("pop(" + stack[stackTop-1].inspect() + ")");
        return stack[--stackTop];
    }
   
    /**
     * Pop top arr.length values into supplied arr.
     *
     * @param arr to be populated from the stack
     * @return the array passed in
     */
    private IRubyObject[] popArray(IRubyObject arr[]) {
        stackTop -= arr.length;
        System.arraycopy(stack, stackTop, arr, 0, arr.length);
       
        /*
        System.out.print("popArray:");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(" " + arr[0].inspect());
        }
        System.out.println("");
        */
       
        return arr;
    }

    /**
     * set the nth stack value to value
     * @param depth nth index of stack
     * @param value to be set
     */
    private void setn(int depth, IRubyObject value) {
        stack[stackTop - depth] = value;
    }
   
    /**
     * push nth stack value
     *
     * @param depth which element to push
     */
    private void topn(int depth) {
        push(stack[stackTop - depth]);
    }

    /**
     * Set/Replace top stack value with value
     *
     * @param value to replace current stack value
     */
    public void set(IRubyObject value) {
        stack[stackTop] = value;
    }

    public void unimplemented(int bytecode) {
        System.err.println("Not implemented, YARVMachine." + YARVInstructions.name(bytecode));
    }

    /**
     * Top-level exec into YARV machine.
     *
     * @param context thread that is executing this machine (Note: We need to make n machines with
     *   each belonging to an individual context)
     * @param scope of exec (evals will sometimes pass in something interesting)
     * @param bytecodes to be executed
     * @return last value pop'd of machine stack
     */
    public IRubyObject exec(ThreadContext context, StaticScope scope, Instruction[] bytecodes) {
        try {
            IRubyObject self = context.getRuntime().getObject();
           
            context.preScopedBody(new ManyVarsDynamicScope(scope));
       
            if (scope.getModule() == null) {
                scope.setModule(context.getRuntime().getObject());
            }
           
            return exec(context, self, bytecodes);
        } finally {
            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:
            case YARVInstructions.PUTUNDEF:
                // ko1 said this is going away
            case YARVInstructions.TOREGEXP:
            case YARVInstructions.NEWRANGE:
            case YARVInstructions.REPUT:
            case YARVInstructions.OPT_CASE_DISPATCH:
            case YARVInstructions.OPT_CHECKENV:
            case YARVInstructions.EXPANDARRAY:
                // masgn array to values
            case YARVInstructions.CONCATARRAY:
            case YARVInstructions.SPLATARRAY:
            case YARVInstructions.CHECKINCLUDEARRAY:
            case YARVInstructions.ALIAS:
            case YARVInstructions.UNDEF:
            case YARVInstructions.DEFINED:
            case YARVInstructions.POSTEXE:
            case YARVInstructions.TRACE:
            case YARVInstructions.DEFINECLASS:
            case YARVInstructions.INVOKESUPER:
            case YARVInstructions.INVOKEBLOCK:
            case YARVInstructions.FINISH:
            case YARVInstructions.THROW:
            case YARVInstructions.OPT_CALL_NATIVE_COMPILED:
            case YARVInstructions.BITBLT:
            case YARVInstructions.GETLOCAL_OP_2: case YARVInstructions.GETLOCAL_OP_3:
            case YARVInstructions.GETLOCAL_OP_4: case YARVInstructions.SETLOCAL_OP_2:
            case YARVInstructions.SETLOCAL_OP_3: case YARVInstructions.SETLOCAL_OP_4:
            case YARVInstructions.GETDYNAMIC_OP__WC__0:
            case YARVInstructions.GETDYNAMIC_OP_1_0: case YARVInstructions.GETDYNAMIC_OP_2_0:
            case YARVInstructions.GETDYNAMIC_OP_3_0: case YARVInstructions.GETDYNAMIC_OP_4_0:
            case YARVInstructions.SETDYNAMIC_OP__WC__0:
            case YARVInstructions.SETDYNAMIC_OP_1_0: case YARVInstructions.SETDYNAMIC_OP_2_0:
            case YARVInstructions.SETDYNAMIC_OP_3_0: case YARVInstructions.SETDYNAMIC_OP_4_0:
            case YARVInstructions.PUTOBJECT_OP_INT2FIX_0_0_C_:
            case YARVInstructions.PUTOBJECT_OP_INT2FIX_0_1_C_:
            case YARVInstructions.PUTOBJECT_OP_QTRUE: case YARVInstructions.PUTOBJECT_OP_QFALSE:
            case YARVInstructions.SEND_OP__WC___WC__QFALSE_0__WC_:
            case YARVInstructions.SEND_OP__WC__0_QFALSE_0__WC_:
            case YARVInstructions.SEND_OP__WC__1_QFALSE_0__WC_:
            case YARVInstructions.SEND_OP__WC__2_QFALSE_0__WC_:
            case YARVInstructions.SEND_OP__WC__3_QFALSE_0__WC_:
            case YARVInstructions.SEND_OP__WC___WC__QFALSE_0X04__WC_:
            case YARVInstructions.SEND_OP__WC__0_QFALSE_0X04__WC_:
            case YARVInstructions.SEND_OP__WC__1_QFALSE_0X04__WC_:
            case YARVInstructions.SEND_OP__WC__2_QFALSE_0X04__WC_:
            case YARVInstructions.SEND_OP__WC__3_QFALSE_0X04__WC_:
            case YARVInstructions.SEND_OP__WC__0_QFALSE_0X0C__WC_:
            case YARVInstructions.UNIFIED_PUTOBJECT_PUTOBJECT:
            case YARVInstructions.UNIFIED_PUTOBJECT_PUTSTRING:
            case YARVInstructions.UNIFIED_PUTOBJECT_SETLOCAL:
            case YARVInstructions.UNIFIED_PUTOBJECT_SETDYNAMIC:
            case YARVInstructions.UNIFIED_PUTSTRING_PUTSTRING:
            case YARVInstructions.UNIFIED_PUTSTRING_PUTOBJECT:
            case YARVInstructions.UNIFIED_PUTSTRING_SETLOCAL:
            case YARVInstructions.UNIFIED_PUTSTRING_SETDYNAMIC:
            case YARVInstructions.UNIFIED_DUP_SETLOCAL:
            case YARVInstructions.UNIFIED_GETLOCAL_GETLOCAL:
            case YARVInstructions.UNIFIED_GETLOCAL_PUTOBJECT:
                unimplemented(bytecodes[ip].bytecode);
                break;
            }
            ip++;
        }

        return pop();
    }

    private void op_plus(Ruby runtime, ThreadContext context, IRubyObject other, IRubyObject receiver) {
        if (other instanceof RubyFixnum && receiver instanceof RubyFixnum) {
            long receiverValue = ((RubyFixnum) receiver).getLongValue();
            long otherValue = ((RubyFixnum) other).getLongValue();
            long result = receiverValue + otherValue;
            if ((~(receiverValue ^ otherValue) & (receiverValue ^ result) & RubyFixnum.SIGN_BIT) != 0) {
                push(RubyBignum.newBignum(runtime, receiverValue).op_plus(context, other));
            }

            push(runtime.newFixnum(result));
        } else {
            push(receiver.callMethod(context, MethodIndex.OP_PLUS, "+", other));
        }
    }

    private void op_minus(Ruby runtime, ThreadContext context, IRubyObject other, IRubyObject receiver) {
        if (other instanceof RubyFixnum && receiver instanceof RubyFixnum) {
            long receiverValue = ((RubyFixnum) receiver).getLongValue();
            long otherValue = ((RubyFixnum) other).getLongValue();
            long result = receiverValue - otherValue;
            if ((~(receiverValue ^ otherValue) & (receiverValue ^ result) & RubyFixnum.SIGN_BIT) != 0) {
                push(RubyBignum.newBignum(runtime, receiverValue).op_minus(context, other));
            }

            push(runtime.newFixnum(result));
        } else {
            push(receiver.callMethod(context, MethodIndex.OP_MINUS, "-", other));
        }
    }

    private void op_lt(Ruby runtime, ThreadContext context, IRubyObject other, IRubyObject receiver) {
        if (other instanceof RubyFixnum && receiver instanceof RubyFixnum) {
            long receiverValue = ((RubyFixnum) receiver).getLongValue();
            long otherValue = ((RubyFixnum) other).getLongValue();
           
            push(runtime.newBoolean(receiverValue < otherValue));
        } else {
            push(receiver.callMethod(context, MethodIndex.OP_LT, "<", other));
        }
    }

    private int send(Ruby runtime, ThreadContext context, IRubyObject self, Instruction[] bytecodes, int stackStart, int ip) {
        Instruction instruction = bytecodes[ip];
        String name = instruction.s_op0;
        int size = instruction.i_op1;
        int flags = instruction.i_op3;
       
        // ENEBO: We need to define a YarvBlock
        //Instruction[] blockBytecodes = bytecodes[ip].ins_op;
        // TODO: block stuff

        IRubyObject[] args;
        if (size == 0) {
            args = IRubyObject.NULL_ARRAY;
        } else {
            args = new IRubyObject[size];
            popArray(args);
        }
       
        // FCalls and VCalls use a nil as a place holder, but this is just extra stack
        // traffic.  Also extra flag activity (tiny perf-wise).  I would think three
        // send instructions makes more sense...
        IRubyObject recv;
        CallType callType;
        if ((flags & YARVInstructions.VCALL_FLAG) == 0) {
            if ((flags & YARVInstructions.FCALL_FLAG) == 0) {
                recv = pop();
                callType = CallType.NORMAL;
            } else {
                pop();
                recv = self;
                callType = CallType.FUNCTIONAL;
            }
        } else {
            pop();
            recv = self;
            callType = CallType.VARIABLE;
        }
       
        if (instruction.callAdapter == null) {
            instruction.callAdapter = MethodIndex.getCallSite(name.intern());
        }
       
        if (TAILCALL_OPT && (bytecodes[ip+1].bytecode == YARVInstructions.LEAVE ||
            (flags & YARVInstructions.TAILCALL_FLAG) == YARVInstructions.TAILCALL_FLAG) &&
            recv == self && name.equals(context.getFrameName())) {
            stackTop = stackStart;
            ip = -1;
           
            for(int i=0;i<args.length;i++) {
                context.getCurrentScope().getValues()[i] = args[i];
            }
        } else {
            push(instruction.callAdapter.call(context, self, recv, args));
            //push(recv.callMethod(context, name, args, callType));
        }
       
        return ip;
    }
}
TOP

Related Classes of org.jruby.ast.executable.YARVMachine$InstructionSequence

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.